javascript - React/Redux/Reselect - mapStateToProps 即使在看到 reducer 中反映的更改后也会停止触发。
问题描述
我搜索了一个类似的问题,但找不到合适的帖子(......虽然我怀疑这个问题之前已经被问过)所以我提前道歉。
我现在已经在几个项目中使用 Redux 和 React,并且刚刚开始在学习项目中包含 immutable.js 和 Reselect。我的测试/学习项目只是将一个大型 JSON 对象加载到状态中,然后我使用 Reselect 来抓取它的一部分,然后传递到我的组件中。这是我正在加载的对象的示例:
export const formState = {
progress: {
groupId: 3,
questionId: 5,
},
content: [
{
group: { id: 1, name: 'Company', description: 'Data regarding your company.', questions: 2 },
questions: [
{
id: 1,
type: 'textField',
label: 'Required *',
inputLabelProps: { shrink: true },
text: 'group 1 question 1',
answer: '',
},
...
...
...
]
}
该对象通过在 componentWillMount() 中触发的操作加载到状态,然后流经 reducer,最终触发组件内的 mapStateToProps,如下所示:
const mapStateToProps = (state) => {
console.log(state);
return {
progress: getProgressData(state),
content: getContentData(state),
};
};
这按预期工作。该组件有两个按钮,可让您遍历在上述“整体状态”的内容对象中找到的问题数组。
此外,当您按下前进或后退按钮遍历上述问题数组时,进度对象通过一个操作更新,然后通过以下方式在减速器中更新:
switch (action.type) {
case UPDATE_PROGRESS:
formState = state.get('formState');
formState.progress = action.payload;
console.log(formState);
return state
.set('formState', formState);
所以这就是奇怪的地方。我第一次向前或向后单击时,它可以工作,我看到对象得到更新,下一个问题显示在我的组件中。正如预期的那样......
如果我再次单击返回或下一步,我看到动作被触发,我看到减速器中反映了适当的状态,但我将不再在 mapStateToProps 的 console.log 中看到状态。它永远不会到那个地步。关于我做错了什么的任何想法?
注意:我不只是通过以下方式更新减速器中的状态可能看起来很奇怪: return state .setIn(['formState', 'progress'], formState)
我最初尝试这样做,但得到了无效的密钥路径。考虑到我正在通过 fromJS() 将初始状态转换为 immutable.js 映射,这对我来说很奇怪,所以我认为其中包含的任何内容都是映射或列表或任何合适的东西,因此可以通过这种方式寻址......无论如何,我想一旦我解决了上述问题,我就会解决这个问题。也就是说,除非它们是相关的。
与往常一样,如果这是一个重复的问题,我们将不胜感激并真诚地道歉。
谢谢!
解决方案
问题
Immutable.js 函数 Collection.get 返回给定键后面的值,在本例中是指向对象的指针。目前,您更改该对象,然后使用 Collection.set 将其设置回来。对象发生了变化,但指向该对象的指针(即存储在您的状态中的值)没有。因此,您的状态在技术上没有改变,并且您的组件不会更新。
出现此问题是因为您将普通对象存储在 Immutable.js 集合中。您应该只使用普通对象,或者只使用 Immutable.js 集合来安全地使用它。不要混合它们。
使固定
选项 1:Immutable.js 集合
将 state.formState 也设为 Immutable.js 集合。然后通过 Immutable.js 方法更改它。
switch (action.type) {
case UPDATE_PROGRESS: {
let formState = state.get('formState');
formState = formState.set('progress', action.payload)
console.log(formState);
return state
.set('formState', formState);
}
如果你决定使用 Immutable.js,你应该确保不要留下任何 vanilla javascript 对象,因为它们可以绕过 Immutable.js 提供的保护。
选项 2:普通对象(推荐)
将 state 设为 vanilla javascript 对象。
switch (action.type) {
case UPDATE_PROGRESS: {
const formState = { ...state.formState };
formState.progress = action.payload
console.log(formState);
return { ...state, formState };
}
如果您决定不使用 Immutable.js,则必须小心不要意外直接更改状态。最简单的方法是使用扩展语法复制状态:const stateCopy = { ...state };
推荐阅读
- ios - 为什么我会收到 UIDatePicker 和静态 UITableView 的约束错误?
- flutter - Flutter:如何通过 GetxController 控制 PageView?
- javascript - 如何排除文件被 tsc 处理?
- r - 将矩阵列表合并为更大的矩阵
- docker - docker-compose 不同 docker-compose 文件冲突中的相同服务名称
- php - 如何在 Vscode 中禁用参数提示
- r - Plot using subset and/or dplyr:filter doesn't work with dynamic reactive objects
- node.js - Node JS Sequelize:再次运行相同的查询正在检索先前的结果
- c# - 在 WinForms 中保存不同用户的用户设置?
- java - 如何获得与 filter 和 findFirst 相同的结果