在我的测试应用程序中,每次调用某个函数时,都会调用我的API(axios.get),然后使用从数据库接收的数据更新两个状态变量。这两个状态变量都改变了屏幕上显示的内容。
问题是,我添加了一个useEffect钩子来“调试”重新渲染的数量,并且我注意到该组件被重新渲染两次,我想是因为它一次用于一个状态变量,而一次用于另一状态变量。我以为使用useReducer会改变这一点,但不会改变。
这是正常的React行为还是我应该做一些不同的事情才能使组件仅重新渲染一次?
编辑:我正在编辑以添加代码: (这是一种琐事测试应用程序,我是React的新手,所以我正在练习)
import React, { useEffect, useReducer } from 'react'
import axios from 'axios'
import './App.css';
import reducer from './Reducer.js'
const initialState = {
question: '',
id: 1,
choices: []
}
const Questions = () => {
const [state, dispatch] = useReducer(reducer, initialState)
useEffect(() => {
console.log('executed');
})
const getQuestion = async (e) => {
try {
e.preventDefault()
const res = await axios.get(`/questions/${state.id}`)
dispatch({
type: 'set_question',
payload:
res.data.question
})
dispatch({
type: 'set_choices',
payload:
[res.data.correct_answer,
res.data.incorrect_answer1,
res.data.incorrect_answer2]
})
} catch (err) {
console.log(err);
}
}
return (
<div>
<form onSubmit={getQuestion}>
<button>Get next question</button>
</form>
<h1> {state.question ? state.question : null}</h1>
<button> {state.choices ? `${state.choices[0]}` : null}</button>
<button> {state.choices ? ` ${state.choices[1]}` : null}</button>
<button> {state.choices ? ` ${state.choices[2]}` : null}</button>
</div>
)
}
export default Questions
减速器:
const reducer = (state, action) => {
switch (action.type) {
case 'set_question':
return {
...state,
question: action.payload
}
case 'set_choices':
return {
...state,
choices: action.payload
}
default:
return state
}
}
export default reducer
答案 0 :(得分:1)
仅对事件处理程序和生命周期方法中的状态更新进行批处理。如果状态更新发生在异步函数中,例如作为对成功调用fetch或setTimeout的响应,它们将不会被批处理。宣布将在React的未来版本中进行更改。
另请参阅Dan Abramov对此的回答: https://stackoverflow.com/a/48610973/5005177
但是,在React 16和早期版本中,默认情况下,在React事件处理程序之外都没有批处理。因此,如果在您的示例中使用的是AJAX响应处理程序而不是handleClick,则每个
setState()
都会在发生时立即得到处理。在这种情况下,是的,您会看到一个中间状态。promise.then(() => { // We're not in an event handler, so these are flushed separately. this.setState({a: true}); // Re-renders with {a: true, b: false } this.setState({b: true}); // Re-renders with {a: true, b: true } this.props.setParentState(); // Re-renders the parent });
如果只希望一次重新渲染组件,则必须将所有数据保留在一个状态对象中,这样就只需调用setState
一次(或者如果需要,则调用dispatch
)对新数据使用useReducer
。
另一种解决方法是将状态更新块包装在ReactDOM.unstable_batchedUpdates(() => {...})
中,这在以后的版本中很可能不再需要了。另请从上方查看Dan Abramov的答案以了解详细信息。