Redux Toolkit如何根据交互输入组件条件派发不同action
实现方案
不需要为三个时长字段单独写三个action,用一个通用更新action+给输入组件传入对应字段标识的方式就能实现,步骤如下:
1. 首先完善timerSlice的reducer逻辑
直接在reducers里加通用的时长更新、调整方法,通过payload传入要修改的字段名和目标值即可,Redux Toolkit支持直接修改状态字段,不用手动写不可变更新逻辑:
// timerSlice.js import { createSlice } from '@reduxjs/toolkit' const initialState = { pomodoroMinutes: 25, shortBreakMinutes: 5, longBreakMinutes: 15, } const timerSlice = createSlice({ name: 'timer', initialState, reducers: { // 直接输入数值时的更新action updateMinutes: (state, action) => { const { field, value } = action.payload // 只允许修改已定义的三个时长字段,避免非法状态修改 if (['pomodoroMinutes', 'shortBreakMinutes', 'longBreakMinutes'].includes(field)) { // 兜底处理,时长不能小于0 state[field] = Math.max(0, Number(value)) } }, // 点击加减按钮时的调整action adjustMinutes: (state, action) => { const { field, delta } = action.payload if (['pomodoroMinutes', 'shortBreakMinutes', 'longBreakMinutes'].includes(field)) { const newValue = state[field] + delta state[field] = Math.max(0, newValue) } } } }) // 导出action方法供组件调用 export const { updateMinutes, adjustMinutes } = timerSlice.actions export default timerSlice.reducer
2. 改造NumberInput组件,补全交互所需props
原来的组件仅传入了label,现在需要补充值绑定、事件回调相关props,把加减按钮、输入框的交互事件都接上:
//NumberInput.js import React from 'react'; import styled from "./NumberInput.module.css"; const NumberInput = ({ label, value, onIncrement, onDecrement, onChange }) => { return ( <div className={styled.inputContainer}> <label htmlFor="">{label}</label> <input className={styled.input} type="number" min={0} value={value} onChange={(e) => onChange(e.target.value)} /> {/* 上箭头对应增加值 */} <button className={styled.inputBtn} type="button" onClick={onIncrement}> <svg width="14" height="7" viewBox="0 0 14 7" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M1 6L7 2L13 6" stroke="#1E213F" strokeOpacity="0.25" strokeWidth="2"/> </svg> </button> {/* 下箭头对应减少值 */} <button className={styled.inputBtn} type="button" onClick={onDecrement}> <svg width="14" height="7" viewBox="0 0 14 7" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M1 1L7 5L13 1" stroke="#1E213F" strokeOpacity="0.25" strokeWidth="2"/> </svg> </button> </div> ); }; export default NumberInput;
3. 在弹窗父组件中传入对应配置使用
从store读取三个时长的值,给每个NumberInput传入对应字段的操作回调即可,不需要重复写多套dispatch逻辑:
// 设置弹窗组件示例 import { useDispatch, useSelector } from 'react-redux' import NumberInput from './NumberInput' import { updateMinutes, adjustMinutes } from './timerSlice' const SettingsModal = () => { const dispatch = useDispatch() // 从store读取三个时长的当前值 const { pomodoroMinutes, shortBreakMinutes, longBreakMinutes } = useSelector(state => state.timer) // 抽成配置数组,不用重复写三次组件代码 const inputConfig = [ { label: '番茄工作时段', field: 'pomodoroMinutes', value: pomodoroMinutes }, { label: '长休息时段', field: 'longBreakMinutes', value: longBreakMinutes }, { label: '短休息时段', field: 'shortBreakMinutes', value: shortBreakMinutes }, ] return ( <div className="modal"> {inputConfig.map(item => ( <NumberInput key={item.field} label={item.label} value={item.value} onIncrement={() => dispatch(adjustMinutes({ field: item.field, delta: 1 }))} onDecrement={() => dispatch(adjustMinutes({ field: item.field, delta: -1 }))} onChange={(val) => dispatch(updateMinutes({ field: item.field, value: val }))} /> ))} </div> ) } export default SettingsModal
这种实现方式比写三个独立action更易维护,如果后续要新增时长类型,只需要在initialState和配置数组里加对应项即可,不用重复编写reducer和组件逻辑。
内容的提问来源于stack exchange,提问作者Dastan Zhamekeshev
相关产品推荐
相关产品推荐

