• React: 研究React的组件化


    一、简介大概

    在以往的Web开发中,会把web页面所有的复杂控件作为一个单一的整体进行开发,由于控件之间需要进行通信,因此不同的组件之间的耦合度会很多,由于开发一个控件的时候要考虑到控件与控件之间的联系,这么一来,随意一个复杂控件的代码思想就很复杂。ReactJS的出现,很好地解决了这个问题,ReactJS的核心思想就是组件化,它会把页面中的组件一个个进行分解,按照功能要求,大组件可以分解成小组件,小组件还可以分解成更小更简单的组件,各个组件维护自己的状态和UI,当状态发生改变时,会自动重现渲染整个组件,多个组件一起协作共同构成了ReactJS应用。组件化的开发思想中,可以将组件对应一个类,类与类之间的组合实现了解耦,而且类中将界面逻辑和业务逻辑统一在一起又实现了聚合,逻辑很直观。

    二、简单创建

    在ReactJS中,React为开发者提供了丰富的API,详细的可以去官网查看:http://facebook.github.io/react/docs/getting-started.html。当然,在日常开发中常用的API主要分为两大类,分别是顶层API和组件API。

    顶层API:挂在React对象下的API,如React.createClass、React.render、ReactDOM.render等。

    组件API:只有组件内部才可以调用的API,如render等。

    创建一个简单的组件如下:

    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title>Hello React</title>
        <script src="react.js"></script>
        <script src="react-dom.js"></script>
        <script src="browser.min.js"></script>
    </head>
    <body>
        <div id="container"></div>
        <script type="text/babel">
            var DivComponment = React.createClass({
                render: function(){
                    return (
                        <div>Hello DivComponment!!!</div>
                    );
                }
            });
            ReactDOM.render(
                            <DivComponment></DivComponment>,
                            document.getElementById('container') /*document.querySelector('#container')*/
                        );
        </script>
    </body>
    </html>

    渲染结果如下: 

    注意:React.render已过时,推荐用ReactDOM.render

    三、步骤详解

    1、React是全局对象,ReactJS的所有顶层API都挂在这个对象下;

    2、React.createClass是ReactJS用来创建组件类的方法;

    3、render是一个组件级别的API,是React.createClass内部最常用的API,该方法主要用来返回组件结构;

    4、ReactDOM.render是最基本的方法,用于将模板转为HTML,并将转换后的DMO结构插入到指定的DOM节点上。

    5、ReactDOM.render函数可以拥有三个参数,第1个参数是ReactJs组件,第2个参数是组件挂载的父节点容器,第3个则是插入后的函数回调。格式:

    //基本格式
    ReactDOM.render (
       ReactElement element,  //ReactJS组件
       DOMElement container,  //页面中的DOM容器,也即挂载节点
       [function callback]    //插入后的回调
    )

    四、生命周期

    使用ReactJS创建的组件也是存在生命周期的,这个生命周期贯穿在render方法前后,在这个过程中,开发者可以处理需要的业务逻辑。组建的声明周期主要分为四个阶段,分别是创建阶段、实例化阶段、更新阶段、销毁阶段。

    现在,咱们就来监控一下创建一个组建的生命周期是如何运作的。

    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title>Hello React</title>
        <script src="react.js"></script>
        <script src="react-dom.js"></script>
        <script src="browser.min.js"></script>
    </head>
    <body>
        <div id="container"></div>
        <script type="text/babel">
            var DivComponent = React.createClass({
    
                //1.创建阶段
                getDefaultProps() {
                    //在创建组件类的时候被调用, 对this.props进行初始化
                    console.log("------getDefalutProps------");
                    return {
                        title:"I Am XYQ"
                    }
                },
    
                //2.实例化阶段
                getInitialState() {
                    //给this.state进行初始化
                    console.log("------getInitialState------");
                    return {
                        val : 1
                    }
                },
    
                componentWillMount() {
                    //根据业务逻辑对state进行相应的操作
                    var message = "------componentWillMount------";
                    if(this.state.val == 1){
                        message = message + "this.state.val = " + this.state.val;
                    }
                    console.log(message);
                },
    
                render:function() {
                    //渲染返回一个虚拟的DOM 
                    console.log("------render------");
                    return ( 
                        <div>{this.props.title}</div>
                    );
                },
    
                componentDidMount() {
                    //创建真实的DOM结构  
                    console.log("------componentDidMount------");
                    this.setState({
                          val: this.state.val + 1
                        })
                    setTimeout(() => {
                          this.setState({val: this.state.val + 1});
                    }, 0);
    
                    //方式一:修改DOM节点元素的样式, 该方法已过时,推荐使用方式二
                    //this.getDOMNode().style.color = "red"
                    //this.getDOMNode().style.fontSize = "30px"
    
                    //方式二:修改DOM节点元素的样式,ReactDOM.findDOMNode(instance)    
                    var div = document.getElementById('container')
                    ReactDOM.findDOMNode(div).style.color = "red";
                    ReactDOM.findDOMNode(div).style.fontSize = "30px";    
                },
    
                //3.更新阶段
                componentWillReceiveProps(nextProps) {
                    //发生在this.props被修改或父组件调用setProps()时调用
                    console.log("------componentWillReceiveProps------"+"nextProps.title = "+nextProps.title);
                },
                
                shouldComponentUpdate(nextProps, nextState) {
                    //是否更新
                    console.log("------shouldComponentUpdate------"+"nextProps.title = "+nextProps.title + "-----" +"nextState.val = "+nextState.val);
                    return true;
                },
    
                componentWillUpdate() {
                    //将要更新
                    console.log("------componentWillUpdate------");
                },
    
                componentDidUpdate() {
                    //更新完毕
                    console.log("------componentDidUpdate------");
                },
    
                //4.销毁阶段
                componentWillUnmount() {
                    //销毁时调用
                    console.log("------componentWillUnmount------");
                }
    
            });
            ReactDOM.render(
                            <DivComponent/>,
                            document.getElementById('container')  /*document.querySelector('#container')*/
                        );
    
        </script>
    </body>
    </html> 

    结果如下:

    五、流程分析

    1、关键词

    state: 组件的属性,用来存储组件自身需要的数据

    它是可以改变的,它的改变会引发组件的更新,这就是ReactJS的关键点之一。

    每次数据的更新都是通过修改state属性的值,然后ReactJS内部会监听state属性的变化,一旦发生变化,就会主动触发组件的render方法来更新DOM结构

    虚拟DOM: ReactJS中提出的概念

    将真实的DOM结构映射成一个JSON数据结构 

    2、流程线

    创建阶段:创建组件类,也即使用React.createClass()时

    调用getDefalutProps返回一个对象并缓存,作为返回值跟父组件props合并,然后再赋值给this.props作为组件默认属性。

    实例化阶段:对组件类进行实例化 ,也即使用ReactDOM.render()时

    getInittialState: 初始化组件state的值,并作为返回值,赋值给组件的this.state属性
    
    componentWillMount:根据业务逻辑对state进行相应的操作, 组件即将进行组装
    render: 根据state的值,生成页面需要的虚拟DOM结构,并返回该结构
    componentDidMount: 根据虚拟DOM结构生成真实的DOM进行处理,组件完成组装,内部可以使用this.getDOMNode()获取当前组件节点,然后进行操作,该方法已过时

    更新阶段:根据用户的操作,对相应页面的调整进行组件更新

    componentWillReceiveProps(nextProps):获取到新的props属性时调用,例如在该函数中调用this.state对state进行修改
    
    shouldComponentUpdate(nextProps,nextState):该方法用来拦截新的prop或者state,根据逻辑判断来决定组件是否更新
    componentWillUpdate:如果shouldComponentUpdate返回true决定更新,可以在该方法中做一些更新之前的操作,并且后面的componentDidUpdate才会执行
    render:根据diff算法,对更新前后的结构进行比较,生成需要更新的虚拟的DOM数据。推荐,该方法中只做数据和模板组合,不做state等逻辑修改
    componentDidUpdate: 该方法在组件更新同步到DOM后调用,可以对DOM进行一些操作

    销毁阶段:

    componentWillUnmount: 组件从DOM中移除时会调用。一般在该方法中做一些取消事件绑定、销毁定时器等。

    六、组件通信

    虽然说ReactJS的数据流是单向的,但是ReactJS仍然提供了组件之间进行双向通信的方式,可以通过系统默认的属性关键字来实现。

    这两个属性关键字分别是props和ref。

    • 子组件调用父组件的方法:父组件把被调用的的方法以属性的形式放在子组件上,子组件通过“this.props.被调用方法”方式进行调用
    • 父组件调用子组件的方法:子组件被设置一个ref属性,父组件可以通过“this.ref.xxx”方式拿到子组件,然后进行相应的设置和逻辑处理

    如下示例:

    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title>Hello React</title>
        <script src="react.js"></script>
        <script src="react-dom.js"></script>
        <script src="browser.min.js"></script>
    </head>
    <body>
        <div id="container"></div>
        <script type="text/babel">
    
            //父组件
            //通过子组件的ref属性获取子组件并设置子组件样式
            var Parent = React.createClass({
    
                render:function() {
    
                    //给div添加点击事件,切换字体颜色
                    function testClick(){
    
                        var childDOM = ReactDOM.findDOMNode(this.refs.child);
    
                        if(childDOM.style.color == "red"){
                            childDOM.style.color = "green";
                        }
                        else if(childDOM.style.color == "green"){
                            childDOM.style.color = "red";
                        }
                        else {
                            childDOM.style.color = "red";
                        }
                        childDOM.style.fontSize = "30px";
                    }
    
                    return ( 
                        <div onClick={testClick.bind(this)}>
                            Parent is:
                            <Children name={this.props.name} ref="child"></Children> 
                        </div>
                    )
                }
            });
    
            //子组件
            //通过父组件的this.props.name设置子组件属性值
            var Children = React.createClass({
                render:function() {
                    return (
                        <h1> {this.props.name} </h1>
                    )
                }
            });
    
    
            ReactDOM.render(
                            <Parent name="I Am XYQ"></Parent>,
                            document.getElementById('container')
                        );
    
        </script>
    </body>
    </html>

  • 相关阅读:
    【转】Flask安装
    【转】Mac OS X 中 Zsh 下 PATH 环境变量的正确设置
    【转】谁说Vim不是IDE?(二)
    【转】谁说Vim不是IDE?(三)
    【转】谁说Vim不是IDE?(一)
    【转】终极 Shell
    【转】开始使用Mac OS X——写给Mac新人
    【转】如何实现一个malloc
    《神经网络和深度学习》系列文章十六:反向传播算法代码
    Vue.js之生命周期
  • 原文地址:https://www.cnblogs.com/XYQ-208910/p/11922708.html
Copyright © 2020-2023  润新知