简体   繁体   English

React JS - 对于许多渲染,我该如何改进该代码?

[英]React JS - To many renderings, how can I improve that code?

I'm new to React JS, and I'm trying to build a small project to learn.我是 React JS 的新手,我正在尝试构建一个小项目来学习。 So far I'm doing well, but I believe that my app renders too much and it prevents me from getting another fiture I'm interested on adding - a localStorage save of the last stock that was search.到目前为止,我做得很好,但我相信我的应用程序渲染太多,它阻止了我获得另一个我有兴趣添加的设备 - 最后一个搜索股票的 localStorage 保存。

My project is a simple stock searching app, getting the prices of a stock by its name or its ticker.我的项目是一个简单的股票搜索应用程序,通过股票名称或股票代码获取股票价格。

What am I doing wrong?我究竟做错了什么? I get the price as I wish, but it takes too many renderings.我得到了我想要的价格,但是它需要太多的效果图。 If I do just one, the price I get is just a plain 0 instead of the real price.如果我只做一个,我得到的价格只是一个简单的 0,而不是实际价格。 When I go like the code posted below, it shows the correct price, but I believe that I miss something.当我像下面发布的代码一样 go 时,它显示了正确的价格,但我相信我错过了一些东西。

I'm relatively new to React so it's part of the learning I guess:)我对 React 比较陌生,所以我猜这是学习的一部分:)

Another question I had, as I understood react-router is suppose to save the last values entered.据我了解,我的另一个问题是 react-router 应该保存最后输入的值。 I do use react router, is the rendering on this page that is changing to the default value all over again?我确实使用了反应路由器,此页面上的渲染是否再次更改为默认值?

PS, when I tried to keep the default state of the currentStock empty, I got some weird values which I assume is a problem with the API itself. PS,当我尝试将 currentStock 的默认 state 保留为空时,我得到了一些奇怪的值,我认为这是 API 本身的问题。

Here is my code:这是我的代码:


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;

yeah like WebbH re-render every times currentPrice is set... I think I would have tried to use a toggle for loading是的,就像 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>
   );
 };

When Functional Components Rerender功能组件何时重新渲染

In React with functional components each time you update a state variable you will cause the component to rerender (assuming that the state is actually different than before).在 React with functional components 中,每次更新 state 变量时,都会导致组件重新呈现(假设 state 实际上与以前不同)。

So with your code you have the following:因此,使用您的代码,您将拥有以下内容:

  1. A potential rerender triggered by onChange={e => setCurrentStock(e.target.value)}onChange={e => setCurrentStock(e.target.value)}触发的潜在重新渲染
  2. A potential rerender triggered by setCurrentPrice('Loading...');setCurrentPrice('Loading...');
  3. A potential rerender triggered by setCurrentStock(getSymbol.data.result[0].symbol);setCurrentStock(getSymbol.data.result[0].symbol);
  4. A potential rerender triggered by setCurrentPrice(getPrice.data.c);setCurrentPrice(getPrice.data.c);
  5. A potential rerender triggered by setCurrentPrice('Ready;');setCurrentPrice('Ready;');
  6. Your effect is rerunning every time the dependencies change.每次依赖项更改时,您的effect都会重新运行。

Again, these rerenders may not occur if those set 's don't actually result in a changed state.同样,如果这些set实际上没有导致 state 发生更改,则可能不会发生这些重新渲染。

How I Would Write It我会怎么写

If I were to write this component myself I'd probably do something like the following.如果我要自己编写这个组件,我可能会执行以下操作。 Note, that many of my changes are likely just stylistic preferences.请注意,我的许多更改可能只是风格偏好。 However, the combining of the stock and symbol values into a single state variable could help you eliminate a rerender:但是,将股票和代码值组合到单个 state 变量中可以帮助您消除重新渲染:

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反应路由器

I think your question about the react-router probably needs some more detail.我认为您关于 react-router 的问题可能需要更多细节。 There's no indications in your code of how you're trying to leverage react-router state or pass it into this component.您的代码中没有任何迹象表明您是如何尝试利用 react-router state 或将其传递到此组件中的。

Finnhub API Finnhub API

I think the important thing to note about this API is that the /search endpoint is truly returning search results on a string query.我认为关于这个 API 需要注意的重要一点是/search端点真正返回了字符串查询的搜索结果。 Therefore if you pass an empty string it's running a query on that as the search term and returning results.因此,如果您传递一个空字符串,它将作为搜索词运行一个查询并返回结果。 Similarly, even entering something like APPL is subject to have an unexpected result as it's not just searching on the stock symbol.同样,即使输入APPL之类的内容也会产生意想不到的结果,因为它不仅仅是搜索股票代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM