React Function 没有使用更新的数组?
React Function is not using updated array?
我正在学习 React 并正在编写一个 React 应用程序,它可以让您按下具有值(1、0、-1)的按钮,然后进行一些计算(平均值、%pos 等)。
我编写了一个函数来计算我的 App.js 组件中的平均值
const [good, setGood] = useState(0)
const [neutral, setNeutral] = useState(0)
const [bad, setBad] = useState(0)
const [allNum, setAll] = useState([])
const [average, setAverage] = useState(0)
const calcAverage = () => {
console.log('values in calcAvg for allNum: ', allNum)
let total = 0;
for(let i = 0; i < allNum.length; i++) {
total += allNum[i];
}
return total/allNum.length;
}
const handleGoodClick = () => {
setGood(good + 1)
setAll(allNum.concat(1))
setAverage(calcAverage());
}
const handleNeutralClick = () => {
...
}
const handleBadClick = () => {
...
}
return(
<div>
<h1>Give Feedback</h1>
<Button handleClick={handleGoodClick} text="good"/>
...
<Statistics good={good} neutral={neutral} bad={bad} allNum={allNum} average={average}/>
</div>
)
}
统计组件如下:
const Statistics = (props) => {
console.log('props value is: ', props)
return(
<div>
<h1>Statistics</h1>
...
<Statistic text="Average" value={props.average}/>
</div>
)
}
当我按下一个按钮并且应用程序尝试计算平均值时,平均值数组总是落后 1 个值。
即,打开应用程序,按好,Average 显示为 NaN,console.log 显示包含 1 的 allNum 数组,但是当计算 Average 时,allNum 数组中尚未包含 1。为什么不按顺序进行?我怎样才能让它按顺序执行?最佳实践方法是什么?
谢谢
计算收到以前的值的原因是因为 useState
提供的 setState
函数没有同步设置状态。
为了克服这个问题,您可以使用类似 useEffect
的方法在 allNum
发生变化时更新平均值(参考比较)。
const MiscComponent = () => {
const [good, setGood] = useState(0)
const [neutral, setNeutral] = useState(0)
const [bad, setBad] = useState(0)
const [allNum, setAll] = useState([])
const [average, setAverage] = useState(0)
// The useEffect will trigger based on what is entered into the
// dependency array: [setAverage, allNum]
// Each render cycle the values will be compared (reference comparison)
// to the previous values in the dependency array and if there is a
// change the effect will be run.
// NOTE: There is always considered to be a "change" on component mount.
// setAverage is guarenteed to never change reference once created by useState.
// Someone else probably has the link to the React docs for this statement.
// So everytime allNum is updated this effect should run.
useEffect(() => {
const average = allNum.reduce((a, b) => a + b, 0) / allNum.length;
setAverage(average)
}, [setAverage, allNum])
// Since the average update will be handled by the useEffect it can
// now be removed from the click handler.
const handleGoodClick = () => {
setGood(good + 1)
setAll(allNum.concat(1))
}
const handleNeutralClick = () => {
/* Code here */
}
const handleBadClick = () => {
/* Code here */
}
return(
<div>
<h1>Give Feedback</h1>
<Button handleClick={handleGoodClick} text="good"/>
{/* Components Here */}
<Statistics good={good} neutral={neutral} bad={bad} allNum={allNum} average={average}/>
</div>
)
}
另一种选择,如果平均值只受其他状态变量影响(影响?无论如何),您可以使用 useMemo
代替。
const MiscComponent = () => {
const [good, setGood] = useState(0)
const [neutral, setNeutral] = useState(0)
const [bad, setBad] = useState(0)
const [allNum, setAll] = useState([])
// useMemo will return a memoized value for average that will only be recalculated
// based on its associated dependency array.
const average = useMemo(() => {
const average = allNum.reduce((a, b) => a + b, 0) / allNum.length;
return average;
}, [allNum]);
// Since the average update will be handled by the useMemo it can
// now be removed from the click handler.
const handleGoodClick = () => {
setGood(good + 1)
setAll(allNum.concat(1))
}
const handleNeutralClick = () => {
/* Code here */
}
const handleBadClick = () => {
/* Code here */
}
return(
<div>
<h1>Give Feedback</h1>
<Button handleClick={handleGoodClick} text="good"/>
{/* Components Here */}
<Statistics good={good} neutral={neutral} bad={bad} allNum={allNum} average={average}/>
</div>
)
}
我正在学习 React 并正在编写一个 React 应用程序,它可以让您按下具有值(1、0、-1)的按钮,然后进行一些计算(平均值、%pos 等)。
我编写了一个函数来计算我的 App.js 组件中的平均值
const [good, setGood] = useState(0)
const [neutral, setNeutral] = useState(0)
const [bad, setBad] = useState(0)
const [allNum, setAll] = useState([])
const [average, setAverage] = useState(0)
const calcAverage = () => {
console.log('values in calcAvg for allNum: ', allNum)
let total = 0;
for(let i = 0; i < allNum.length; i++) {
total += allNum[i];
}
return total/allNum.length;
}
const handleGoodClick = () => {
setGood(good + 1)
setAll(allNum.concat(1))
setAverage(calcAverage());
}
const handleNeutralClick = () => {
...
}
const handleBadClick = () => {
...
}
return(
<div>
<h1>Give Feedback</h1>
<Button handleClick={handleGoodClick} text="good"/>
...
<Statistics good={good} neutral={neutral} bad={bad} allNum={allNum} average={average}/>
</div>
)
}
统计组件如下:
const Statistics = (props) => {
console.log('props value is: ', props)
return(
<div>
<h1>Statistics</h1>
...
<Statistic text="Average" value={props.average}/>
</div>
)
}
当我按下一个按钮并且应用程序尝试计算平均值时,平均值数组总是落后 1 个值。
即,打开应用程序,按好,Average 显示为 NaN,console.log 显示包含 1 的 allNum 数组,但是当计算 Average 时,allNum 数组中尚未包含 1。为什么不按顺序进行?我怎样才能让它按顺序执行?最佳实践方法是什么?
谢谢
计算收到以前的值的原因是因为 useState
提供的 setState
函数没有同步设置状态。
为了克服这个问题,您可以使用类似 useEffect
的方法在 allNum
发生变化时更新平均值(参考比较)。
const MiscComponent = () => {
const [good, setGood] = useState(0)
const [neutral, setNeutral] = useState(0)
const [bad, setBad] = useState(0)
const [allNum, setAll] = useState([])
const [average, setAverage] = useState(0)
// The useEffect will trigger based on what is entered into the
// dependency array: [setAverage, allNum]
// Each render cycle the values will be compared (reference comparison)
// to the previous values in the dependency array and if there is a
// change the effect will be run.
// NOTE: There is always considered to be a "change" on component mount.
// setAverage is guarenteed to never change reference once created by useState.
// Someone else probably has the link to the React docs for this statement.
// So everytime allNum is updated this effect should run.
useEffect(() => {
const average = allNum.reduce((a, b) => a + b, 0) / allNum.length;
setAverage(average)
}, [setAverage, allNum])
// Since the average update will be handled by the useEffect it can
// now be removed from the click handler.
const handleGoodClick = () => {
setGood(good + 1)
setAll(allNum.concat(1))
}
const handleNeutralClick = () => {
/* Code here */
}
const handleBadClick = () => {
/* Code here */
}
return(
<div>
<h1>Give Feedback</h1>
<Button handleClick={handleGoodClick} text="good"/>
{/* Components Here */}
<Statistics good={good} neutral={neutral} bad={bad} allNum={allNum} average={average}/>
</div>
)
}
另一种选择,如果平均值只受其他状态变量影响(影响?无论如何),您可以使用 useMemo
代替。
const MiscComponent = () => {
const [good, setGood] = useState(0)
const [neutral, setNeutral] = useState(0)
const [bad, setBad] = useState(0)
const [allNum, setAll] = useState([])
// useMemo will return a memoized value for average that will only be recalculated
// based on its associated dependency array.
const average = useMemo(() => {
const average = allNum.reduce((a, b) => a + b, 0) / allNum.length;
return average;
}, [allNum]);
// Since the average update will be handled by the useMemo it can
// now be removed from the click handler.
const handleGoodClick = () => {
setGood(good + 1)
setAll(allNum.concat(1))
}
const handleNeutralClick = () => {
/* Code here */
}
const handleBadClick = () => {
/* Code here */
}
return(
<div>
<h1>Give Feedback</h1>
<Button handleClick={handleGoodClick} text="good"/>
{/* Components Here */}
<Statistics good={good} neutral={neutral} bad={bad} allNum={allNum} average={average}/>
</div>
)
}