【问题标题】:React JS - To many renderings, how can I improve that code?React JS - 对于许多渲染,我该如何改进该代码?
【发布时间】:2021-07-09 12:33:46
【问题描述】:

我是 React JS 的新手,我正在尝试构建一个小项目来学习。 到目前为止,我做得很好,但我相信我的应用程序渲染过多,这使我无法获得我有兴趣添加的另一个功能 - 一个本地存储保存最后一次搜索的股票。

我的项目是一个简单的股票搜索应用程序,通过股票名称或股票代码获取股票价格。

我做错了什么? 我得到了我想要的价格,但是它需要太多的效果图。如果我只做一个,我得到的价格只是一个普通的 0,而不是实际价格。 当我按照下面发布的代码进行操作时,它显示了正确的价格,但我相信我错过了一些东西。

我对 React 比较陌生,所以我猜这是学习的一部分 :)

我的另一个问题,据我了解,react-router 是假设保存最后输入的值。我确实使用了react router,这个页面上的渲染是否再次更改为默认值?

PS,当我尝试将 currentStock 的默认状态保持为空时,我得到了一些奇怪的值,我认为这是 API 本身的问题。

这是我的代码:


const Stocks = () => {

  const [currentStock, setCurrentStock] = useState('AAPL');
  const [currentPrice, setCurrentPrice] = useState('Loading...');
  const [stockFromClick, setClick] = useState();

  useEffect( () => {

    if(currentPrice === 0){
      setCurrentPrice('Ready!')
    }
    const fetchData = async() =>{
    const getSymbol = await axios(`https://finnhub.io/api/v1/search?q=${currentStock}&token=${API_KEY}`);
    setCurrentStock(getSymbol.data.result[0].symbol);

    const getPrice = await axios (`https://finnhub.io/api/v1/quote?symbol=${currentStock}&token=${API_KEY}`)
    setCurrentPrice(getPrice.data.c)
    }

  fetchData();
  console.log(currentPrice);
  } , [stockFromClick, currentPrice]);


  const handleClick = () =>{
    setCurrentPrice('Loading... Please allow the system a few seconds to gather all the information');

    setClick(currentStock);

    console.log(currentStock);
  }

  return (
    <div>
      Stocks!<br></br>
      <input type="text" placeholder="Search a Company" value={currentStock} onChange={e => setCurrentStock(e.target.value)} /><br></br>
      <button type="button" onClick={handleClick}> Search</button><br></br>
      {currentPrice}

    </div>
  )
}

export default Stocks;

【问题讨论】:

  • 您的useEffect 每次currentPrice 更改时都会运行,但它也会更改currentPrice 的值

标签: javascript reactjs performance react-router react-hooks


【解决方案1】:

功能组件重新渲染时

在带有功能组件的 React 中,每次更新状态变量都会导致组件重新呈现(假设状态实际上与以前不同)。

因此,您的代码具有以下内容:

  1. onChange={e =&gt; setCurrentStock(e.target.value)} 触发的潜在重新渲染
  2. setCurrentPrice('Loading...'); 触发的潜在重新渲染
  3. setCurrentStock(getSymbol.data.result[0].symbol); 触发的潜在重新渲染
  4. setCurrentPrice(getPrice.data.c); 触发的潜在重新渲染
  5. setCurrentPrice('Ready!'); 触发的潜在重新渲染
  6. 您的effect 会在每次依赖项更改时重新运行。

同样,如果这些 set 并没有真正导致更改状态,则这些重新渲染可能不会发生。

我会怎么写

如果我自己编写这个组件,我可能会执行以下操作。请注意,我的许多更改可能只是风格偏好。但是,将股票和交易品种值组合成一个状态变量可以帮助您消除重新渲染:

import { useState, useEffect, useCallback } from 'react';
import axios from 'axios';

const Stocks = () => {
  const [isLoading, setIsLoading] = useState(false);
  const [stock, setStock] = useState({});
  const [query, setQuery] = useState('APPL');

  const fetchData = useCallback(async (q) => {

    // don't do anything if we don't have a query string
    if (!q) return;

    setIsLoading(true);
    const getSymbol = await axios(`https://finnhub.io/api/v1/search?q=${q}&token=${API_KEY}`);
    const symbol = getSymbol.data.result[0].symbol;

    const getPrice = await axios(`https://finnhub.io/api/v1/quote?symbol=${symbol}&token=${API_KEY}`);
    const price = getPrice.data.c;

    setStock({ symbol, price });
    setIsLoading(false);
  }, []);

  // load the default stock data on initial rendering
  useEffect(() => fetchData(query), []);

  return (
    <div>
      Stocks! <br/><br/>
      <label for="query">Search For A Stock:</label>
      <input
        name="query"
        type="text"
        placeholder="Ex. APPL"
        value={query}
        onChange={e => setQuery(e.target.value)}
      />
      <br></br >
      <button
        type="button"
        onClick={() => fetchData(query)}
      >Search</button>
      <br/><br/>

      {isLoading && <span>Loading... Please allow the system a few seconds to gather all the information</span>}
      {!isLoading &&
        <div>
          <div>Symbol: {stock.symbol}</div>
          <div>Price: {stock.price}</div>
        </div>
      }
    </div>
  );
}

export default Stocks;

反应路由器

我认为您关于 react-router 的问题可能需要更多细节。您的代码中没有任何迹象表明您是如何尝试利用 react-router 状态或将其传递到此组件中的。

Finnhub API

我认为关于这个 API 需要注意的重要一点是,/search 端点真正返回的是字符串查询的搜索结果。因此,如果您传递一个空字符串,它将作为搜索词运行一个查询并返回结果。同样,即使输入APPL 之类的内容也会产生意外结果,因为它不仅仅是搜索股票代码。

【讨论】:

  • 太棒了 :) 非常感谢。学到了一两件事。
【解决方案2】:

是的,就像 WebbH 每次设置 currentPrice 时都会重新渲染... 我想我会尝试使用切换来加载

const Stocks = () => {
const [currentStock, setCurrentStock] = useState("apple");
const [currentPrice, setCurrentPrice] = useState(null);
const [isLoading, setIsLoading] = useState(true);

const fetchData = async () => {
    if (!isLoading) setIsLoading(true);
    try {
        const getSymbol = await axios.get(
            `https://finnhub.io/api/v1/search?q=${currentStock}&token=${API_KEY}`
        );
        setCurrentStock(getSymbol.data.result[0].symbol);

        const getPrice = await axios.get(
            `https://finnhub.io/api/v1/quote? 
             symbol=${currentStock}&token=${API_KEY}`
        );
        setCurrentPrice(getPrice.data.c);

        setIsLoading(false);
    } catch (error) {
        console.log("fetchData: ", error);
    }
  };

   useEffect(() => {
    fetchData();
   }, []);

   const handleClick = () => {
    fetchData();
   };

   return (
    <div>
        ...
        <br></br>
        {isLoading && !currentPrice
            ? "Loading... Please allow the system a few seconds to gather all the 
               information"
            : { currentPrice }}
    </div>
   );
 };

【讨论】:

  • 我试过这样做,但由于某种原因,如果我不再次呈现 currentPrice,我会得到 0 作为当前价格。知道我能做什么吗?
  • 我在你的 api 中编辑我的代码 getSymbol 必须是 /search?q=apple no ?
猜你喜欢
  • 1970-01-01
  • 2021-02-14
  • 2023-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-05
相关资源
最近更新 更多