React.js 无限重新渲染

时间:2021-03-04 18:58:10

标签: javascript reactjs

我的代码有问题。我的函数“getNames”可能会重新渲染多次,但我希望它渲染一次?你有什么线索吗?

import grounds  from './../../UballersGroundsData.json';

export default function Groundlist() {

    function getNames(jsonObj){
        for(let item in jsonObj){
            console.log("item = " + item);
            for(let property in jsonObj[item] ){
                console.log(jsonObj[item]);
                // if (property === "groundName"){
                //     console.log(jsonObj[item][property]);
                // }
                
            }
        }       
    }

return(
        <div>
            <h1>Hello world!</h1> 
            <ul>
                {getNames(grounds)}
            </ul>

        </div>
    )
}

谢谢!

4 个答案:

答案 0 :(得分:1)

您应该将函数放在 useEffect hook 中,然后使用 useState 将其设置为 state hook。然后,为您的列表绘制列表项(假设您正在从您的函数返回一个数组)。如果您希望它只在第一次渲染时运行 getNames,您可以使用空的依赖数组设置 useEffect 钩子。代码应如下所示:

import React, { useEffect, useState } from 'react'
import grounds  from './../../UballersGroundsData.json';

export default function Groundlist() {
    const [names, setNames] = useState([]) // Initial state with empty array

    useEffect(() => {
        function getNames(jsonObj){
            // your function logic here...       
        }
        const result = getNames(grounds) // Call your function
        setNames(result) // set it to names state hook
    }, []) // Empty array here means it will only use the useEffect on the first render.

return(
        <div>
            <h1>Hello world!</h1> 
            <ul>
                {Array.from(names).map(name =>  <li>{name}</li>)}
            </ul>

        </div>
    )
}

答案 1 :(得分:1)

您可以使用 useMemo 反应钩子来记住返回的值,即跳过由于其他状态、道具或上下文变量的变化而导致的不必要/繁重的计算。

示例:

import { useMemo } from "react"

export default function Groundlist(props) {

  const grounds = props.data // if grounds is passed as props from Parent component

  const groundsMemo = useMemo(() => {
    // do all the heavy calculations here 
    // (e.g. do the work of getNames function)
    
    // and return some JSX or Array (data)

    // returned value will be memoized;
    // means it will be re-calculated only if "grounds" changes
    
    // Hence, no unnecessary calls to getNames (heavy calculations)

  }, [grounds])

  return (
    <div>
      {/* Use this if groundsMemo is JSX */}
      <ul>{groundsMemo}</ul>

      {/* Use this if groundsMemo is an Array (data) */}
      <ul>{groundsMemo.map(item => <li key={some_key}>
        {item.property}
      </li>)}</ul>
    </div>
  )
}

答案 2 :(得分:0)

尝试使用 useMemouseCallBack 来优化您的 React 应用。 React 官方文档清楚地描述了如何使用它:useMemo useCallBack

答案 3 :(得分:0)

您永远不应该在渲染的返回范围内调用函数。 组件在没有适当处理的情况下重新渲染是正常的。

考虑其他 2 个答案

您可以使用 useEffect、useCallback 和 React.memo 的全部功能来防止任何内容重新渲染。

import React from 'react';
import grounds  from './../../UballersGroundsData.json';

function Groundlist() {
  // initiate state
  const [names, setNames] = React.useState([]);

  // This will prevent the Function from recalculate - useCallback
  const getNames = React.useCallback(function (jsonObj) {
    for(let item in jsonObj){
      console.log("item = " + item);
      for(let property in jsonObj[item] ){
        console.log(jsonObj[item]);
        // if (property === "groundName"){
        //     console.log(jsonObj[item][property]);
        // }
      }
    }
  }, []);
  

  // Will make function run only once and nevermore - useEffect
  React.useEffect(() => {
    setNames(getNames());
  }, [])

  return(
    <div>
        <h1>Hello world!</h1>
        <ul>
            {names.map(a => <li>{a}</li>)}
        </ul>

    </div>
  )
}

// Will prevent React from try to re-render without changing in props, so as your component has no props, will never re-render without yourself unmounting first
export default React.memo(Groundlist);

在另一种情况下,您可以使用函数的最后一个参数控制组件何时重新计算您的名称

useCallback(() => {}, []) //<---

例如

useCallback(() => {}, [updateState]);

当 updateState 更改时,将重新创建该函数。