【问题标题】:How to use setState along with dispatch from redux - it re-renders whole component and restarts updated setState如何使用 setState 以及来自 redux 的调度 - 它重新渲染整个组件并重新启动更新的 setState
【发布时间】:2022-08-22 03:24:43
【问题描述】:
我有这个组件
const CheckboxColumn: FC<ICheckboxColumnProps> = ({ id_llamada }) => {
// select pickup
const dispatch = useTypedDispatch();
const [isPickupSelected, setIsPickupSelected] = useState(false);
const selectPickup = (e: ChangeEvent<HTMLInputElement>) => {
setIsPickupSelected(e.target.checked);
dispatch(controlPickup(id_llamada));
};
return (
<TableCell
component={\'div\'}
padding=\"checkbox\"
sx={{ padding: \'0px 0px 0px 4px\' }}
onClick={(e) => {
e.stopPropagation();
}}
>
<Checkbox
color=\"primary\"
checked={isPickupSelected ? true : false}
// disabled={true}
sx={{
padding: \'7px\',
\'&:hover\': {
backgroundColor: \'rgba(0, 0, 0, 0.06)\',
},
}}
onChange={selectPickup}
/>
</TableCell>
);
};
export default CheckboxColumn;
而且我需要能够选择一个表的行,还要将其信息发送到 redux,问题是,我不知道如何使用 setState 和 dispatch
目前正在发生的事情是,我的isPickupSelected 没有更新它的值,而是它实际上保存在我的减速器中的数据,并且当我评论dispatch(function()) 时,我的状态能够正常工作。
我一直在尝试寻找解决方案,其中之一是,我应该使用 useEffect 并且每当我的状态发生变化时,我应该调度该函数,它可以工作,但它会立即重新启动我的组件,还有我的isPickupSelected,所以我的状态不再更新,而是恢复到原来的值false
在这种情况下我该怎么办
标签:
reactjs
redux
setstate
redux-toolkit
【解决方案1】:
您不必在下面进行相等检查,因为 isPickupSelected 已经是 boolean 值。
checked={isPickupSelected ? true : false}
尝试简单地使用:
<Checkbox
color="primary"
checked={isPickupSelected}
...
此外,鉴于复选框只能选中或取消选中,您实际上可以这样做:
const selectPickup = () => {
setIsPickupSelected(!isPickupSelected) // instead of `e.target.checked`
这样,当用户单击复选框时,状态设置器会将isPickupValue 设置为与当前值相反的值(切换)。
让我知道这是否能解决您的问题?干杯
【解决方案2】:
您的调度如何更新状态与您的 setIsPickupSelected 之间的区别在于,您的调度状态依赖于前一个状态值来确定下一个状态值,而您的设置器依赖于 UI 元素值。该 UI 元素值由 isPickupState 控制,因此当单击复选框时,传入的值将是您从 e.target.checked 获得的值。要解决此问题,您需要与 UI 元素分开控制该状态。您已经使用 isPickupSelected 状态变量执行此操作。
此外,由于您的复选框组件是唯一使用状态的组件,因此您可以在每次复选框更改时保存您的 TableCell 重新渲染。您所要做的就是将该逻辑提升到一个单独的组件中。
const ControlledCheckbox : FC<IControlledCheckboxProps> = () => {
const dispatch = useTypedDispatch();
const [isPickupSelected, setIsPickupSelected] = useState(false);
const selectPickup = () => {
setIsPickupSelected(!isPickupSelected);
dispatch(controlPickup(id_llamada));
};
return <Checkbox
color="primary"
checked={isPickupSelected ? true : false}
// disabled={true}
sx={{
padding: '7px',
'&:hover': {
backgroundColor: 'rgba(0, 0, 0, 0.06)',
},
}}
onChange={selectPickup}
/>
}
const CheckboxColumn: FC<ICheckboxColumnProps> = ({ id_llamada }) => {
return (
<TableCell
component={'div'}
padding="checkbox"
sx={{ padding: '0px 0px 0px 4px' }}
onClick={(e) => {
e.stopPropagation();
}}
>
<ControlledCheckbox />
</TableCell>
);
};
export default CheckboxColumn;
【解决方案3】:
解决方案 1:从 Checkbox 中删除选中的道具,使其不受控制的输入。
// checked={isPickupSelected ? true : false}
解决方案 2:在处理程序 func 中:
setIsPickupSelected(prevState => !prevState)
【解决方案4】:
prop id_llamada 来自 Redux 商店吗?
如果是这种情况,那么组件将重新渲染,从而将 isPickedUpSelected 设置回 false。为什么?我假设调度在父级别更新id_llamada 的值,导致渲染进程捕获更新并在组件传递回组件时重新渲染组件。
以上将是组件状态未更新的根本原因,这就是为什么当您注释掉调度时状态更新起作用的原因。
为避免这种情况,您可能希望使用 id_llamada 的存储值,而不是将其作为道具传递。也许您想了解Redux Selectors。
此外,作为与初始问题无关的观察结果,由于isPickupSelected 是一个布尔值,您可以将checked={isPickupSelected ? true : false} 简化为checked={isPickupSelected}。