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

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

文章后面说:

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

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


当前回答

props (properties的缩写)和state都是简单的JavaScript 对象。而两者都持有影响输出的信息 渲染,他们在一个重要的方面是不同的:道具被传递到 组件(类似于函数参数),而状态为 在组件中管理(类似于在组件中声明的变量 功能)。

所以简单的状态仅限于你当前的组件,但道具可以传递给任何组件你希望…你可以将当前组件的状态作为道具传递给其他组件……

同样在React中,我们有无状态的组件,它们只有道具,没有内部状态……

下面的例子展示了它们如何在你的应用程序中工作:

父组件(全状态组件):

class SuperClock extends React.Component {

  constructor(props) {
    super(props);
    this.state = {name: "Alireza", date: new Date().toLocaleTimeString()};
  }

  render() {
    return (
      <div>
        <Clock name={this.state.name} date={this.state.date} />
      </div>
    );
  }
}

子组件(无状态组件):

const Clock = ({name}, {date}) => (
    <div>
      <h1>{`Hi ${name}`}.</h1>
      <h2>{`It is ${date}`}.</h2>
    </div>
);

其他回答

道具和状态是相关的。一个组件的状态通常会成为子组件的道具。道具在父元素的呈现方法中作为React.createElement()的第二个参数传递给子元素,如果您使用的是JSX,则是更熟悉的标记属性。

<MyChild name={this.state.childsName} />

父类的childsName的状态值变成子类的this.props.name。从子进程的角度来看,名称道具是不可变的。如果它需要改变,父进程只需要改变它的内部状态:

this.setState({ childsName: 'New name' });

React会把它传播给你的子程序。一个自然的后续问题是:如果子程序需要更改其名称道具怎么办?这通常是通过子事件和父回调完成的。子进程可能会公开一个名为onNameChanged的事件。然后父进程通过传递回调处理程序来订阅事件。

<MyChild name={this.state.childsName} onNameChanged={this.handleName} />

子进程将通过调用this.props将其请求的新名称作为参数传递给事件回调。onNameChanged('New name'),父进程将在事件处理程序中使用该名称来更新其状态。

handleName: function(newName) {
   this.setState({ childsName: newName });
}

用户在应用程序的某个地方输入了一些数据。

在其中输入数据的组件应该在其状态中拥有该数据,因为它需要在数据输入期间操作和更改它 在应用程序的其他任何地方,数据都应该作为道具传递给所有其他组件

所以,是的,道具是在变化的,但它们是从“源头”改变的,然后简单地从那里向下流动。所以道具在接收它们的组件的上下文中是不可变的。

例如,在一个参考数据屏幕上,用户编辑一个供应商列表将在状态下管理它,然后会有一个操作,导致更新的数据保存在ReferenceDataState中,它可能比AppState低一级,然后这个供应商列表将作为道具传递给所有需要使用它的组件。

道具只是属性的简写。道具是组件之间相互交流的方式。如果你熟悉React,那么你应该知道道具是从父组件向下流动的。

还有一种情况是,你可以有默认的道具,这样即使父组件没有传递道具,道具也会被设置。

这就是为什么人们认为React具有单向数据流。这需要一些理解,我可能会在后面的博客中对此进行讨论,但现在只要记住:数据从父流向子。道具是不可变的(是指不变的)

所以我们很高兴。组件从父组件接收数据。都整理好了,对吧?

嗯,不完全是。当组件从父组件以外的对象接收数据时会发生什么?如果用户直接向组件输入数据呢?

这就是我们有状态的原因。

状态

道具不应该改变,所以状态上升。组件通常没有状态,因此被称为无状态。使用状态的组件称为有状态的。在聚会上随便说说你的小秘密,然后看着人们慢慢地离你而去。

所以使用状态是为了让组件可以在它所做的任何渲染之间跟踪信息。当你setState时,它更新状态对象,然后重新渲染组件。这非常酷,因为这意味着React会处理困难的工作,并且速度非常快。

作为状态的一个小例子,这里是一个搜索栏的片段(如果你想了解更多关于React的知识,值得看看这门课程)

Class SearchBar extends Component {
 constructor(props) {
  super(props);
this.state = { term: '' };
 }
render() {
  return (
   <div className="search-bar">
   <input 
   value={this.state.term}
   onChange={event => this.onInputChange(event.target.value)} />
   </div>
   );
 }
onInputChange(term) {
  this.setState({term});
  this.props.onSearchTermChange(term);
 }
}

总结

道具和状态的作用类似,但使用方式不同。大多数组件可能是无状态的。

道具用于将数据从父组件传递给子组件或由组件本身传递。它们是不可变的,因此不会被改变。

State用于可变数据或将更改的数据。这对于用户输入特别有用。以搜索栏为例。用户将输入数据,这将更新他们所看到的内容。

我们可以改变states的值但我们不能改变props的值,或者我们可以说props是不可变的而states是可变的

主要的区别是状态是组件私有的,只能在组件内部更改,而道具只是静态值和键的子组件,通过父组件传递,不能在子组件内部更改