React.js学习笔记之组件属性与状态

React.js学习笔记之组件属性与状态

@(前端技术)javascript

组件本质上是状态机,输入肯定,输出必定肯定html

组件把状态与结果一一对应起来,组件中有state与prop(状态与属性)。前端

  • 属性是由父组件传递给子组件的java

  • 状态是子组件内部维护的数据,当状态发生变化的同时,组件也会进行更新。当状态发生转换时会触发不一样的钩子函数,从而让开发者有机会作出相应.react

statics

statics 对象容许你定义静态的方法,这些静态的方法能够在组件类上调用。git

var MyComponent = React.createClass({
  statics: {
    customMethod: function(foo) {
      return foo === 'bar';
    }
  },
  render: function() {
  }
});

MyComponent.customMethod('bar');  // true

在这个块儿里面定义的方法都是静态的,意味着你能够在任何组件实例建立以前调用它们,这些方法不能获取组件的 props 和 state。若是你想在静态方法中检查 props 的值,在调用处把 props 做为参数传入到静态方法。github

props

this.props 表示一旦定义,就再也不改变的特性数组

属性的用法

1.键值对

键 :值
值能够有多种形式
<HelloWorld name= ? />服务器

  • 字符串:"XiaoWang"less

  • 求值表达式 {123}、{"XiaoWang"}

  • 数组{[1,2,3]}

  • 变量{variable}

  • 函数求值表达式{function}(不推荐,若是须要函数能够单独把函数提取出来而后单独调用函数)

var HelloWorld =React.createClass({
    rencer:function () {
        return <p>Hello,{this.props.name ? this.props.name : "World"}</p>;
    },
});
var HelloUniverse = React.createClass({
    getInitialState:function () {
        return {name: ''};
    },
    handleChange: function (event) {
        this.setState({name: event.target.value});
    },
    render: function () {
        return <div>
        <HelloWorld name={this.state.name}></HelloWorld>
        <br/>
        <input type="text" onChange={this.handleChange} />
        </div>
    },
});
ReactDom.render(<HelloUniverse />,document.body);

2.展开语法{...props}

React会自动把对象中的属性和值当作属性的赋值

var HelloWorld =React.createClass({
    rencer:function () {
        return <p>Hello,{this.props.name1 + ' 'this.props.name2}</p>;
    },
});
var HelloUniverse = React.createClass({
    getInitialState:function () {
        return {
            name1:'Tim',
            name2:'John',
        };
    },
    handleChange: function (event) {
        this.setState({name: event.target.value});
    },
    render: function () {
        return <div>
        <HelloWorld name={...this.state}></HelloWorld>
        <br/>
        <input type="text" onChange={this.handleChange} />
        </div>
    },
});
ReactDom.render(<HelloUniverse />,document.body);

3.setProps

var HelloWorld =React.createClass({
    rencer:function () {
        return <p>Hello,{this.props.name ? this.props.name : "World"}</p>;
    },
});
var instance = React.render(<HelloWorld />,document.body);
instance.setProps({name:'Tim'});

setProps(object nextProps[, function callback])
能够设置组件的属性。这个方法已通过时了(与replaceProps等同样),不久将被删除。这个方法不支持ES6类组件React.Component扩展。

propTypes

组件的属性能够接受任意值,字符串、对象、函数等等均可以。有时,咱们须要一种机制,验证别人使用组件时,提供的参数是否符合要求。

  • 组件类的PropTypes属性,就是用来验证组件实例的属性是否符合要求

var MyTitle = React.createClass({
  propTypes: {
    title: React.PropTypes.string.isRequired,
  },
  render: function() {
     return <h1> {this.props.title} </h1>;
   }
});

上面的Mytitle组件有一个title属性。PropTypes 告诉 React,这个 title 属性是必须的,并且它的值必须是字符串。如今,咱们设置 title 属性的值是一个数值。

var data = 123;
ReactDOM.render(
  <MyTitle title={data} />,
  document.body
);

这样一来,title属性就通不过验证了。控制台会显示一行错误信息

getDefaultProps

getDefaultProps 方法能够用来设置组件属性的默认值。

