Javascript 使用useReducer时,如何获取useCallback中的当前状态?

Javascript 使用useReducer时,如何获取useCallback中的当前状态?,javascript,reactjs,typescript,react-hooks,Javascript,Reactjs,Typescript,React Hooks,将react hooks与TypeScript一起使用,下面是我尝试做的一个最简单的表示:在屏幕上有一个按钮列表,当用户单击按钮时,我想将按钮的文本更改为“button clicked”,然后仅重新渲染单击的按钮 我使用useCallback包装按钮单击事件,以避免在每次渲染时重新创建单击处理程序 此代码按照我想要的方式工作:如果我使用useState并在数组中维护我的状态,那么我可以使用in-useState并获得我想要的确切行为: import*as React from'React';

将react hooks与TypeScript一起使用,下面是我尝试做的一个最简单的表示:在屏幕上有一个按钮列表,当用户单击按钮时,我想将按钮的文本更改为“button clicked”,然后仅重新渲染单击的按钮

我使用useCallback包装按钮单击事件,以避免在每次渲染时重新创建单击处理程序

此代码按照我想要的方式工作:如果我使用useState并在数组中维护我的状态,那么我可以使用in-useState并获得我想要的确切行为:

import*as React from'React';
从“/IHelloWorldProps”导入{IHelloWorldProps};
从“react”导入{useffect,useCallback,useState};
从“office ui fabric react”导入{PrimaryButton};
界面IMyButtonProps{
标题:字符串;
id:字符串;
onClick:(clickedDeviceId:string)=>(事件:任意)=>void;
}
const MyButton:React.FunctionComponent=React.memo((props:IMyButtonProps)=>{
log(`Button rendered for${props.title}`);
返回;
});
接口设备{
名称:字符串;
Id:字符串;
}
const HelloWorld:React.FunctionComponent=(props:IHelloWorldProps)=>{
//如果我对状态使用数组而不是对象,然后对函数更新使用useState,我会得到想要的结果。
常量initialState:IDevice[]=[];
const[deviceState,setDeviceState]=useState(初始状态);
useffect(()=>{
//模拟网络调用以加载数据。
设置超时(()=>{
setDeviceState([{Name:“Apple”,Id:“appl01”},{Name:“Android”,Id:“andr02”},{Name:“Windows Phone”,Id:“wp03”}]);
}, 500);
}, []);
const\u deviceClicked=useCallback((clickedDeviceId:string)=>((事件:任意):void=>{
setDeviceState(prevState=>prevState.map((设备:IDevice)=>{
如果(device.Id==clickedDeviceId){
device.Name=`${device.Name}单击了`;
}
返回装置;
}));
}), []);
返回(
{deviceState.map((设备:IDevice)=>{
返回;
})}
);
};

导出默认HelloWorld您可以分派一个函数,该函数将被reducer调用,并获取传递给它的当前状态。大概是这样的:

//Using useReducer to mimic class component's this.setState functionality where only the updated state needs to be sent to the reducer instead of the entire state.
const [deviceState, dispatch] = useReducer(
  (previousState, action) => action(previousState),
  initialState
);

//Have to wrap in useCallback otherwise the "MyButton" component will get a new version of _deviceClicked for each time.
//If the useCallback wrapper is removed from here, I see the behavior I want but then the entire device list is re-rendered everytime I click on a device.
const _deviceClicked = useCallback(
  (clickedDeviceId) => (event) => {
    //Since useCallback contains the cached version of the function before the useEffect runs, deviceState.devices is always an empty array [] here.
    dispatch((deviceState) => ({
      ...deviceState,
      devices: deviceState.devices.map((device) => {
        if (device.Id === clickedDeviceId) {
          device.Name = `${device.Name} clicked`;
        }

        return device;
      }),
    }));
    //no dependencies here
  },
  []
);
下面是一个工作示例:

const{useCallback,useReducer}=React;
常量应用=()=>{
const[deviceState,dispatch]=useReducer(
(previousState,action)=>操作(previousState),
{计数:0,其他:88}
);
const click=useCallback(
(增加)=>()=>{
//由于useCallback在useEffect运行之前包含函数的缓存版本,因此deviceState.devices在此始终为空数组[]。
调度((设备状态)=>({
…设备状态,
计数:设备状态。计数+增加,
}));
//这里没有依赖项
},
[]
);
返回(
+1
+2
+3
{JSON.stringify(deviceState)}
);
};
ReactDOM.render(,document.getElementById('root'))


useState
是对组件的
setState
合并行为进行分类的最简单选项。你仍然选择
useReducer
有什么原因吗?谢谢,是的,我重新考虑了一下,决定选择
useState
。谢谢,我已经将此标记为答案,但你是对的,
useState
可能更适合这里,所以我决定使用它而不是useReducer。创建了一个自定义钩子,该钩子围绕useState进行包装,并公开函数以将新状态与现有状态合并,或者如果新状态依赖于现有状态,则公开分派方法。