如果连接到未更改的商店,React componentDidUpdate 方法不会在继承的道具更改时触发
React componentDidUpdate method won't fire on inherited props change if connected to a store that didn't change
我想让我的组件知道是否已经加载了一些库。要知道从任何上下文我都将它连接到我商店的 "library" reducer 到我的组件。
我还从调用组件的父级向它传递一个配置对象 this.props.dataObject
。像这样:
class GoogleButton extends Component {
render() {
if (this.props.libraries.google) {
return <a id='sharePost' className='google_icon'></a>
} else {
return null
}
}
componentDidUpdate() {
gapi.interactivepost.render('sharePost', this.props.dataObject)
}
}
function mapStateToProps(state) {
return { libraries: state.libraries }
}
export default connect(mapStateToProps)(GoogleButton)
处理库状态的reducer是这样的:
let newState = {...state}
newState[action.libraryName] = action.state
return newState
当我更改库状态时 componentDidUpdate
有效。问题是当我更改父 this.props.dataObject
继承的道具时。在那种情况下,componentDidUpdate 不会触发。如果我从组件中删除 connect
它会按预期工作。我在这里遗漏了什么?
很可能你的一些道具在组件外发生了变化。
例如,您可能会像这样渲染您的组件:
class Parent extends Component {
constructor() {
super()
this.state = { libraries: {} }
}
handleClick() {
// MUTATION!
this.state.libraries.google = true
// Normally this forces to update component anyway,
// but React Redux will assume you never mutate
// for performance reasons.
this.setState({ libraries: this.state.libraries })
}
render() {
return (
<div onClick={() => this.handleClick()}>
<GoogleButton libraries={this.state.libraries} />
</div>
)
}
}
因为 Redux 应用程序处理不可变数据,connect()
使用 shallow equality check 作为其 props 以避免不必要的重新渲染。但是,如果您在应用中使用突变,这将不起作用。
你有两个选择:
不要改变任何东西
这是最好的选择。例如,而不是像
handleClick() {
this.state.libraries.google = true
this.setState({ libraries: this.state.libraries })
}
你可以写
handleClick() {
this.setState({
libraries: {
...this.state.libraries,
google: true
}
})
}
这样我们就创建了一个新对象,这样 connect()
就不会忽略更改后的引用。 (我在此片段中使用 object spread syntax。)
禁用性能优化
一个更糟糕的选择是完全禁用 connect()
所做的性能优化。然后,即使您在父级中改变它们,您的道具也会更新,但您的应用程序会变慢。为此,替换
export default connect(mapStateToProps)(GoogleButton)
和
export default connect(mapStateToProps, null, null, { pure: false })(GoogleButton)
除非绝对必要,否则不要这样做。
我解决了。我不是 100% 确定这是准确的,但我会解释。如果我有什么不对的地方,请指正。
我一直在想 Dan 在他的回答中所说的 shallow equality check。问题就在那里。
我从父级传递一个对象,该对象的嵌套元素发生了变化。对象保持不变。因此,通过 connect 带来的浅层相等性检查,组件将永远不会更新。
我的解决方案是在传递道具时让父级使用 Object.assign({}, dataObject)
,因此我制作了另一个不同的对象。现在浅层相等检查可以比较它并确定 props 已经改变并且在更新组件之前。
我有同样的问题,我使用 object.assign 创建新状态,但我使用 combineReducer 并导致多级状态,在我的情况下,我将整个状态作为道具传递给组件,所以 shallow equality check
可以没有检测到我的状态变化,所以 componentDidUpdate 没有调用,重要的是在使用 combine reducer 时在它改变的级别传递状态
就我而言,我是这样传递的
const MapStateToProps=(state)=>{
return {
reportConfig:state.ReportReducer
}
};
我的状态树是这样的
{
ReportReducer: {
reportConfig: {
reportDateFilter: 'this week',
reportType: null,
reportShopId: null,
updateShop: true
}
}
}
在我的减速器中 return 它像这样 ReportReducer
export default combineReducers({reportConfig});
我的root reducer是这样的
const rootReducer =combineReducers({ReportReducer});
const store = createStore(rootReducer ,{},enhancer);
您可以使用的另一个选项是在子组件上制作继承道具 this.props.dataObject
的深层副本,这是为了 componentDidUpdate
到 'catch' 更新的道具,您可以使用:
dataObject={JSON.parse(JSON.stringify(valueToPass))}
在从父组件传递 prop 的地方使用它,这对我有类似的问题(当你在 prop 中没有任何功能时这适用)。
我在使用外部库中的组件时遇到了完全相同的问题。
所以我没有修改继承的 属性.
的选项
我只需要一部分继承的 属性 对象(为简单起见,将使用 dataObject
)。通过将它添加到 mapStateToProps
函数来解决它:
function mapStateToProps(state, ownProps) {
return { libraries: state.libraries, neededValue: ownProps.dataObject.value }
}
浅比较足以注意到值的变化。所以在render()
函数中使用this.props.neededValue
isothis.props.dataObject.value
我想让我的组件知道是否已经加载了一些库。要知道从任何上下文我都将它连接到我商店的 "library" reducer 到我的组件。
我还从调用组件的父级向它传递一个配置对象 this.props.dataObject
。像这样:
class GoogleButton extends Component {
render() {
if (this.props.libraries.google) {
return <a id='sharePost' className='google_icon'></a>
} else {
return null
}
}
componentDidUpdate() {
gapi.interactivepost.render('sharePost', this.props.dataObject)
}
}
function mapStateToProps(state) {
return { libraries: state.libraries }
}
export default connect(mapStateToProps)(GoogleButton)
处理库状态的reducer是这样的:
let newState = {...state}
newState[action.libraryName] = action.state
return newState
当我更改库状态时 componentDidUpdate
有效。问题是当我更改父 this.props.dataObject
继承的道具时。在那种情况下,componentDidUpdate 不会触发。如果我从组件中删除 connect
它会按预期工作。我在这里遗漏了什么?
很可能你的一些道具在组件外发生了变化。
例如,您可能会像这样渲染您的组件:
class Parent extends Component {
constructor() {
super()
this.state = { libraries: {} }
}
handleClick() {
// MUTATION!
this.state.libraries.google = true
// Normally this forces to update component anyway,
// but React Redux will assume you never mutate
// for performance reasons.
this.setState({ libraries: this.state.libraries })
}
render() {
return (
<div onClick={() => this.handleClick()}>
<GoogleButton libraries={this.state.libraries} />
</div>
)
}
}
因为 Redux 应用程序处理不可变数据,connect()
使用 shallow equality check 作为其 props 以避免不必要的重新渲染。但是,如果您在应用中使用突变,这将不起作用。
你有两个选择:
不要改变任何东西
这是最好的选择。例如,而不是像
handleClick() {
this.state.libraries.google = true
this.setState({ libraries: this.state.libraries })
}
你可以写
handleClick() {
this.setState({
libraries: {
...this.state.libraries,
google: true
}
})
}
这样我们就创建了一个新对象,这样 connect()
就不会忽略更改后的引用。 (我在此片段中使用 object spread syntax。)
禁用性能优化
一个更糟糕的选择是完全禁用 connect()
所做的性能优化。然后,即使您在父级中改变它们,您的道具也会更新,但您的应用程序会变慢。为此,替换
export default connect(mapStateToProps)(GoogleButton)
和
export default connect(mapStateToProps, null, null, { pure: false })(GoogleButton)
除非绝对必要,否则不要这样做。
我解决了。我不是 100% 确定这是准确的,但我会解释。如果我有什么不对的地方,请指正。
我一直在想 Dan 在他的回答中所说的 shallow equality check。问题就在那里。 我从父级传递一个对象,该对象的嵌套元素发生了变化。对象保持不变。因此,通过 connect 带来的浅层相等性检查,组件将永远不会更新。
我的解决方案是在传递道具时让父级使用 Object.assign({}, dataObject)
,因此我制作了另一个不同的对象。现在浅层相等检查可以比较它并确定 props 已经改变并且在更新组件之前。
我有同样的问题,我使用 object.assign 创建新状态,但我使用 combineReducer 并导致多级状态,在我的情况下,我将整个状态作为道具传递给组件,所以 shallow equality check
可以没有检测到我的状态变化,所以 componentDidUpdate 没有调用,重要的是在使用 combine reducer 时在它改变的级别传递状态
就我而言,我是这样传递的
const MapStateToProps=(state)=>{
return {
reportConfig:state.ReportReducer
}
};
我的状态树是这样的
{
ReportReducer: {
reportConfig: {
reportDateFilter: 'this week',
reportType: null,
reportShopId: null,
updateShop: true
}
}
}
在我的减速器中 return 它像这样 ReportReducer
export default combineReducers({reportConfig});
我的root reducer是这样的
const rootReducer =combineReducers({ReportReducer});
const store = createStore(rootReducer ,{},enhancer);
您可以使用的另一个选项是在子组件上制作继承道具 this.props.dataObject
的深层副本,这是为了 componentDidUpdate
到 'catch' 更新的道具,您可以使用:
dataObject={JSON.parse(JSON.stringify(valueToPass))}
在从父组件传递 prop 的地方使用它,这对我有类似的问题(当你在 prop 中没有任何功能时这适用)。
我在使用外部库中的组件时遇到了完全相同的问题。 所以我没有修改继承的 属性.
的选项我只需要一部分继承的 属性 对象(为简单起见,将使用 dataObject
)。通过将它添加到 mapStateToProps
函数来解决它:
function mapStateToProps(state, ownProps) {
return { libraries: state.libraries, neededValue: ownProps.dataObject.value }
}
浅比较足以注意到值的变化。所以在render()
函数中使用this.props.neededValue
isothis.props.dataObject.value