rccoder / blog

😛 个人博客 🤐 订阅是 watch 是 watch 是 watch 是 watch
582 stars 36 forks source link

React 数据阵营之 State 与 Props #16

Open rccoder opened 7 years ago

rccoder commented 7 years ago

image

在任何应用中管理数据都是必不可少的。通过用户界面来编排数据流是一项具有挑战的工程。现代的 Web 应用会涉及复杂的 UI 交互,比如改变了一个地方的 UI 数据,需要直接或者间接的改变其他地方的 UI 数据。一些双向绑定的框架(比如:Angular.js 等)都是对这种场景比较好的解决方案。

对于一些应用(尤其是数据流比较简单的),这种双向绑定是非常快速和足够的解决方案。但是对于一些更加复杂的应用场景,数据双向绑定已经被证明是不够的,它会妨碍用户界面的设计。实际上,React 并没有解决这样一个复杂应用中比较复杂的数据流问题(虽然后面出现了 Flux 这种解决方案),但是他确实解决了一个组件中数据流的问题。

对于一个有上下文关系的组件, React 解决了数据流问题 —— 即通过更新 UI 来反应数据流的结果;除此之外,React 解决的另外一个问题是命名模式问题 —— 通过比较有创意的虚拟 DOM 解决。

组件数据的类型

在 React 中组件的数据存储在 propsstate 中。

props 是一个组件的输入。他经常被用作渲染组件和初始化状态。当实例化完一个组件,props 应该是不可变的(持久的)。props 被用作在实例化组件的时候,然后组件将再次渲染 DOM,在这个过程中,React 将会对比新 props 和老 props 然后来确定哪些 DOM 的变化是必要的。

下面是一个设置 props 然后用 props 的变化来更新 DOM 的例子:

 "use strict";

var HelloWorld = React.createClass({

  render: function() {
    return (
      <div>
        <span>Counter: {this.props.count}</span>
        <br />
        <input type="text" />
      </div>
    );
  },

});

var
  mainElement = document.querySelector("main"),
  count = 1;

setInterval(function() {

  ReactDOM.render(<HelloWorld count={count++}></HelloWorld>, mainElement); 

http://codepen.io/SitePoint/pen/XKqQqN

state 可以通过组组件发生变化,这种变化经常会和组件的事件处理函数连接起来。通常情况下,state 的这种变化会触发组件的重新渲染。在组件初始化之前,他的 state 必须先进行初始化,其值包含常数、props

与 Angular 这样的框架相比,可以理解为 props 是单向数据绑定,state 是双向数据绑定。当然这并不是一种恰当的比喻: Angular 使用一种有两种方式的数据对象,而 React 是使用两种数据对象,每种对象都有着自己的使用方法。

Props

当我们给一个组件添加 css 样式的 class 时,我们必须用 className,而不是 class。这是因为在 ES 2015 中 class 是一个用来定义对象的保留字。为了去避免这种冲突,在 React 中使用了 className。如果你使用了 class,React 将会在 console 里面输出一段友好的提示,让你使用 className 而不是 class

除了像 className 一样这些 props 的名字之外,props 还有一些其他有意思的地方。比如改变 props 的值就是一种反模式props 应该在组件实例化之前就进行设置,在这之后进行设置是不可的。其中就包括在组件实例化之后(render 之后)。可变值在组件中被认为是状态,一般使用 state 而不是 props

在下面的这个例子中,someComponent 实例化了,在这之后 props 的值发生了变化。

var someComponent = <SomeComponent />; 

someComponent.props.prop1 = “some value”; 
someComponent.props.prop2 = “some value”;

改变 props 的值会让应用程序发生一些错误,并且这种错误是无法跟踪的。于此同时,改变 props 的值不会触发组件的再次渲染,这样就会让数据和界面不是同步的。

所以。props 应该在实例化的时候作为组件的一部分。

var someComponent = <SomeComponent prop1=”some value” prop2=”some value” /> 

这样,props 发生变化的时候就会协调进行 DOM 树的对比,然后进行 UI 的更新。

State

state 表示组件内可变的状态,这个状态一般是由用户去作用而产生的。为了促成这种改变,事件处理程序将会作用在相应的 DOM 元素上,当事件触发之后,值将会从 DOM 上取得,然后去通知组件有一个新的 state。在组件使用 state 之前,state 必须通过 getInitialState 函数进行初始化。通常情况下,getInitilaState 函数通过静态值、props 或者其他数据源进行初始化 state

var Message = React.createClass({ 

  getInitialState: function() { 
    return { message: this.props.message }; 
  }, 

一旦 state 被初始化,就能像 props 一样在组件中使用了。为了去捕获用户的行为带来,然后去更新 state,各种需要使用的事件函数都会注册。为了保持组件的独立(和其他组件之间只通过数据进行交换,较少耦合性),每个事件处理函数都可以以 props的形式进性传递,也可以直接在组件内进行定义。

"use strict";

var Message = React.createClass({

  getInitialState: function() {
    return { message: this.props.message };
  },

  _messageChange: function(e) {
    this.setState({ message: e.target.value });
  },

  render: function() {
    return (
      <div>
        <span>Message: {this.state.message}</span>
        <br />
        Message: <input type="text" value={this.state.message} onChange={this._messageChange} />
      </div>
    );
  },

});

var mainElement = document.querySelector("main");

ReactDOM.render(<Message message="Hello World!!" />, mainElement); 

React 的另外一个优点就是使用了标准的 HTML 事件。这样一来学习特殊的事件库,事件处理函数和第三方事件就不再是需要的。

为了去处理 state 的变化,setState 函数被用来设置 state 的新值。调用这个函数会触发组件的重新渲染。

结论

React 组件对数据提供了两种机制: propsstate。他把数据清楚的划分为了持久性数据 props 与经常改变的数据 state,然后把这两种数据和组件产生关联。

通常意义上,对于简单的数据流 props 是首选的,state 对于捕获用户交互或者其他 UI 事件造成的数据更新是非常有用的。

propsstate 之间的关系促成了数据通过组件的流动。props 可以用来初始化 statestate 可以在初始化、渲染组件的使用设置 props。通过 state 来捕获用户输出的值、更新 props

上面讨论的只是组件中数据流相关,对于大型的应用中的数据流建议使用 Flux

原文:https://www.sitepoint.com/working-with-data-in-react-properties-state/


版权声明

写文不易,赠我一杯咖啡增强一下感情可好?

alipay