【问题标题】:How to set state from props that is passed to the component in react?如何从传递给组件的道具中设置状态反应?
【发布时间】:2026-02-16 05:35:01
【问题描述】:

我有这个简单的组件,initialPlayers props 被传递给App 组件。

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

控制台出现此错误,无法将值作为{this.state.players} 传递给Header 组件。有什么想法吗?。

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)

【问题讨论】:

标签: javascript reactjs


【解决方案1】:

您想使用componentWillMount,因为它在组件的第一次渲染之前运行——将其与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>

【讨论】:

    【解决方案2】:

    首先你需要初始化你的state,否则你会得到错误更新它的值,然后你必须使用setState方法来改变它(这是在反应中更新state的推荐方法)

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

    【讨论】:

    • componentDidMount 使用错误,ESlint 本身会为此抛出错误。相反,应该使用 componentWillMount。
    • 是的,你是对的,在这种情况下,最好的选择是 componentWillMount
    【解决方案3】:

    将设置播放器行移动到您的构造函数()中:

    constructor(props) {
      super(props);
      this.state = {
        players: this.props.initialPlayers
      };
    }
    

    【讨论】: