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

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

文章后面说:

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

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


当前回答

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

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

其他回答

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

Props: Props只是组件的属性,react组件只是一个javascript函数。

  class Welcome extends React.Component {
    render() {
      return <h1>Hello {this.props.name}</h1>;
    }
  }

Const元素=;

这里<Welcome name="Sara" />传递一个对象{name: 'Sara'}作为Welcome组件的道具。为了将数据从一个父组件传递给子组件,我们使用props。 道具是不可变的。在组件的生命周期中,道具不应该改变(认为它们是不可变的)。

状态:状态只能在组件中访问。为了跟踪组件中的数据,我们使用状态。我们可以通过setState来改变状态。如果我们需要将state传递给child,我们必须将它作为props传递。

class Button extends React.Component {
  constructor() {
    super();
    this.state = {
      count: 0,
    };
  }

  updateCount() {
    this.setState((prevState, props) => {
      return { count: prevState.count + 1 }
    });
  }

  render() {
    return (<button
              onClick={() => this.updateCount()}
            >
              Clicked {this.state.count} times
            </button>);
  }
}

简单地说:

状态由组件自己管理。它是可重用的、组件私有的、可修改的。 道具从父母传递给孩子。它是一个单向流,子组件是只读的。父组件的状态可以作为道具传递给子组件。

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

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

状态是可变的

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

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

在react中,我们通常使用模块来分离组件。有时分离的组件需要在它们内部共享数据。如果父组件有一些数据应该在子组件上共享,那么道具是解决方案。我们可以使用从父母到孩子的道具共享数据。Props是不可变的,这意味着您不能更改数据。

另一方面,状态用于跟踪数据中的任何变化。您可以将状态视为数据的存储和可以更新该数据的函数。状态是可变的。您可以在同一组件中使用setState函数更改状态