如果连接到未更改的商店,则 React componentDidUpdate 方法不会在继承的props更改时触发

IT技术 javascript reactjs redux react-redux
2021-05-07 14:11:50

我想让我的组件知道是否已经加载了某个库。要知道从任何上下文我将它连接到我的商店的“库”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问题是当我更改父继承的props时this.props.dataObject在这种情况下,componentDidUpdate 不会触发。如果我connect从组件中删除它,它会按预期工作。我在这里遗漏了什么?

4个回答

很可能你的一些props在组件外发生了变异。
例如,您可能会像这样渲染您的组件:

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 应用程序处理不可变数据,所以对其 propsconnect()使用浅层相等性检查以避免不必要的重新渲染。但是,如果您在应用程序中使用突变,这将不起作用。

您有两个选择:

不要改变任何东西

这是最好的选择。例如,而不是像

  handleClick() {
    this.state.libraries.google = true
    this.setState({ libraries: this.state.libraries })
  }

你可以写

  handleClick() {
    this.setState({
      libraries: {
        ...this.state.libraries,
        google: true
      }
    })
  }

这样我们就创建了一个新对象,因此connect()不会忽略更改的引用。(我在这个片段中使用了对象传播语法。)

禁用性能优化

一个更糟糕的选择是完全禁用由connect(). 然后,即使您在父级中对它们进行变异,您的props也会更新,但您的应用程序会变慢。为此,请更换

export default connect(mapStateToProps)(GoogleButton)

export default connect(mapStateToProps, null, null, { pure: false })(GoogleButton)

除非绝对必要,否则不要这样做。

我解决了。我不是 100% 确定这是准确的,但我会解释。如果我有什么不对的地方,请纠正我。

我一直在想丹在他的回答中所说肤浅的平等检查问题就在那里。我从父对象传递了一个对象,并且该对象的嵌套元素发生了变化。对象保持不变。因此,使用connect带来的浅层相等性检查,组件将永远不会更新。

Object.assign({}, dataObject)当我传递props时,我的解决方案是在父级使用中,因此我制作了另一个不同的对象。现在,浅层相等性检查可以比较它并在更新组件之前确定 props 已经改变了。

我有同样的问题,我使用 object.assign 创建新状态,但我使用 combineReducer 并导致多级状态,在我的情况下,我将整个状态作为props传递给组件,因此shallow equality check无法检测到我的状态更改,因此 componentDidUpdate 没有调用,它是在我的情况下使用组合减速器时,在级别中传递状态很重要,我像这样传递它

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);

您可以使用的另一个选项是this.props.dataObject在子组件上制作继承props的深层副本,这是为了componentDidUpdate“捕获”更新的props,您可以使用:

dataObject={JSON.parse(JSON.stringify(valueToPass))}

在从父组件传递props的地方使用它,这对我有类似的问题(这适用于props内没有任何功能的情况)。