2017-10-16 3 views
0

Je vais avoir un problème avec un composant qui a des propTypes nécessaires.état de mise à jour avant de rendre: PropType marqué comme nécessaire, mais non définie

L'erreur que je reçois est:

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) 

Et mon code ...

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; 

Je modifier l'état avant que la méthode render a appelé donc je suis confus comment les accessoires pour UserHeader sont vérifiés avant que le setTimeout ne soit terminé?

Comment suis-je capable de tenir à distance sur le rendu/propChecking jusqu'à ce que setTimeout a terminé?

Je pensais que sur la configuration par défaut un état initial lors de la création du magasin, comme ceci:

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

... mais cela semble un peu hackish.

+0

Peut être que vous voulez à la caisse ce https://stackoverflow.com/questions/43312223/asynchronous-call-in-componentwillmount-finishes-after-render-method – praveenweb

Répondre

3

Vous ne modifie pas l'état avant render, parce que vous utilisez un setTimeout. Render n'attend pas votre setTimeout et s'appelle directement après componentWillMount.

Vous devez définir des valeurs par défaut dans le réducteur de Redux. Vous pouvez simplement mettre dans le réducteur

user: null, 
.... 

et lors du rendu vérifier si vous avez l'utilisateur ou non

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

Et mapStateToProps copier tout l'ensemble user obj:

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

Il existe également d'autres façons de le faire. Vous pouvez simplement définir les valeurs par défaut pour firstName et level dans le réducteur comme vous l'avez suggéré, ou vous pouvez toujours rendre le UserHeader avec un accessoire user et décider de ce qu'il faut afficher si vous n'avez pas les valeurs de sous-valeurs définies.

0

Ajouter un composant chargeur ou null comme ci-dessous. Et l'utilisation de l'état local.

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