React/Redux/Reselect - mapStateToProps 即使在看到 reducer 中反映的更改后也会停止触发。
React/Redux/Reselect - mapStateToProps stops firing even after seeing changes reflected in the reducer.
我搜索了类似的问题,但找不到合适的问题 post(...虽然我怀疑这个问题之前有人问过)所以我提前道歉。
我现在已经在几个项目中使用 Redux 和 React,并且刚刚开始在一个学习项目中包括 immutable.js 和 Reselect。我的 testing/learning 项目只是将一个大的 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),
};
};
这按预期工作。该组件有两个按钮,可让您遍历在上述 "overall state."
的内容对象中找到的问题数组
此外,当您按下前进或后退按钮遍历上述问题数组时,进度对象会通过一个操作进行更新,然后通过以下方式在 reducer 中进行更新:
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 状态
.setIn(['formState', 'progress'], formState)
我最初尝试这样做,但得到的密钥路径无效。考虑到我正在通过 fromJS() 将初始状态转换为 immutable.js 映射,这对我来说很奇怪,所以我认为其中包含的任何内容都是映射或列表或任何合适的,因此可以通过这种方式寻址。 .. 无论如何,我想一旦我解决了上述问题我就会解决这个问题。也就是说,除非它们是相关的。
一如既往,如果这是一个重复的问题,我们将不胜感激,我们深表歉意。
谢谢!
你不应该在 reducer 中更新状态。它几乎总是会导致奇怪的行为,immutable-update-patterns。您是否尝试返回新对象?即
switch (action.type) {
case UPDATE_PROGRESS:
return {
...state,
formState: {
...state.formState,
progress: action.payload
}
};
问题
Immutable.js 函数 Collection.get returns 给定键后面的值,在本例中是指向 object 的指针。目前,您可以更改 object,然后使用 Collection.set 将其重新设置。 object 发生了变化,但是指向 object 的指针(即存储在您的状态中的值)没有发生变化。因此,您的状态在技术上没有变化,您的组件也没有更新。
出现此问题是因为您将纯 object 存储在 Immutable.js Collection 中。您应该只使用普通的 objects 或只使用 Immutable.js Collections 以确保安全。不要混用。
修复
选项 1:Immutable.jsCollections
也使state.formState成为Immutable.jsCollection。然后通过 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,您应该确保不要留在任何原版 javascript object 中,因为它们可以绕过 Immutable.js 提供的保护.
选项 2:普通 objects(推荐)
将状态设为原版 javascript object.
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 };
我搜索了类似的问题,但找不到合适的问题 post(...虽然我怀疑这个问题之前有人问过)所以我提前道歉。
我现在已经在几个项目中使用 Redux 和 React,并且刚刚开始在一个学习项目中包括 immutable.js 和 Reselect。我的 testing/learning 项目只是将一个大的 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),
};
};
这按预期工作。该组件有两个按钮,可让您遍历在上述 "overall state."
的内容对象中找到的问题数组此外,当您按下前进或后退按钮遍历上述问题数组时,进度对象会通过一个操作进行更新,然后通过以下方式在 reducer 中进行更新:
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 状态 .setIn(['formState', 'progress'], formState)
我最初尝试这样做,但得到的密钥路径无效。考虑到我正在通过 fromJS() 将初始状态转换为 immutable.js 映射,这对我来说很奇怪,所以我认为其中包含的任何内容都是映射或列表或任何合适的,因此可以通过这种方式寻址。 .. 无论如何,我想一旦我解决了上述问题我就会解决这个问题。也就是说,除非它们是相关的。
一如既往,如果这是一个重复的问题,我们将不胜感激,我们深表歉意。
谢谢!
你不应该在 reducer 中更新状态。它几乎总是会导致奇怪的行为,immutable-update-patterns。您是否尝试返回新对象?即
switch (action.type) {
case UPDATE_PROGRESS:
return {
...state,
formState: {
...state.formState,
progress: action.payload
}
};
问题
Immutable.js 函数 Collection.get returns 给定键后面的值,在本例中是指向 object 的指针。目前,您可以更改 object,然后使用 Collection.set 将其重新设置。 object 发生了变化,但是指向 object 的指针(即存储在您的状态中的值)没有发生变化。因此,您的状态在技术上没有变化,您的组件也没有更新。
出现此问题是因为您将纯 object 存储在 Immutable.js Collection 中。您应该只使用普通的 objects 或只使用 Immutable.js Collections 以确保安全。不要混用。
修复
选项 1:Immutable.jsCollections
也使state.formState成为Immutable.jsCollection。然后通过 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,您应该确保不要留在任何原版 javascript object 中,因为它们可以绕过 Immutable.js 提供的保护.
选项 2:普通 objects(推荐)
将状态设为原版 javascript object.
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 };