[关闭]
@Dale-Lin 2019-03-20T21:11:36.000000Z 字数 5604 阅读 797

React 概念

Reactjs


React 组件

React 允许将代码封装成 component,然后像插入普通 HTML 一样,在网页中插入这个组件。

React.createClass 方法用于生成一个组件类:

  1. var HelloMessage = React.createClass(
  2. render: function() {
  3. return <h1>Hello {this.props.name}</h1>;
  4. }
  5. );
  6. ReactDOM.render(
  7. <HelloMessage name="John" />,
  8. document.getElementById('example')
  9. );

上面代码中声明了组件类 HelloMessage 。在模板中插入 <HelloMessage /> 时(无子代的组件类可以使用自闭合标签),会自动生成该组件类的一个实例。所有组件类都必须有自己的 render 方法,用于输出组件。

组件类的第一个字母必须大写!
组件类只能包含一个顶层标签!

组件的用法和原生的 HTML 标签完全一致,可以任意加入属性。比如上述代码中,HelloMessage 组件的实例加入了一个 name 属性,值为 John

组件的属性可以在组件 中的 this.props 对象中获取。如上例使用 this.props.name 获取了组件实例的 name 属性。

作为 JavaScript 保留字的属性有特殊写法:

this.props.children

this.props 对象的属性与组件的属性一一对应,例外的是 this.props.children 属性,它表示组件实例的所有子节点:

  1. var NotesList = React.createClass(
  2. render: function() {
  3. return (
  4. <ol>
  5. React.Children.map(this.props.children, function (child) {
  6. return <li>{child}</li>;
  7. })
  8. </ol>
  9. )
  10. }
  11. );
  12. ReactDOM.render(
  13. <NoteList>
  14. <span>hello</span>
  15. <span>world</span>
  16. </NoteList>,
  17. document.body
  18. );

上面代码的 NodeList 实例有两个子节点,都可以通过组件类中的 this.props.children 读取。

如果当前组件没有子节点,this.props.childrenundefined;如果有一个子节点,数据类型是 object;如果有多个子节点,数据类型是 array

上例使用了 React 提供的工具方法 React.Children.map(children, function[(thisArg)]) 来处理 this.props.children
使用这个方法可以遍历 this.props.children 子节点,不用考虑其数据类型。

事件处理

React 的事件类似 JavaScript 语法中的事件,要注意的是,事件处理函数返回 false 不会阻止事件的冒泡。应该合理使用 e.stopPropagation()e.preventDefault() 来手动设置。

