Reputation: 245
I have this simple component, initialPlayers
props is passed to App
component.
import React from 'react';
import ReactDOM from 'react-dom';
var PLAYERS = [
{
name: "xyz",
score: 123
}
];
// App component
class App extends React.Component {
constructor() {
super();
}
componentDidMount() {
this.state = {
players: this.props.initialPlayers
}
}
render() {
return(
<div>
<Header players={this.state.players} />
</div>
);
}
}
// Render component
ReactDOM.render(<App initialPlayers={ PLAYERS }/>,
document.getElementById('root'));
Have this error in console, and not able to pass value to Header
component as {this.state.players}
. Any idea?.
Uncaught TypeError: Cannot read property 'players' of null
at App.render (bundle.js:14379)
at bundle.js:20173
at measureLifeCyclePerf (bundle.js:19452)
at ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (bundle.js:20172)
at ReactCompositeComponentWrapper._renderValidatedComponent (bundle.js:20199)
at ReactCompositeComponentWrapper.performInitialMount (bundle.js:19739)
at ReactCompositeComponentWrapper.mountComponent (bundle.js:19635)
at Object.mountComponent (bundle.js:4667)
at ReactCompositeComponentWrapper.performInitialMount (bundle.js:19748)
at ReactCompositeComponentWrapper.mountComponent (bundle.js:19635)
Upvotes: 5
Views: 28338
Reputation: 2242
Move the setting players line into your constructor():
constructor(props) {
super(props);
this.state = {
players: this.props.initialPlayers
};
}
Upvotes: 8
Reputation: 4332
First you need to initialize your state
otherwise you'll get error updating it's value, then you have to use setState
method to change it (this is the recommended way to update state
in react)
import React from 'react';
import ReactDOM from 'react-dom';
var PLAYERS = [
{
name: 'xyz',
score: 123
}
];
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
players: []
};
}
componentDidMount() {
this.setState({
players: this.props.initialPlayers
});
}
render() {
return(
<div>
<ul>
{this.renderPlayers()}
</ul>
</div>
);
}
renderPlayers() {
return this.state.players.map((player, index) =>
<li key={index}>{`name: ${player.name} - score: ${player.score}`}</li>
);
}
}
ReactDOM.render(
<App initialPlayers={ PLAYERS }/>,
document.getElementById('root')
);
Upvotes: 0
Reputation: 135416
You want to use componentWillMount
because it runs before the component's first render – compare that to the description of componentDidMount
var PLAYERS = [
{ name: "xyz", score: 123 },
{ name: 'abc', score: 111 },
{ name: 'def', score: 222 }
];
const Header = ({players}) =>
<ul>{players.map(({name,score}) =>
<li><span>{name}</span><span>{score}</span></li>)}</ul>
// App component
class App extends React.Component {
// get rid of constructor if you're not doing anything with it
// constructor() { ... }
// use componentWillMount instead of componentDidMount
componentWillMount() {
this.setState({
players: this.props.initialPlayers
})
}
// don't wrap everything in a div if it's not necessary
render() {
return <Header players={this.state.players} />
}
}
// Render component
ReactDOM.render(<App initialPlayers={ PLAYERS }/>,
document.getElementById('root'));
span {
display: inline-block;
font-weight: bold;
margin-right: 1em;
}
span ~ span {
font-weight: normal;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Upvotes: 1