我希望我的组件知道是否已加载某个库。要知道从任何上下文我连接到"库"我商店的减速机到我的组件。
我还从已调用组件的父级传递配置对象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
,它会按预期工作。我在这里错过了什么?
答案 0 :(得分:8)
很可能你的一些道具在组件外突变 例如,您可能正在渲染组件:
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作为其道具以避免不必要的重新渲染。但是,如果您在应用中使用变异,这将无效。
您有两种选择:
这是最好的选择。例如,而不是像
那样的东西 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)
除非绝对必要,否则不要这样做。
答案 1 :(得分:3)
我解决了。我不是100%确定这是准确的,但我会解释。如果我的错误,请纠正我。
我一直在想丹在他的回答中所说的shallow equality check。问题出在那里。 我从父对象传递了一个对象,该对象的嵌套元素是那些已经改变的对象。对象保持不变。因此,使用浅层相等检查connect使组件永远不会更新。
当我传递道具时,我的解决方案在父使用Object.assign({}, dataObject)
中,因此我创建了另一个不同的对象。现在浅层等式检查可以比较它并确定道具已经改变,并在更新组件之前进行更改。
答案 2 :(得分:0)
我遇到了同样的问题,我使用object.assign创建了新状态,但是我使用CombineReducer并导致了多级状态,就我而言,我将整个状态作为prop传递给了组件,因此shallow equality check
无法检测到我的状态进行更改,以便componentDidUpdate没有调用,在使用Combine Reducer时在更改级别传递状态非常重要
就我而言,我像这样通过它
const MapStateToProps=(state)=>{
return {
reportConfig:state.ReportReducer
}
};
我的状态树就是这样
{
ReportReducer: {
reportConfig: {
reportDateFilter: 'this week',
reportType: null,
reportShopId: null,
updateShop: true
}
}
}
,然后在我的减速器中,将其返回为ReportReducer
export default combineReducers({reportConfig});
我的减根剂是这样的
const rootReducer =combineReducers({ReportReducer});
const store = createStore(rootReducer ,{},enhancer);
答案 3 :(得分:0)
您可以使用的另一种选择是在子组件上制作继承道具this.props.dataObject
的深层副本,这是为了使componentDidUpdate
能够“捕获”更新的道具,您可以使用:
dataObject={JSON.parse(JSON.stringify(valueToPass))}
在您从父组件传递prop的地方使用它,这对我也有类似的问题(当您在prop内部没有任何功能时适用)。
答案 4 :(得分:0)
我在外部库中使用的组件也遇到了同样的问题。 所以我没有选择修改继承的属性。
我只需要继承属性对象的一部分(为简单起见,将使用dataObject
)。通过将其添加到mapStateToProps
函数中来解决该问题:
function mapStateToProps(state, ownProps) {
return { libraries: state.libraries, neededValue: ownProps.dataObject.value }
}
通过一个浅比较就足以注意到值的变化。因此,请在this.props.neededValue
函数中使用this.props.dataObject.value
iso render()
。