React中如何更新状态且不触发组件重渲染
问题原因
- 题目生成逻辑直接放在Question组件的渲染流程里,组件只要触发重渲染,
makeQuestion就会重新执行生成新的随机数,题目自然会变 - 你把用户输入的状态存在顶层App组件里,每次输入调用
setUserAnswer都会触发App重渲染,连带Question子组件一起重跑渲染逻辑 - 直接在App的return里写
<Input />作为prop传给Question,每次App重渲染都会生成新的组件引用,也会触发子组件不必要的重渲染
修复方案
核心思路是两点:一是把题目生成结果缓存住,不要每次渲染都重新算随机数;二是缩小状态触发重渲染的范围,不要让输入框的局部更新影响整个组件树。
1. 缓存题目生成结果
用useState的初始化函数,只在Question组件首次挂载的时候生成随机数,后续重渲染不会重新执行随机逻辑:
import { useState } from 'react'; const Question = ({ input }) => { // 初始化函数仅在组件首次挂载时执行一次,后续重渲染直接复用已生成的题目 const [questionText] = useState(() => { const firstNumber = randomRange(); const secondNumber = randomRange(); return `${firstNumber} + ${secondNumber}`; }); return ( <> <div>{questionText}</div> {input} </> ); }; export default Question;
2. 下沉输入状态,缩小重渲染范围
不要把输入框的临时值存在顶层App,把状态放到输入组件内部,只有用户确认提交答案(比如按回车、点提交按钮)的时候,再把最终值传给父组件,这样输入过程中只会触发输入框自己重渲染,不会影响上层的Question和App组件:
import { useState } from 'react'; const UserInput = ({ onSubmit }) => { // 输入过程中的临时状态存在组件内部,更新时不会触发父组件重渲染 const [inputVal, setInputVal] = useState(''); return ( <input value={inputVal} onChange={(e) => setInputVal(e.target.value)} onKeyDown={(e) => { // 按回车时才把答案提交给父组件 if (e.key === 'Enter') { onSubmit(inputVal); } }} /> ); };
3. 优化顶层组件逻辑
App里只存最终提交的答案,固定回调函数的引用,避免不必要的组件更新:
import { useState, useCallback } from 'react'; function App() { const [finalAnswer, setFinalAnswer] = useState(''); // 用useCallback缓存回调,避免每次渲染生成新函数引用 const handleAnswerSubmit = useCallback((answer) => { setFinalAnswer(answer); // 这里可以加答案校验、触发刷新新题的逻辑 }, []); return <Question input={<UserInput onSubmit={handleAnswerSubmit} />} />; }
如果你确实需要实时同步输入值到父组件(比如做实时输入校验),可以给Question组件套
React.memo做浅比较缓存,配合上面的题目初始化逻辑,就算上层重渲染,Question也不会重复生成题目。
内容的提问来源于stack exchange,提问作者flowoverstack
相关产品推荐
相关产品推荐

