如何将非Redux的React表单改造为Redux方案以避免冗余渲染?
用Redux Toolkit解决表单组件不必要渲染问题
问题根源
你当前的实现中,BigForm作为父组件维护dataA和dataB两个状态,每次更新其中一个状态时,父组件会重新渲染,导致两个子组件FormA和FormB也跟着重新渲染——即使另一个组件的props并没有变化。Redux可以让子组件直接订阅自己需要的状态,避免这种无意义的渲染。
解决方案步骤(基于Redux Toolkit,官方推荐的现代Redux用法)
1. 安装依赖
首先安装Redux Toolkit和React-Redux:
npm install @reduxjs/toolkit react-redux
2. 创建表单状态Slice
在项目中新建features/form/formSlice.js文件,定义状态和操作:
import { createSlice } from '@reduxjs/toolkit'; const initialState = { dataA: '', dataB: '' }; const formSlice = createSlice({ name: 'form', initialState, reducers: { updateDataA: (state, action) => { state.dataA = action.payload; }, updateDataB: (state, action) => { state.dataB = action.payload; } } }); export const { updateDataA, updateDataB } = formSlice.actions; export default formSlice.reducer;
3. 配置Redux Store
新建app/store.js文件:
import { configureStore } from '@reduxjs/toolkit'; import formReducer from '../features/form/formSlice'; export const store = configureStore({ reducer: { form: formReducer } });
4. 在根组件中包裹Provider
修改你的根组件(比如index.js),用Redux的Provider包裹整个应用:
import React from 'react'; import ReactDOM from 'react-dom/client'; import { Provider } from 'react-redux'; import { store } from './app/store'; import { BigForm } from './BigForm'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <Provider store={store}> <BigForm /> </Provider> );
5. 修改组件代码
更新FormA、FormB和BigForm,让它们直接和Redux交互:
import React, { useEffect } from "react"; import { useSelector, useDispatch } from 'react-redux'; import { updateDataA } from './features/form/formSlice'; const FormA = () => { useEffect(()=>{ console.log('Form A was just rendered')}) // 只订阅dataA状态 const dataA = useSelector(state => state.form.dataA); const dispatch = useDispatch(); return ( <div> <input onChange={(e) => dispatch(updateDataA(e.target.value))}></input> <p>Input Form A{dataA}</p> </div> ); }; const FormB = () => { useEffect(()=>{ console.log('Form B was just rendered')}) // 只订阅dataB状态 const dataB = useSelector(state => state.form.dataB); const dispatch = useDispatch(); return ( <div> <input onChange={(e) => dispatch(updateDataB(e.target.value))}></input> <p>Input Form B{dataB}</p> </div> ); }; export function BigForm () { // 父组件不再维护状态,只负责渲染子组件 return ( <div className="App"> <FormA /> <FormB /> </div> ); }
效果验证
现在在FormA输入内容时,只有FormA会触发渲染日志;在FormB输入时,只有FormB会触发渲染日志,彻底解决了不必要的渲染问题。同时所有表单数据都统一存储在Redux store中,方便后续聚合使用。
内容的提问来源于stack exchange,提问作者Ae Leung
相关产品推荐
相关产品推荐