事件处理程序是公用的,事件对象会被复用,在事件处理程序结束后事件对象的所有属性会清除,不能通过异步方式访问事件:

  1. function onClick(event) {
  2. console.log(event); //nullified object.
  3. console.log(event.type); //"click"
  4. const event.type = event.type; //"click"
  5. setTimeout(function() {
  6. console.log(event.type); //null
  7. console.log(eventType); //"click"
  8. }, 0);
  9. //this.setState.clickEvent only contains null values
  10. this.setState({clickEvent: event});
  11. //can still export event properties
  12. this.setState({eventType: event.type);
  13. }

可以调用 event.persist() 将事件从公共池移出,从而异步地访问事件属性。

支持事件:

获取真实的 DOM 节点

组件是 virtual DOM 结构,只有插入文档以后才会变成真实的 DOM。
React 中,所有 DOM 变动都先在 virtual DOM 上发生,然后再将实际发生变动的部分,反映在真实 DOM 上(DOM diff)。

在组件类中声明 ref 属性用于获取真实的 DOM 节点:

  1. import React, { Component } from 'react';
  2. class Input extends React.Component {
  3. constructor(props) {
  4. super(props);
  5. this.handleClick = this.handleClick.bind(this); //类的方法默认不绑定 this,为 undefined
  6. }
  7. handleClick(e) {
  8. this.refs.yourInputName.focus();
  9. }
  10. render() {
  11. return {
  12. <div>
  13. <input type="text" ref="yourInputName" />
  14. <input type="button" value="Focus the text input" onClick={this.handleClick} />
  15. </div>
  16. };
  17. }
  18. }

Input 组件的子节点中,第一个文本输入框用于获取用户的输入;第二个用于聚焦第一个文本框。Virtual DOM 是不能获取用户输入的,要拿到真实的 DOM 节点,在对应的 virtual DOM 元素上要设置一个 ref=[refName] ,其真实的 DOM 节点会保存在 this.refs.[refName] 中。

只有在 virtual DOM 插入文档后才会有该类的真实 DOM,这时才可以访问。

更好的用法

  1. <Component ref={(node) => {this.saveDomNode = node}}/>

如果 ref 属性是一个函数,将会把组件的 DOM 元素作为参数传给这个函数,从而可以获得其引用。

this.setState(updater/stateChange)

如果把组件看成一个函数,那么它接受了外部参数——props;内部参数为——state,返回一个 virtual DOM 的实现。

当组件实例与用户互动,this.setState 被调用来改变内部状态时,组件和其子组件会尝试重新渲染:

  1. import React, { Component } from 'react';
  2. class Counter extends React.Component {
  3. constructor(props) {
  4. super(props);
  5. this.handleClick = this.handleClick.bind(this);
  6. this.state = { count: 0 };
  7. }
  8. handleClick(e) {
  9. e.preventDefault(); //使用该方法才能阻止默认行为
  10. this.setState({
  11. count: this.state.count + 1
  12. });
  13. }
  14. render() {
  15. return {
  16. <div>
  17. <p>{this.state.count}</p>
  18. <a href="#" onClick={this.handleClick}>Refresh</a>
  19. </div>
  20. };
  21. }
  22. }

参数可以是一个函数(updater):
(prevState, props) => stateChange
其中的 state 对应当前的 state,返回的是重新设置的 state。例如,利用原 state 和 props 设置:

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

也可以使用一个对象作为参数:
setState(stateChange)
这样将会把 stateChange 合并到更新的 state 中。

setState通过引发一次组件的更新过程来引发重新绘制

setState 方法调用引起的 React 组件更新四个生命周期函数:

比起修改 props 引发的生命周期少一个 componentWillReceiveProps。
只有 render 调用时,state 才会更新。

React 生命周期

React 组件的生命周期分为两类:

组件的挂载和卸载过程

组件的挂载又称组件的初始化,有两个生命周期方法:

数据更新过程

更新过程指父组件向下传递 props 或组件自身执行 setState() 方法时发生的一系列动作。

如果组件自身的 state 更新了,会依次执行:

shouldComponentUpdate() 是一个特别的方法,它接收需要更新的 propsstate,可以在内部进行判断,让组件在需要更新的时候进行更新。当方法返回 false 的时候,组件不再向下执行生命周期方法。

默认情况下组件会将更新 props 节点的所有子节点重新渲染,因为 shouldComponentUpdate() 方法返回 true。

无状态组件每次都会重新渲染。

componentWillUpdate(nextProps, nextState) 在渲染前,提供需要更新的 propsstatecomponentDidUpdate(prevProps, prevState) 在渲染后,提供更新前的 propsstate,。

如果组件是由父组件更新 props 而更新的,那么在 shouldComponentUpdate() 之前会先执行 componentWillReceiveProps(nextProps)
此方法可以作为 React 组件在 props 传入后,渲染之前 setState() 而不二次渲染的机会。

整体流程

新生命周期

static getDerivedStateFromProps(nextProps, prevState)

用该方法替换 componentsWillReceiveProps
返回值是包含要更新的 state 对象的:

  1. static getDerivedStateFromProps(nextProps, prevState) {
  2. if (nextProps.value !== prevState.value) {
  3. return {
  4. value: nextProps.value,
  5. }
  6. }
  7. return null,
  8. }

React 与 DOM

ReactDOM

在顶层组件以及由于 React 模型所限而不得不操作 DOM 的时候,需要使用 ReactDOM。
DOM 真正被添加到 HTML 中的生命周期方法是 componentDidMountcomponentDidUpdate ,在这两个方法中可以使用以下两种方法获取真正的 DOM 元素。

要严格限制 DOM 操作场景!

ref

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注