var MyTitle = React.createClass({
  getDefaultProps : function () {
    return {
      title : 'Hello World'
    };
  },

  render: function() {
     return <h1> {this.props.title} </h1>;
   }
});
ReactDOM.render(<MyTitle />,document.body);

this.props.children

this.props 对象的属性与组件的属性一一对应,可是有一个例外,就是 this.props.children 属性。它表示组件的全部子节点

var NotesList = React.createClass({
  render: function() {
    return (
      <ol>
      {
        React.Children.map(this.props.children, function (child) {
          return <li>{child}</li>;
        })
      }
      </ol>
    );
  }
});
ReactDOM.render(
  <NotesList>
    <span>hello</span>
    <span>world</span>
  </NotesList>,
  document.body
);

上面代码的 NoteList 组件有两个 span 子节点,它们均可以经过 this.props.children 读取。
这里须要注意, this.props.children 的值有三种可能:

  1. 若是当前组件没有子节点,它就是 undefined;

  2. 若是有一个子节点,数据类型是 object;

  3. 若是有多个子节点,数据类型就是 array

React 提供一个工具方法 React.Children 来处理 this.props.children 。咱们能够用 React.Children.map 来遍历子节点,而不用担忧 this.props.children 的数据类型是 undefined 仍是 object。
1.React.Children.map
object React.Children.map(object children, function fn [, object context])
在每个直接子级(包含在 children 参数中的)上调用 fn 函数,此函数中的 this 指向 上下文。若是 children 是一个内嵌的对象或者数组,它将被遍历:不会传入容器对象到 fn 中。若是 children 参数是 null 或者 undefined,那么返回 null 或者 undefined 而不是一个空对象。
2.React.Children.forEach
React.Children.forEach(object children, function fn [, object context])
相似于 React.Children.map(),可是不返回对象。
3.React.Children.count
number React.Children.count(object children)
返回 children 当中的组件总数,和传递给 map 或者 forEach 的回调函数的调用次数一致。
4.React.Children.only
object React.Children.only(object children)
返回 children 中仅有的子级。不然抛出异常。

state

组件在运行时须要修改的数据就是状态

组件免不了要与用户互动,React 的一大创新,就是将组件当作是一个状态机,一开始有一个初始状态,而后用户互动,致使状态变化,从而触发从新渲染 UI

this.state 是会随着用户互动而产生变化的特性。

state工做原理

经常使用的通知 React 数据变化的方法是调用 setState(data, callback)。这个方法会合并(merge) data 到 this.state,并从新渲染组件。渲染完成后,调用可选的 callback 回调。大部分状况下不须要提供 callback,由于 React 会负责把界面更新到最新状态。

var LikeButton = React.createClass({
  getInitialState: function() {
    return {liked: false};
  },
  handleClick: function(event) {
    this.setState({liked: !this.state.liked});
  },
  render: function() {
    var text = this.state.liked ? 'like' : 'haven\'t liked';
    return (
      <p onClick={this.handleClick}>
        You {text} this. Click to toggle.
      </p>
    );
  }
});

ReactDOM.render(
  <LikeButton />,
  document.getElementById('example')
);

getInitialState

object getInitialState()
getInitialState 方法用于定义初始状态,也就是一个对象,这个对象能够经过 this.state 属性读取。在组件挂载以前调用一次。返回值将会做为 this.state 的初始值。

setState

setState(object nextState[, function callback])
合并 nextState 和当前 state。这是在事件处理函数中和请求回调函数中触发 UI 更新的主要方法。另外,也支持可选的回调函数,该函数在 setState 执行完毕而且组件从新渲染完成以后调用。this.setState 方法用于修改状态值,每次修改之后,自动调用 this.render 方法,再次渲染组件。

注意:

  1. 绝对不要直接改变 this.state,由于在以后调用 setState() 可能会替换掉你作的更改。把 this.state 当作不可变的。

  2. setState ( ) 不会马上改变 this.state,而是建立一个即将处理的 state 转变。在调用该方法以后获取 this.state 的值可能会获得现有的值,而不是最新设置的值。

  3. 不保证 setState ( ) 调用的同步性,为了提高性能,可能会批量执行 state 转变和 DOM 渲染。

  4. setState ( ) 将老是触发一次重绘,除非在 shouldComponentUpdate ( ) 中实现了条件渲染逻辑。若是使用可变的对象,可是又不能在shouldComponentUpdate ( ) 中实现这种逻辑,仅在新 state 和以前的 state 存在差别的时候调用 setState ( ) 能够避免没必要要的从新渲染。

