React异步state更新失效及useHook使用错误问题求助
解决方法
问题根源
- 异步更新滞后:你在
onClick里调用fetchData后立刻执行setField(data),但fetchData是异步请求,setData更新data状态的操作是异步的,此时data还是请求前的旧值,所以setField存的是无效数据。 - Hook调用违规:
useEffect必须在组件顶层作用域调用,不能放在事件处理函数(比如onClick)内部,这违反了React Hook的调用规则。
方案1:移除多余的field状态(推荐)
如果你的Select选项直接使用请求返回的data,完全不需要额外维护field状态,直接用useData返回的data即可:
export const MainPage = props => { const [state, setState] = useState({ pharam: 'Yes', value: '', }); // 直接使用useData返回的data,无需额外的field状态 const {data, fetchData} = useData() const onClick = (event) => { setState({ ...state, pharam: '', value: event }); // 仅调用fetchData,data更新后组件会自动重渲染 fetchData(url, query, event) } return ( <div> ... <Select placeholder='select'> {/* 直接用data渲染选项 */} {data.map(item => ( <Select.Option key={item.name}>{item.name}</Select.Option> ))} </Select> <Button onClick={onClick}>Change Select</Button> ... </div> ) }
方案2:若必须保留field状态,用useEffect同步
如果业务需要单独维护field状态,在组件顶层添加useEffect,监听data的变化来自动同步:
export const MainPage = props => { const [state, setState] = useState({ pharam: 'Yes', value: '', }); const [field, setField] = useState([]) const {data, fetchData} = useData() // 组件顶层添加useEffect,监听data变化 useEffect(() => { // 当data更新时,同步到field setField(data) }, [data]) // 依赖项为data,仅在data变化时执行 const onClick = (event) => { setState({ ...state, pharam: '', value: event }); fetchData(url, query, event) // 无需手动调用setField,交给useEffect处理 } return ( <div> ... <Select placeholder='select'> {field.map(item => ( <Select.Option key={item.name}>{item.name}</Select.Option> ))} </Select> <Button onClick={onClick}>Change Select</Button> ... </div> ) }
额外优化:让fetchData返回请求结果(可选)
如果需要在请求完成后立刻操作结果,可以修改useData的fetchData,让它返回请求数据,这样在onClick里直接拿到最新值:
// usaData.js const useData = () => { const [data, setData] = useState([]); const fetchData = async (url, query, variable) => { const queryResult = await axios.post(url, { query: query, variables: variable, }); const resultData = queryResult.data.data; setData(resultData); // 返回请求结果 return resultData; }; return {data, fetchData} };
然后修改onClick为异步函数:
const onClick = async (event) => { setState({ ...state, pharam: '', value: event }); // 等待请求完成,拿到最新数据 const result = await fetchData(url, query, event); // 直接用返回结果设置field setField(result) }
这种方式不需要依赖data状态更新,直接拿到请求结果同步,适合需要立刻使用数据的场景。
内容的提问来源于stack exchange,提问作者Devil's Dream
相关产品推荐
相关产品推荐

