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>

 

posted @ 2019-11-26 16:34  XYQ全哥  阅读(1095)  评论(0编辑  收藏  举报