React中props何时变更?是否仅由父组件重渲染触发?还有其他场景吗?
一、Props何时发生变更?
Props是父组件传递给子组件的数据,当传递的数据源本身发生变化,且父组件在重渲染时将这个变化后的值传递给子组件时,子组件的props就会变更。
二、Props变更是否必然由父组件重渲染触发?
是的。React的渲染逻辑是:组件只有在重渲染时,才会重新计算JSX中的值并传递给子组件。如果父组件不重渲染,哪怕你直接修改了某个非状态变量(这本身就不符合React规范),子组件接收的props也不会更新——因为父组件没重新执行渲染逻辑,子组件拿到的还是旧值。
三、是否只需关注父组件更新?还有哪些其他触发props变更的场景?
除了你给出的「父组件state更新导致重渲染」的场景,还有以下几种常见情况:
1. 父组件自身的props变更引发重渲染
如果父组件本身也是某个组件的子组件,当它的父级传递的props变化时,父组件会重渲染,进而可能导致它传递给子组件的props变更。比如:
const Grandparent = () => { const [count, setCount] = useState(0); return <Parent count={count} />; }; const Parent = ({ count }: { count: number }) => { // 父组件因自身props变更重渲染,传递给Child的props随之更新 return <Child doubled={count * 2} />; }; const Child = ({ doubled }: { doubled: number }) => { return <div>{doubled}</div>; };
2. 父组件用useReducer更新状态触发重渲染
和useState类似,useReducer触发的状态更新会让父组件重渲染,进而更新子组件props:
const ParentComponent = () => { const [state, dispatch] = useReducer((state, action) => { switch(action.type) { case 'UPDATE_MESSAGE': return { ...state, message: action.payload }; default: return state; } }, { message: 'Hello World' }); return ( <> <button onClick={() => dispatch({ type: 'UPDATE_MESSAGE', payload: 'Hello Foo' })}> Click </button> <ChildComponent message={state.message} /> </> ); };
3. 手动强制父组件重渲染(不推荐但存在这种场景)
直接修改useRef的current值不会触发重渲染,但如果手动调用强制重渲染的方法(比如类组件的forceUpdate,或者函数组件用空state触发),父组件重渲染后也会更新子组件props:
const ParentComponent = () => { const messageRef = useRef('Hello World'); const [, forceUpdate] = useState({}); return ( <> <button onClick={() => { messageRef.current = 'Hello Foo'; forceUpdate({}); // 手动触发重渲染 }}>Click</button> <ChildComponent message={messageRef.current} /> </> ); };
注意:这种方式违反React的数据流规范,实际开发中不推荐使用,仅作为场景说明。
4. 类组件中setState/forceUpdate触发重渲染
类组件里调用this.setState更新状态,或者直接this.forceUpdate强制重渲染,都会导致父组件重新渲染,进而更新子组件的props:
class ParentComponent extends React.Component { state = { message: 'Hello World' }; render() { return ( <> <button onClick={() => this.setState({ message: 'Hello Foo' })}>Click</button> <ChildComponent message={this.state.message} /> </> ); } }
5. 父组件依赖的Context发生变化
如果父组件使用了useContext,当Context的全局值更新时,父组件会重渲染,可能导致传递给子组件的props变更:
const MessageContext = createContext('Hello World'); const Grandparent = () => { const [message, setMessage] = useState('Hello World'); return ( <MessageContext.Provider value={message}> <Parent /> </MessageContext.Provider> ); }; const Parent = () => { const message = useContext(MessageContext); // Context变化导致Parent重渲染,传递给Child的props更新 return <ChildComponent message={message} />; };
总结
所有props变更的根源都是父组件发生了重渲染,而父组件重渲染的触发原因除了自身state更新,还包括自身props变更、依赖的Context变化、强制重渲染等场景。只要父组件重渲染时,传递给子组件的props值和之前不同(React做浅比较),子组件的props就会发生变更。
内容的提问来源于stack exchange,提问作者Leech

