[英]Force a single re-render with useSelector
This is a follow-up to Refactoring class component to functional component with hooks, getting Uncaught TypeError: func.apply is not a function这是Refactoring class component to function component with hooks, getting Uncaught TypeError: func.apply is not a function 的后续
I've declared a functional component Parameter that pulls in values from actions/reducers using the useSelector hook:我已经声明了一个功能组件参数,它使用 useSelector 钩子从动作/减速器中提取值:
const Parameter = () => {
let viz = useSelector(state => state.fetchDashboard);
const parameterSelect = useSelector(state => state.fetchParameter)
const parameterCurrent = useSelector(state => state.currentParameter)
const dispatch = useDispatch();
const drawerOpen = useSelector(state => state.filterIconClick);
const handleParameterChange = (event, valKey, index, key) => {
parameterCurrent[key] = event.target.value;
return (
prevState => ({
...prevState,
parameterCurrent: parameterCurrent
}),
() => {
viz
.getWorkbook()
.changeParameterValueAsync(key, valKey)
.then(function () {
//some code describing an alert
});
})
.otherwise(function (err) {
alert(
//some code describing a different alert
);
});
}
);
};
const classes = useStyles();
return (
<div>
{drawerOpen ? (
Object.keys(parameterSelect).map((key, index) => {
return (
<div>
<FormControl component="fieldset">
<FormLabel className={classes.label} component="legend">
{key}
</FormLabel>
{parameterSelect[key].map((valKey, valIndex) => {
return (
<RadioGroup
aria-label="parameter"
name="parameter"
value={parameterCurrent[key]}//This is where the change should be reflected in the radio button
onChange={(e) => dispatch(
handleParameterChange(e, valKey, index, key)
)}
>
<FormControlLabel
className={classes.formControlparams}
value={valKey}
control={
<Radio
icon={
<RadioButtonUncheckedIcon fontSize="small" />
}
className={clsx(
classes.icon,
classes.checkedIcon
)}
/>
}
label={valKey}
/>
</RadioGroup>
);
})}
</FormControl>
<Divider className={classes.divider} />
</div>
);
})
) : (
<div />
)
}
</div >
)
};
export default Parameter;
What I need to have happen is for value={parameterCurrent[key]} to rerender on handleParameterChange (the handleChange does update the underlying dashboard data, but the radio button doesn't show as being selected until I close the main component and reopen it).我需要发生的是 value={parameterCurrent[key]} 在 handleParameterChange 上重新呈现(handleChange 确实更新了基础仪表板数据,但在我关闭主组件并重新打开它之前,单选按钮不会显示为被选中)。 I thought I had a solution where I forced a rerender, but because this is a smaller component that is part of a larger one, it was breaking the other parts of the component (ie it was re-rendering and preventing the other component from getting state/props from it's reducers).我以为我有一个强制重新渲染的解决方案,但是因为这是一个较小的组件,它是较大组件的一部分,所以它破坏了组件的其他部分(即它正在重新渲染并阻止其他组件获得来自它的减速器的状态/道具)。 I've been on the internet searching for solutions for 2 days and haven't found anything that works yet.我已经在互联网上搜索了 2 天的解决方案,但还没有找到任何有效的方法。 Any help is really apprecaited!任何帮助真的很感激! TIA!蒂亚!
useSelector()
uses strict ===
reference equality checks by default, not shallow equality. useSelector()
默认使用严格的===
引用相等检查,而不是浅相等检查。
To use shallow equal check, use this要使用浅等检查,请使用此
import { shallowEqual, useSelector } from 'react-redux'
const selectedData = useSelector(selectorReturningObject, shallowEqual)
Ok, after a lot of iteration, I found a way to make it work (I'm sure this isn't the prettiest or most efficient, but it works, so I'm going with it).好的,经过多次迭代,我找到了一种使其工作的方法(我确定这不是最漂亮或最有效的,但它有效,所以我会继续使用它)。 I've posted the code with changes below.我已经发布了以下更改的代码。
I added the updateState and forceUpdate lines when declaring the overall Parameter function:我在声明整个 Parameter 函数时添加了 updateState 和 forceUpdate 行:
const Parameter = () => {
let viz = useSelector(state => state.fetchDashboard);
const parameterSelect = useSelector(state => state.fetchParameter)
const parameterCurrent = useSelector(state => state.currentParameter);
const [, updateState] = useState();
const forceUpdate = useCallback(() => updateState({}), []);
const dispatch = useDispatch();
const drawerOpen = useSelector(state => state.filterIconClick);
Then added the forceUpdate() line here:然后在此处添加 forceUpdate() 行:
const handleParameterChange = (event, valKey, index, key) => {
parameterCurrent[key] = event.target.value;
return (
prevState => ({
...prevState,
parameterCurrent: parameterCurrent
}),
() => {
viz
.getWorkbook()
.changeParameterValueAsync(key, valKey)
.then(function () {
//some code describing an alert
});
})
.otherwise(function (err) {
alert(
//some code describing a different alert
);
});
forceUpdate() //added here
}
);
}; };
Then called forceUpdate in the return statement on the item I wanted to re-render:然后在我想重新渲染的项目的返回语句中调用 forceUpdate :
<RadioGroup
aria-label="parameter"
name="parameter"
value={forceUpdate, parameterCurrent[key]}//added forceUpdate here
onChange={(e) => dispatch(
handleParameterChange(e, valKey, index, key)
)}
>
I've tested this, and it doesn't break any of the other code.我已经测试过了,它不会破坏任何其他代码。 Thanks!谢谢!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.