我在看Pluralsight关于React的课程,老师说道具不应该被改变。我现在正在读一篇关于道具vs.国家的文章(uberVU/react-guide),它说

道具和状态更改都会触发呈现更新。

文章后面说:

Props(属性的缩写)是组件的配置,如果可以的话,是它的选项。它们是从上面接收的,是不可变的。

所以道具可以改变,但它们应该是不可变的? 什么时候应该使用道具,什么时候应该使用状态? 如果你有一个React组件需要的数据,它应该通过道具或设置在React组件通过getInitialState?


当前回答

State:具有内部值,这意味着只在该类组件中有效,因此不能将其传递给另一个组件。

道具:另一方面,你可以将道具从父对象传递给子对象或从子对象传递给父对象。

其他回答

大多数时候,你的子组件是无状态的,这意味着它们代表了它的父组件给它的数据/信息。

另一方面,状态处理的是处理组件本身,状态可以在组件内部通过setState和useState钩子改变。

例如

class Parent extends Component{
  constructor(props){
    super(props);
    this.state = {
      fruit: 'apple'
    }
    this.handleChange = this.handleChange.bind(this)
  }

  handleChange(){
    this.setState({fruit: 'mango'})
  }
  render(){
    return (
      <div>
      <Child  fruit={this.state.fruit} />
      <button onClick={this.handleChange}>Change state</button>
      </div>
    )
  }
}

当点击按钮时,父类将其状态从apple更改为mango,并将其状态作为道具传递给子组件。现在,没有状态的子组件根据父组件的状态显示不同的标题。

class Child extends Component{

  render(){
    return(
      <h1>I have received a prop {this.props.fruit}</h1>
    )
  }
}

所以在根级别上,道具是父进程与子进程的通信,而状态是描述父进程的情况等。

我最喜欢的道具vs状态总结在这里:反应指南向这些家伙致敬。以下是该页面的编辑版本:


道具vs状态

如果一个组件需要在某个时间点改变它的一个属性,这个属性应该是它状态的一部分,否则它应该只是该组件的一个道具。


道具

道具(属性的简称)是组件的配置。它们是从上面接收的,对于接收它们的组件来说是不可变的。组件不能更改它的道具,但它负责将其子组件的道具组合在一起。道具不一定只是数据——回调函数可以作为道具传递进来。

状态

状态是一个数据结构,在组件挂载时以默认值开始。它可能会随着时间发生变化,主要是由于用户事件。

组件在内部管理自己的状态。除了设置一个初始状态外,它没有权利修改它的子进程的状态。您可以将状态概念化为该组件的私有状态。

改变道具和状态

                                                   props   state
    Can get initial value from parent Component?    Yes     Yes
    Can be changed by parent Component?             Yes     No
    Can set default values inside Component?*       Yes     Yes
    Can change inside Component?                    No      Yes
    Can set initial value for child Components?     Yes     Yes
    Can change in child Components?                 Yes     No

注意,从父组件接收到的props和state初始值都会覆盖组件内部定义的默认值。

这个组件应该有状态吗?

状态是可选的。由于状态增加了复杂性并降低了可预测性,因此最好使用没有状态的组件。即使在交互式应用程序中你显然不能没有状态,你也应该避免有太多的状态组件。

组件类型

无状态组件只有道具,没有状态。除了render()函数之外,没有什么事情要做。他们的逻辑围绕着他们得到的道具展开。这使得它们非常容易遵循和测试。

有状态组件包括道具和状态。当您的组件必须保持某种状态时使用这些。这是客户端-服务器通信(XHR、web套接字等)、处理数据和响应用户事件的好地方。这些类型的逻辑应该封装在适量的有状态组件中,而所有的可视化和格式化逻辑应该向下移动到许多无状态组件中。

来源

关于“props”和“state”的问题-谷歌组 React中的思考:确定你的状态应该在哪里

这是我在使用react时学到的。

组件使用Props从外部环境中获取数据,例如另一个组件(纯组件、函数组件或类)或一般类或javascript/typescript代码 用于管理组件内部环境的状态意味着组件内部的数据变化

