65React简介:

一、ReactJS的背景和原理(真实DOM和虚拟DOM)  
![图片描述](attimg://article/content/picture/201805/20/194653fnrpps9b0ncpcpdn.png)
1、所有浏览器的引擎工作流程都大致分5步:解析HTML,创建DOM tree–>解析CSS,创建Style Rules->合并DOM树和CSS规则,生成Render tree->布局Render tree–>绘制Render tree。用原生api或jQuery操作DOM“一次”,浏览器会从创建DOM tree开始,把这5步从头到尾执行“一遍”。
2、比如一次(点击)事件执行时,需要更新10个DOM节点的坐标值,可能更新下一个DOM节点的坐标值时,上一个节点的坐标值又变了,导致前一次计算是无用功,显然这些重绘和回流在浪费性能。理想状态是一次性构建完DOM树,再执行后续操作。但浏览器没这么智能,收到第一个更新DOM请求后,并不知道后续还有9次更新操作,因此会马上执行流程,最终执行10次流程。
3、虚拟DOM就是为了解决这个浏览器性能问题而被设计出来的。在页面打开的时候,React组件会调用render函数构建一棵虚拟DOM树(旧树),在一次操作中,在state/props发生改变后,有10次更新DOM的动作,render函数会10次渲染出新的虚拟DOM树(新树),diff算法会10次更新新树、对比新旧这两棵树、记录这两棵树的差异,最终将差异一次性地attach到DOM树上,然后通知浏览器去绘制,这样可以避免大量的无用计算。
4、在react组件里,render函数执行时,里面的JSX代码经babel转译,变成了React.createElement(),执行结果是虚拟DOM,最后调用ReactDOM.render(virtualDOM,containerDOM)将虚拟DOM转化成真实DOM并插入到页面上。
5、JSX必须借助ReactJS环境才能运行,所以使用前要先加载ReactJS文件(react.js、react-dom.js)除了ReactJS环境,还需要加载JSX的解析器(browser.js)http://www.hangge.com/blog/cache/detail_1472.html
浏览器的工作原理:https://www.html5rocks.com/zh/tutorials/internals/howbrowserswork/
重绘和回流:https://www.cnblogs.com/nanshanlaoyao/p/5876018.html
虚拟Dom原理浅析:https://www.jianshu.com/p/e131df377053
React之diff算法:https://www.jianshu.com/p/3ba0822018cf
Perf调用:https://yq.aliyun.com/articles/66958
二、React的缺点和优点  
1、缺点:React本身只是一个V,不是一个完整的框架,大型项目想要一套完整的框架的话,基本都需要加上React-Router和React-Redux才能用。  
2、优点:(1)单向数据流动;(2)虚拟DOM取代物理DOM作为操作对象;(3)用JSX语法取代HTML模板,在JavaScript里声明式地描述UI。  
三、react组件间的传值
(1)react父组件向子组件传值:属性传参
(2)react子组件向父组件传值:实例是一个对象,在父组件定义一个函数,给这个函数绑定父组件的this,在这个函数的函数体里,将这个函数的参数赋值给父组件实例的一个属性;然后通过属性传参的方式把这个函数传给子组件。在子组件里,给这个函数传参并执行,实现子组件向父组件传值!
(3)跨级组件通信
```javascript
class List extends Component {
    static childContextTypes = {
        color: PropTypes.string
    };
    getChildContext() {//注意一
        return {
            color: 'red'
        };
    }
    render() {
        const {list} = this.props;
        /*return (
            <div>
                < ListTitle title = {title} / >
                    < ul >
                        {list.map((entry, index) = > (
                           < ListItem key = {`list-${index}`} value = {entry.text} />
                         ))}
                    </ul >
            </div>
        );*/
    }
};

class ListItem extends Component {
    static contextTypes = {
        color: PropTypes.string,
    };
    render() {
        const { value } = this.props;
        return (
            /*<li style={{background: this.context.color}}>//注意二
                <span>{value}</span>
            </li>*/
        );
    }
}
```
(4)没有嵌套关系的组件通信
```xml
import {EventEmitter} from 'events';
export default new EventEmitter();
import ReactDOM from 'react-dom';
import React, {Component, PropTypes} from 'react';
import emitter from './events';
class ListItem extends Component {
    static defaultProps = {checked: false,}
    constructor(props) {
        super(props);
    }
    render() {
        return (<li><input type = "checkbox" checked = {this.props.checked} onChange = {this.props.onChange}/><span> {this.props.value}</span> </li>)}
}
class List extends Component {
    constructor(props) {
        super(props);
        this.state = {list: this.props.list.map(entry => ({text: entry.text, checked: entry.checked || false}))}
    }
    onItemChange(entry) {
        const {list} = this.state;
        this.setState({
            list: list.map(prevEntry => ({
                text: prevEntry.text,
                checked: prevEntry.text === entry.text ? !prevEntry.checked : prevEntry.checked,
            }))
    })
        emitter.emit('ItemChange', entry);
    }

    render() {
        return ( <div> <ul> {this.state.list.map((entry, index) => (<ListItem key = {`list-${index}`} value = {entry.text} checked = {entry.checked}
        onChange = {this.onItemChange.bind(this, entry)}/>))}</ul> </div>)
    }
}
class App extends Component {
    componentDidMount() {this.itemChange = emitter.on('ItemChange', (data) => {console.log(data)})}
    componentWillUnmount() {
        emitter.removeListener(this.itemChange);
    }
    render() {
        return ( <List list = {[{text: 1},{text: 2}]}/>)
    }
}
```


四:React组件生命周期  
1、实例化  
(1)实例首次被创建,即第一次调用<element attr="" />  
A、getDefaultProps  
B、getInitialState  
C、componentWillMount  
D、render  
E、componentDidMount  
(2)实例再次被创建,即后来调用<element attr="" />   
A、getInitialState  
B、componentWillMount  
C、render  
D、componentDidMount  
2、存在期:组件已存在时的状态改变,即在完整调用一次<element attr="" /> 的过程中,它内部的state的变化。props是组件外面传入的数据,state是组件内部私有的数据。React组件的数据是一个“从上到下”的“单向”数据流。所有组件的state(状态)就如同一个额外属性汇入主流props(属性),且只能随着主流的方向向下流动。
(1)componentWillReceiveProps  
(2)shouldComponentUpdate  
(3)componentWillUpdate  
(4)render  
(5)componentDidUpdate  
3、销毁&清理期  
componentWillUnmount  
五、React创建组件的三种方式及其区别  
1、React定义组件的三种方式:  
(1)函数式定义的无状态组件  
(2)es5原生方式React.createClass定义的组件  
(3)es6形式的extendsReact.Component定义的组件  
React.createClass和React.Component共同点:  
(1)创建有状态的组件,  
(2)组件要被实例化,  
(3)可以访问组件的生命周期方法。  
2、无状态函数式组件:创建纯展示组件,这种组件只负责根据传入的props来展示,不涉及到要state状态的操作。无状态组件只能访问输入的props,同样的props会得到同样的渲染结果,不会有副作用。  
六、React组件的构成  
1、getInitialState()	一个用于设置最初的state的函数,返回一个对象  
2、getDefaultProps()	一个用于设置默认props的函数,返回值为一个对象  
3、propTypes	一个用于验证特定props类型的对象  
4、mixins	组件间共享方法的途径  
5、statics	一个由多个静态方法组成的对象,静态方法中不能直接调用props和state(可通过参数)  
6、displayName	是一个用于命名组件的字符串,用于展示调试信息,使用JSX时将自动设置  
7、componentWillMount()	在组件首次渲染前触发,只会触发一次  
8、componentDidMount()	在组件首次渲染后触发,只会触发一次  
9、componentWillReceiveProps()	在组件将接受新props时触发  
10、shouldComponentUpdate()	组件再次渲染前触发,可用于判断是否需要再次渲染  
11、componentWillUpdate()	组件再次渲染前立即触发  
12、componentDidUpdate()	组件渲染后立即触发  
13、componentWillUnmount()	组件卸载前立即触发  
14、render()	必填,通常为一个返回Reactnodes或者其它组件的函数  
七、为什么不能用index做key?  
key不同,不会进行diff比较,直接销毁该组件,再重建组件;key相同,不销毁该组件,复用该组件;用index做key值,在视图里移除key=3的元素,那么原来key=4的元素就会占据该位置成为key=3的元素,浏览器渲染到此,会将移除前index=3的元素的相关数据给这个key=3的元素,很显然这样做是错误的;解决办法:让key唯一且不可变;这是删除,增加与之类似。  
八、React组件的数据(props和state)  
props是组件外面传入的数据,state是组件内部私有的数据。React组件的数据是一个“从上到下”的“单向”数据流。所有组件的state(状态)就如同一个额外的水源汇入props(属性)主流,且只能随着主流的方向向下流动。  
九、受控组件:表单元素输入值受React控制的组件为“受控组件”。<inputtype="text">,<textarea>和<select>都接受一个value属性来实现受控组件。 
十一、React 组件
React 组件基本上由 3 个部分组成——属性(props)、状态(state)以及生命周期方法。React 组件可以接收参数(即改变props),也可能有自身状态。一旦接收到的参数(即props)或自身状态有所改变,React 组件就会执行相应的生命周期方法,最后渲染。整个过程完全符合传统组件所定义的组件职责(“属性更新”与“状态改变”)。以上内容来自《深入React技术栈》第18页。“更新过程”指的是父组件向下传递 props 或组件自身执行setState 方法时发生的“一系列更新”。以上内容来自《深入React技术栈》第30页。
动作。
十二、ref可以设置回调函数
1、<input type="text" ref="myInput"/>
this.refs.myInput.value ="22"; //this.$refs.myInput  减少获取dom节点的消耗
2、ref属性可以设置为一个回调函数,这也是官方强烈推荐的用法;这个函数执行的时机为:
组件被挂载后,回调函数被立即执行,回调函数的参数为该组件的具体实例。
组件被卸载或者原有的ref属性本身发生变化时,回调也会被立即执行,此时回调函数参数为null,以确保内存泄露。
```html
class CustomTextInput extends React.Component {
  focus() {
    this.textInput.focus();
  }
  render() {
    return (
      <div>
        <input
          type="text"
          ref={(input) => { this.textInput = input; }} />
          //此时input参数就是表示该DOM本身
        <input
          type="button"
          value="Focus the text input"
          onClick={this.focus.bind(this)}
        />
      </div>
    );
  }
}
```
十三、React browserHistory.push 传参
来源http://www.lizhe.name/node/239
1、传参方式1,参数的名字为value:
browserHistory.push(pathname: '/routerName/123');
通过this.props.params.value获取
2、传参方式2,通过state传参,url中不显示参数:
browserHistory.push(pathname: '/routerName',state: { key: value });
this.props.location.state.key便可以获得state中的key的value;

十四、react相关:
1、状态管理:redux、react-redux
2、自身特性:单向数据流
3、双向绑定:input->onchange->setState-><p>{this.state.value}</p>
4、向上传值:父级组件的函数体内含this和形参->将函数通过属性传参传入子组件->给函数传参并执行
5、向下跨级传值:context
6、getChildContext:定义在上级组件内部,比如<MyDiv><Provider>实现步骤:
(1)上层组件:定义childContextTypes对象和getChildContext函数return{propA:'propA'}
(2)下层组件:定义contextTypes对象和var propA=this.context.propA变量


browserHistory
hashHistory
createMemoryHistory

附:
以 chrome extension 为例,只要在 manifest.json 文件中配置好 permissions ,扩展发起的请求就可以成功跨域




猜你喜欢

转载自blog.csdn.net/bao13716164418/article/details/91975329
65
今日推荐