React useReducer实战疑问:状态处理、子组件传值及多字段操作
React useReducer 实现筛选功能答疑
问题1:change handler不是纯函数,需要外部库吗?
不需要。useReducer只要求reducer函数必须是纯函数,而触发dispatch的回调(比如react-select的onChange)完全可以是非纯的——你只需要在这个回调里把筛选的结果整理成符合action格式的数据,再传给dispatch就行,不用额外依赖库。
问题2:dispatch方法该在父组件声明还是传给子组件?
直接把dispatch传给子组件就行,或者在父组件封装一个回调函数再传给子组件,两种方式都可行:
- 直接传dispatch:子组件里拿到dispatch后,直接构造action触发状态变更
- 封装回调:在父组件里写好处理逻辑(比如格式化react-select返回的选项数据),再把这个回调传给子组件,这样子组件不需要知道dispatch的细节,更解耦
问题3:多个筛选字段需要写单独的action吗?
两种方案任你选:
- 方案一:为每个字段写单独action(比如
SET_MAKE、SET_MODEL),每个action对应明确的状态变更,逻辑清晰,后期维护起来一目了然 - 方案二:用一个通用action(比如
UPDATE_FILTER),action的payload里携带字段名和对应值,这样reducer里只需要一个case就能处理所有筛选字段的更新,代码更简洁
解决react-select获取选中值更新状态的代码示例
第一步:定义reducer
const filterReducer = (state, action) => { switch (action.type) { // 通用action方案 case 'UPDATE_FILTER': return { ...state, [action.payload.key]: action.payload.value }; // 如果用单独action方案,替换成下面的case: // case 'SET_MAKE': // return { ...state, make: action.payload }; // case 'SET_MODEL': // return { ...state, model: action.payload }; default: return state; } };
第二步:父组件使用useReducer并传递回调给子组件
import { useReducer, useEffect, useState } from 'react'; import Select from 'react-select'; // 初始筛选状态 const initialFilters = { make: null, model: null }; const ParentComponent = () => { const [filters, dispatch] = useReducer(filterReducer, initialFilters); const [filteredData, setFilteredData] = useState([]); const [rawData, setRawData] = useState([]); // 模拟从服务器获取原始数据 useEffect(() => { fetch('/api/vehicle-data') .then(res => res.json()) .then(data => setRawData(data)); }, []); // 根据筛选条件过滤数据 useEffect(() => { let result = [...rawData]; // 品牌筛选 if (filters.make) { result = result.filter(item => item.make === filters.make.value); } // 车型筛选 if (filters.model) { result = result.filter(item => item.model === filters.model.value); } setFilteredData(result); }, [filters, rawData]); // 封装筛选变更回调:react-select的onChange返回选中的选项对象 const handleFilterChange = (filterKey) => (selectedOption) => { dispatch({ type: 'UPDATE_FILTER', payload: { key: filterKey, value: selectedOption } }); // 如果用单独action方案,替换成: // dispatch({ type: `SET_${filterKey.toUpperCase()}`, payload: selectedOption }); }; // 假设预先定义的选项数组 const makeOptions = [ { value: 'Toyota', label: '丰田' }, { value: 'Honda', label: '本田' } ]; const modelOptions = [ { value: 'Camry', label: '凯美瑞' }, { value: 'Accord', label: '雅阁' } ]; return ( <div className="filter-container"> <Select options={makeOptions} value={filters.make} onChange={handleFilterChange('make')} placeholder="选择品牌" /> <Select options={modelOptions} value={filters.model} onChange={handleFilterChange('model')} placeholder="选择车型" isDisabled={!filters.make} // 可选:未选品牌时禁用车型选择 /> {/* 渲染过滤后的数据 */} <div className="data-list"> {filteredData.length > 0 ? ( filteredData.map(item => ( <div key={item.id} className="data-item"> {item.make} - {item.model} </div> )) ) : ( <p>暂无匹配数据</p> )} </div> </div> ); }; export default ParentComponent;
注意:react-select的onChange回调返回的是选中的选项对象(不是event),所以你可以直接拿到selectedOption.value或者把整个对象存在筛选状态里——上面示例存的是整个对象,方便后续在Select组件里回显选中值。
内容的提问来源于stack exchange,提问作者Nemanja
相关产品推荐
相关产品推荐