replaceState

replaceState(object nextState[, function callback])
相似于 setState(),可是删除以前全部已存在的 state 键,这些键都不在 nextState 中。

注意:这个方法在ES6类组件扩展不可用,它可能会在将来某个React版本中删除

哪些组件应该有 State?

大部分组件的工做应该是从 props 里取数据并渲染出来。可是,有时须要对用户输入、服务器请求或者时间变化等做出响应,这时才须要使用 State。
尝试把尽量多的组件无状态化。这样作能隔离 state,把它放到最合理的地方,也能减小冗余,同时易于解释程序运做过程。

经常使用的模式是建立多个只负责渲染数据的无状态(stateless)组件,在它们的上层建立一个有状态(stateful)组件并把它的状态经过 props 传给子级。这个有状态的组件封装了全部用户的交互逻辑,而这些无状态组件则负责声明式地渲染数据。

哪些应该做为 State?

State 应该包括那些可能被组件的事件处理器改变并触发用户界面更新的数据。 真实的应用中这种数据通常都很小且能被 JSON 序列化。当建立一个状态化的组件时,想象一下表示它的状态最少须要哪些数据,并只把这些数据存入 this.state。在 render() 里再根据 state 来计算你须要的其它数据。你会发现以这种方式思考和开发程序最终每每是正确的,由于若是在 state 里添加冗余数据或计算所得数据,须要你常常手动保持数据同步,不能让 React 来帮你处理。

哪些不该该做为 State?

this.state 应该仅包括能表示用户界面状态所需的最少数据。所以,它不该该包括:

  • 计算所得数据: 不要担忧根据 state 来预先计算数据 —— 把全部的计算都放到 render() 里更容易保证用户界面和数据的一致性。例如,在 state 里有一个数组(listItems),咱们要把数组长度渲染成字符串, 直接在 render() 里使用 this.state.listItems.length + ' list items' 比把它放到 state 里好的多。

  • React 组件: 在 render() 里使用当前 props 和 state 来建立它。

  • 基于 props 的重复数据: 尽量使用 props 来做为唯一数据来源。把 props 保存到 state 的一个有效的场景是须要知道它之前值的时候,由于将来的 props 可能会变化。

属性和状态的对比

类似点

1. 都是纯JS对象

纯JS对象就是JS中的原生对象。是使用 { } 来建立的对象

2. 都会触发render更新

状态和属性的变化都会触发render更新,属性和状态的改变都会触发整个生命周期流程,从处理属性到是否应该更新,到进行对比,到最后的render真正执行,会触发不少函数,咱们能够在不一样的函数中进行不一样的对应操做。

3. 都具备肯定性

给定相同的属性和相同的状态,组件生成的都是相同的代码

对比

Item 属性 状态
可否从父组件获取初始值? o x
可否由父组件修改? o x
可否在组件内部设置默认值? o o
可否在组件内部修改? x o
可否设置子组件的初始值? o x
可否修改子组件的值? o x
  • 状态只与组件自己相关,由本身自己维护。与父组件与子组件无关

  • 组件不能修改本身的属性,但能够从父组件获取属性,父组件也能修改其属性,组件也能够修改子组件的属性

实例

关于属性与状态的实例代码传送门:React简易小demo

小结

本文主要介绍了组件的属性与状态。组件化是React的主要思想,也是其核心所在。组件化也是前端将来的发展趋势,React算是引领了这一潮流吧。关于属性与状态的更多用法在生命周期与协同使用中还会介绍。

PS

被官微转发了有点小意外。声明下,目前在网上找不到一个比较完整的文字react学习文章,博主决定利用业余时间总结下。本博文原创内容很少,大部分都是对文档与网上文章的本身学习总结。

特别感谢

相关文章
相关标签/搜索