Redux状态更新后没有调用ComponentDidMount?

Posted

技术标签:

【中文标题】Redux状态更新后没有调用ComponentDidMount?【英文标题】:ComponentDidMount not getting called after redux state update? 【发布时间】:2018-07-21 21:13:29 【问题描述】:

我想我在这里遗漏了一个关于 React 和 Redux 的概念。我正在尝试处理存储在 redux 中的对象,但遇到了麻烦。

还原: 我有一个动作 fetchItems,它从数据库中获取所有项目。此操作成功。

反应: 我有一个容器 UserProfile,它在 componentDidMount 中调用 fetchItems。

class UserProfile extends Component 

  componentWillMount() 
    console.log('------------ USER PROFILE -------------------');
  

  componentDidMount() 
    console.log('[ComponentDidMount]: Items: ', this.props.items);
    this.props.fetchItems();
  

  render() 
    let profile = null;
    console.log('[Render]: Items: ', this.props.items);

    return <Auxillary>profile</Auxillary>;
  


const mapStateToProps = state => 
  return 
    items: state.items.items
  ;
;

const mapDispatchToProps = dispatch => 
  return 
    fetchItems: () => dispatch(actions.fetchItems())
  ;
;

export default connect(mapStateToProps, mapDispatchToProps)(UserProfile);

我看到的问题是 this.props.items 始终为空(即使 fetchItems 成功)。我可以检测到项目存储在 redux 存储中的唯一方法是使用 componentWillRecieveProps(nextProps)。在这里,我成功看到了 nextProps 中的项目。我觉得使用 componentWillReceiveProps 可能太“杂乱”了。我想我要问的是,在 react 中处理 redux 状态更新的标准方法是什么?

阿塞尔

【问题讨论】:

一个组件的生命周期如下:constructor() componentWillMount() render() componentDidMount() 所以在componentDidMount()中执行的任何东西都会在render()之后得到执行者 【参考方案1】:

循环将是:

constructor() componentWillMount()(顺便说一句,很快就会被弃用:https://medium.com/@baphemot/whats-new-in-react-16-3-d2c9b7b6193b) render() => 首次渲染(this.props.items,来自 mapStateToProps 将未定义) componentDidMount() => 启动 fetchItems() => 改变 redux 状态 => 改变 this.props.items => 启动第二个 render() this.props.items 将被设置。

所以:

你应该有两个console.log('[Render]: Items: ', this.props.items); 当 this.props.items 为 null 时,您应该处理“加载”状态

如果第二个console.log 仍然为空,请尝试在reducer 中添加日志,在mapStateToProps 中,...也许不是state.items.items ...

【讨论】:

【参考方案2】:

在反应中,我们有一个叫做状态的东西。如果组件的状态发生更改,则组件将重新渲染。话虽如此,我们可以在componentWillRecieveProps 中使用this.setState() 来更新状态,这反过来又会重新渲染组件。所以你的代码看起来像这样,这是在 react 中处理 Redux 级别状态更改的标准方法。

class UserProfile extends Component 

    constructor(props) 
        super(props);
        this.state = 
            items: props.items
        
    
    componentWillMount() 
      console.log('------------ USER PROFILE -------------------');
    

    componentWillRecieveProps( items ) 
        this.setState( items );
    

    componentDidMount() 
      console.log('[ComponentDidMount]: Items: ', this.state.items);
      this.props.fetchItems();
    

    render() 
      let profile = null;
      console.log('[Render]: Items: ', this.state.items);

      return <Auxillary>profile</Auxillary>;
    
  

  const mapStateToProps = state => 
    return 
      items: state.items.items
    ;
  ;

  const mapDispatchToProps = dispatch => 
    return 
      fetchItems: () => dispatch(actions.fetchItems())
    ;
  ;

  export default connect(mapStateToProps, mapDispatchToProps)(UserProfile);

P.S 仅在 componentWillMount 内进行 API 调用也无济于事,因为 API 调用是异步的,并且可能需要一些时间来解决,直到那时 react 将完成渲染组件。所以你仍然必须使用componentWillRecieveProps

【讨论】:

componentWillRecieveProps 是错字。 componentWillReceiveProps 是正确的。【参考方案3】:

标准做法是在您的构造函数或 componentWillMount() 中调用 this.props.fetchItems()。

componentDidMount 在渲染后被调用,这就是你的项目不渲染的原因 - 它们在初始渲染之后才存在。

【讨论】:

【参考方案4】:

有一些方法可以解决这个问题。 第一次调用 render() 时,它订阅了通过 redux connect 方法在 redux store 中初始化的初始 props/state。在您的情况下,itemsnull。 总是用一些有意义的数据初始化你的 redux 存储。

在您的情况下,如果 items 将是数组,您可以使用空数组进行初始化。 当您发送操作时,您的商店将得到更新,并且订阅 items 的组件将被重新呈现,这样您就不必在 componentWillReceiveProps 中使用 setState 你可以避免使用它。

您需要在渲染中处理某些情况,例如如果数组为空且数据仍在加载,则显示某种加载器,一旦获取数据然后显示它。

【讨论】:

以上是关于Redux状态更新后没有调用ComponentDidMount?的主要内容,如果未能解决你的问题,请参考以下文章

axios.post 调用后 Redux 更新状态太慢

Redux 存储在调度后不更新(异步数据加载)

如何在 Redux 中更新状态后触发回调?

从 redux 更改状态后如何以及何时调用反应组件方法

Redux 状态未在 Redux DevTool 中更新

更新:没有调用 Redux reducer 来更改 CSS 类