State是react中的一个特殊变量,用于在组件更新时重新渲染组件

状态对于组件本身是私有的。也就是说,它不能在组件外部被访问或修改。setState/用于更新状态的钩子。每当状态更新时,组件重新呈现

状态是可变的

道具是组件的输入,并使用道具数据呈现内容

道具是不可变的(Object。冻结= true)

Basically, props and state are two ways the component can know what and how to render. Which part of the application state belongs to state and which to some top-level store, is more related to your app design, than to how React works. The simplest way to decide, IMO, is to think, whether this particular piece of data is useful for application as a whole, or it's some local information. Also, it's important to not duplicate state, so if some piece of data can be calculated from props - it should calculated from props.

For example, let's say you have some dropdown control (which wraps standart HTML select for custom styling), which can a) select some value from list, and b) be opened or closed (i.e., the options list displayed or hidden). Now, let's say your app displays a list of items of some sort and your dropdown controls filter for list entries. Then, it would be best to pass active filter value as a prop, and keep opened/closed state local. Also, to make it functional, you would pass an onChange handler from parent component, which would be called inside dropdown element and send updated information (new selected filter) to the store immediately. On the other hand, opened/closed state can be kept inside dropdown component, because the rest of the application doesn't really care if the control is opened, until user actually changes it value.

下面的代码是不完全工作,它需要css和处理下拉单击/模糊/改变事件,但我想保持示例最小。希望这有助于理解其中的区别。

const _store = {
    items: [
    { id: 1, label: 'One' },
    { id: 2, label: 'Two' },
    { id: 3, label: 'Three', new: true },
    { id: 4, label: 'Four', new: true },
    { id: 5, label: 'Five', important: true },
    { id: 6, label: 'Six' },
    { id: 7, label: 'Seven', important: true },
    ],
  activeFilter: 'important',
  possibleFilters: [
    { key: 'all', label: 'All' },
    { key: 'new', label: 'New' },
    { key: 'important', label: 'Important' }
  ]
}

function getFilteredItems(items, filter) {
    switch (filter) {
    case 'all':
        return items;

    case 'new':
        return items.filter(function(item) { return Boolean(item.new); });

    case 'important':
        return items.filter(function(item) { return Boolean(item.important); });

    default:
        return items;
  }
}

const App = React.createClass({
  render: function() {
    return (
            <div>
            My list:

            <ItemList   items={this.props.listItems} />
          <div>
            <Dropdown 
              onFilterChange={function(e) {
                _store.activeFilter = e.currentTarget.value;
                console.log(_store); // in real life, some action would be dispatched here
              }}
              filterOptions={this.props.filterOptions}
              value={this.props.activeFilter}
              />
          </div>
        </div>
      );
  }
});

const ItemList = React.createClass({
  render: function() {
    return (
      <div>
        {this.props.items.map(function(item) {
          return <div key={item.id}>{item.id}: {item.label}</div>;
        })}
      </div>
    );
  }
});

const Dropdown = React.createClass({
    getInitialState: function() {
    return {
        isOpen: false
    };
  },

  render: function() {
    return (
        <div>
            <select 
            className="hidden-select" 
          onChange={this.props.onFilterChange}
          value={this.props.value}>
            {this.props.filterOptions.map(function(option) {
            return <option value={option.key} key={option.key}>{option.label}</option>
          })}
        </select>

        <div className={'custom-select' + (this.state.isOpen ? ' open' : '')} onClick={this.onClick}>
            <div className="selected-value">{this.props.activeFilter}</div>
          {this.props.filterOptions.map(function(option) {
            return <div data-value={option.key} key={option.key}>{option.label}</div>
          })}
        </div>
      </div>
    );
  },

  onClick: function(e) {
    this.setState({
        isOpen: !this.state.isOpen
    });
  }
});

ReactDOM.render(
  <App 
    listItems={getFilteredItems(_store.items, _store.activeFilter)} 
    filterOptions={_store.possibleFilters}
    activeFilter={_store.activeFilter}
    />,
  document.getElementById('root')
);