渲染前更新状态:propType标记为必需但未定义

时间:2017-10-16 13:22:46

标签: javascript reactjs redux react-redux

我遇到了一个包含某些必需propTypes的组件的问题。

我得到的错误是:

Warning: Failed prop type: The prop `firstname` is marked as required in `UserHeader`, but its value is `undefined`.
in UserHeader (at App.js:32)
in App (created by Connect(App))
in Connect(App) (at index.js:17)
in Provider (at index.js:16)

我的代码......

import React, { Component } from 'react';
import { connect } from 'react-redux';

import ErrorBoundary from './containers/ErrorBoundary'
import UserHeader from './components/UserHeader';
import Header from './components/Header';

class App extends Component {
  constructor(props) {
    super(props);
  }

  componentWillMount() {
    // Pretend this is an API call that takes a second
    setTimeout(() => {
      const data = {
        user: {
          firstname: 'bughunter',
          level: 55
        }
      };
      this.props.didMountHandler(data)
    }, 1000);
  }

  render() {
    return (
      <ErrorBoundary>
        <Header />
        <UserHeader 
          firstname={this.props.firstname}
          level={this.props.level}
        />
      </ErrorBoundary>
    );
  }
}

const mapStateToProps = (state, ownProps) => {
  return {
    firstname: state.user.firstname,
    level: state.user.level
  }
};

const mapDispatchToProps = dispatch => ({
  didMountHandler: data => {
    dispatch({
      type: 'USER_DATA_RECEIVED',
      data
    });
  }
})

const AppContainer = connect(  
  mapStateToProps,
  mapDispatchToProps
)(App);

export default AppContainer;

我在render方法调用之前修改了状态,所以我很困惑UserHeader完成之前检查setTimeout的道具是什么?

setTimeout完成之前,我怎样才能推迟渲染/ propChecking?

我考虑过在创建商店时设置一些初始默认状态,如下所示:

{
    user: {
        firstname: '',
        level: 0
    }
}

......但这看起来有些过时。

2 个答案:

答案 0 :(得分:3)

您没有修改render之前的状态,因为您正在使用setTimeout。渲染不等待您的setTimeout,并在调用componentWillMount后直接调用。

您必须在redux reducer中设置一些默认值。你可以在减速器中设置

user: null,
....

并在渲染时检查您是否拥有该用户

render() {
    const { user } = this.props;
    { user && <UserHeader firstname={user.firstname} level={user.level} /> }

mapStateToProps中只需复制整个user obj:

const mapStateToProps = (state, ownProps) => {
  return {
    user: state.user
  }
};

还有其他方法可以做到这一点。您可以按照建议在reducer中设置firstNamelevel的默认值,也可以始终使用UserHeader道具渲染user并确定如果您没有设置值subValues,则显示。

答案 1 :(得分:0)

添加一个加载程序组件或null,如下所示。并使用当地的州。

state = { initialized: false }

componentWillMount() {
// Pretend this is an API call that takes a second
setTimeout(() => {
  const data = {
    user: {
      firstname: 'bughunter',
      level: 55
    }
  };
  this.props.didMountHandler(data)
  this.setState({ initialized: true });
}, 1000);
}

render(){
   if(!this.state.initialized){
       return null;
   }

   return (
     <ErrorBoundary>
        <Header />
        <UserHeader 
           firstname={this.props.firstname}
           level={this.props.level}
        />
     </ErrorBoundary>
   );
}