React 精简快速入门

作者: github加星点进来 | 来源:发表于2016-07-14 23:48 被阅读421次
    React.png

    React是一个用于构建用户界面的Javascript库
    和庞大的AngularJS不同,React专注于MVC架构中的V,即视图
    reACT 重新造了个轮子: JSX
    React引入了 虚拟DOM的概念
    开发者操作虚拟DOM,React在必要的时候将它们渲染到真正的 DOM上
    虚拟DOM是React的基石

    在React中,应用程序在虚拟DOM上操作, React在每次需要渲染时,会先比较当前DOM内容和待渲染内容的差异, 然后再决定如何最优地更新DOM。

    除了性能的考虑,React引入虚拟DOM更重要的意义是提供了一种一致的开发方 式来开发服务端应用、Web应用和手机端应用:

    因为有了虚拟DOM这一层,所以通过配备不同的渲染器,就可以将虚拟DOM的内容 渲染到不同的平台。而应用开发者,使用JavaScript就可以通吃各个平台了。

    相当棒的思路!

    • createElement(type,[props],[children...]) - 在虚拟DOM上创建指定的React元素

    参数type用来指定要创建的元素类型,可以是一个字符串或一个React组件类型。当使用 字符串时,这个参数应当是标准的HTML标签名称,比如:p、div、canvas等等。

    参数props是可选的JSON对象,用来指定元素的附加属性,比如样式、CSS类等等。 我们在示例中简单的设置为null。

    从第三个参数children开始的所有参数,都被认为是这个元素的子元素。考虑到 虚拟DOM好歹也是DOM,容易理解React需要通过这些子元素参数,让我们可以构造虚拟DOM树:

    var el = React.createElement(
    "ul",
     null,
    React.createElement("li",null,"China"),
    React.createElement("li",null,"Japan"),
    React.createElement("li",null,"Korea")
    );
    

    上面的例子在虚拟DOM中创建了一个具有三个li子元素的ul元素,看起来有点累。不过 想想,造一个轮子,总会付出一些代价的。

    在示例中,我们简单地传入了一个文本子元素作为p元素的内容。

    • render(element,container,[callback]) - 将虚拟DOM上的对象渲染到真实DOM上

    参数element是我们使用createElement()方法创建的React元素,注意,不是HTML元素!

    参数container是真实DOM中的HTML元素,作为渲染的目标容器,它的内容将被render()方法 的执行改变。

    callback参数是可选的函数,当渲染完成或更新后被执行,通常我们不用它。

    React组件

    在React中定义一个组件也是相当的容易,组件就是一个 实现预定义接口的JavaScript类:

    • React.createClass(meta)

    参数meta是一个实现预定义接口的JavaScript对象,用来 对React组件原型进行扩展。

    在meta中,至少需要实现一个render()方法,而这个方法, 必须而且只能返回一个有效的React元素。

    这意味着,如果你的组件是由多个元素构成的,那么你必须在外边包一个顶层 元素,然后返回这个顶层元素。比如我们创建一个布局组件:

     render:function(){
     return React.createElement(
       "div",null,
    React.createElement("div",null,"header"),
    React.createElement("div",null,"content"),
    React.createElement("div",null,"footer")
     );
    

    }

    注意 :你的React组件名称的首字母应当大写, 关于大小写的差异你会在后面发现。

    在示例代码中,我们实现了一个液晶显示组件EzLedComp(为了更逼真一些, 定义了简单的样式,别忘了翻看一下),你应该会注意到div元素的样式类是用 className而不是class声明的,这是因为class 是JavaScript的保留字,渲染后,真实的DOM还会是:

    <div class="ez-led">Hello, React!</div>
    

    组件定义以后,和标准HTML标签一样,可以使用createElement()方法 创建元素,只是这时,第一个参数是我们定义的组件类,而不是标签名字符串:

    • React.createElement(EzLedComp);

    修改示例代码,定义一个两排字的液晶显示组件

    轮子来了:JSX == javascript + XML

    <script src="lib/react.min.js"></script>

    <script src="lib/JSXTransformer.js"></script>

                    //JSX-->
                    <div>
                        <div className="ez-led">Hello, React!</div>
                        <div className="ez-led">2015-04-15</div>
                    </div>;
                    //<--JSX
    
    • 指定脚本类型

    在html文件中引入的JSX脚本,需要指定类型为text/jsx:

    • //内联脚本
    • <script type="text/jsx">...</script>
    • //外部脚本
    • <script src="a.js" type="text/jsx"></script>
    • 引入JSX语法转换库

    在html中使用JSX,还需要引入JSX语法转换库JSXTransform.js。 这个库加载后,将在DOM树构造完成后(通过监听DOMContentLoaded事件)处理 JSX脚本:

      1. 搜索DOM树中的script节点,如果其类型为text/jsx则进行后续处理
      1. 读取script节点的内容,将其转化为JavaScript代码
      1. 构造一个新的script元素,设置其内容为转化结果代码,并追加到DOM树head元素中

    JSXTransform.js引入后通过全局对象JSXTransformer提供了API接口, 我们可以使用transform()方法来模拟这个语法自动转换的过程。

    在右边的示例代码中,为了避免自动转换,我们将script元素的类型设置为text/jsx2, 同时为了简化DOM元素定位,给它加了一个id。

    属性 : props
    三种写法

    //定义React组件
    var EzLampComp = React.createClass({
    render : function(){
    //取得属性值
    var onoff = this.props.onoff;

                //返回React元素
                if(onoff == "on")
                    return <span className = "ez-lamp on"></span>;  //JSX
                else
                    return <span className = "ez-lamp off"></span>;  //JSX
            }
        });
        //渲染React元素
    
    1. 属性
      React.render(
      < EzLampComp onoff="off" /> ,
      document.querySelector("#content"));

    2.  var myOnoff = "on";
       React.render(
       < EzLampComp onoff={myOnoff} />,
       document.querySelector("#content"));
      
    3.   varmyOnoff="on";
        React.render(
        React.createElement(
        EzLampComp,
        {
        onoff : myOnoff
        }),
        document.querySelector("#content"));
      

    内联样式

    在前面的示例中,每当需要设定元素的样式,我们总是使用样式类。但有时我们的确需要 直接在元素上声明内联样式,就像在HTML中一样:

    • //HTML
      <div style="width:200px;height:200px;"></div>

    在React元素中声明样式,需要给出一个JSON对象,其字段对应样式名称,比如要渲染出 上面的HTML片段,需要这样:

        var myStyle = {
         width:"200px",
        height:"200px"
        };
    
    • //JSX
      var e = <div style={myStyle} />;

    • //JavaScript
      var e = React.createElement(
      "div",{
      style : myStyle
      });

    • //render
      React.render(e,...);

    • 注意1 - 对应样式名称的字段,需要使用驼峰式命名

    比如:border-radius样式需要使用borderRadius来访问,而background-image 样式需要使用backgroundImage来访问。

    • 注意2 - 样式名称中的供应商前缀,除ms外都需要大写首字母

    对于供应商前缀(-webkit, -moz, -o, -ms),除了ms,其他都需要将首字母大写。 比如:-webkit-transition应当通过WebkitTransition来访问,然而-ms-transition 则需要通过msTransition来访问。

    状态记忆 : state

    很多情况下,组件实例的外观及行为通过使用props变量进行定制就可以了。 这样的组件我们称之为无状态/stateless的组件,因为在任何时刻,组件 实例的表现都仅仅取决于外部传入的props属性,与 它自身之前的表现毫无关系,即,它本身没有任何记忆。

    让一个组件拥有记忆能力,意味着它不仅能对外界的刺激产生反应(通过props 传入的数据、或用户的交互事件),也能根据自身的状态对同样的刺激做出 不同的反应。

    比如示例中的切换开关,它可以响应用户的点击事件,如果当前状态是关,那么它就 切换到开的状态(显示开状态的图片);而如果当前状态是开,那么它就切换到关的 状态(显示关状态的图片):

    现在思考一下,使用props可以实现这个切换开关吗?

    React的组件的确引入了状态机的概念,通过将组件划分为不同的状态,使组件具有 了一定的记忆能力:

    • state - 组件的状态变量

    每个React组件实例都有一个state变量,用来保存组件的当前状态。可以在 任何时刻使用this.state读取当前状态。

    • getInitialState() - 设置组件初始状态

    组件的实现者应当实现一个getInitialState()方法来设置组件的初始状态。getInitialState()方法必须返回一个JSON对象或空值null, 这意味着即使你只需要一个简单的标志作为状态,比如true或false,也要把它放到JSON对象里。

    • setState(currentState) - 设置组件当前状态

    尽管可以使用this.state来直接设置组件当前状态,但React要求我们使用setState()方法来进行状态设置。这是因为,setState()方法会自动 地重新渲染组件,而这通常是我们所期望的。

    参数currentState是一个JSON对象,不必包含状态变量的所有字段,setState()方法会 将这个参数值与当前状态this.sate进行合并,结果作为状态变量的新值。

    生命周期

    在组件实例的整个周期中,React将在特定的时间点调用以下方法:

    • componentWillMount() - 组件实例即将挂接(初次渲染)时被调用

    这个方法在整个生命周期中只会被调用一次。

    • componentDidMount() - 组件实例挂接(初次渲染)后被调用

    这个方法在整个生命周期中只会被调用一次。

    • componentWillReceiveProps(nextProps) - 组件实例即将设置新属性时被调用

    参数nextProps表示即将应用到组件实例上的新属性值。

    这个方法在初次渲染时不会被调用。在此方法内调用setState()不会引起重新渲染。

    • shouldComponentUpdate(nextProps, nextState) - 组件实例即将重新渲染时被调用

    参数nextProps传入即将应用到组件实例上的新属性值,参数nextState传入组件实例即将被 设置的状态值。如果这个方法返回false,那么组件实例就不会被重新渲染。除非我们明确地 知道,新的属性和状态不需要进行重新渲染,否则这个方法都应该返回true。

    这个方法在初次渲染时或通过forceUpdate()方法进行渲染时不会被调用。

    • componentWillUpdate(nextProps, nextState) - 组件实例即将重新渲染时被调用

    这个方法在初次渲染时不会被调用。注意:不能在此方法内调用setState()。

    • componentDidUpdate(prevProps, prevState) - 组件实例重新渲染后被调用

    这个方法在初次渲染时不会被调用。

    • componentWillUnmount() - 组件实例即将从DOM树移除时被调用

    这个方法在整个生命周期中只会被调用一次。

    访问DOM

    在React中,有时需要_直接访问_React元素对应的DOM对象,比如读取用户的输入。 这需要两个步骤:

    • 设置React元素的ref属性

    如果需要在代码中访问某个React元素的DOM对象,那么首先需要设置这个React 元素的ref属性。

    比如,我们需要读取文本输入框的值,那么首先给这个input元素指定ref属性:

    • //JSX
      <input type="text" defaultValue="beijing" ref="q"
      placeholder="请输入城市拼音,如:beijing"/>

    声明了React元素的ref属性之后,可以通过this.refs对象访问 这个组件,比如上面的示例中:this.refs.q指向input组件对象,你应该已经注意到, 我们为React元素设置的ref属性值,在这里被用为this.refs对象的键值。

    • 获得DOM对象

    在设置了React元素的ref属性后,可以使用React.findDOMNode()方法获得对应的 DOM对象:

    • React.findDOMNode(component)

    参数component是一个React组件对象,如前所述,我们可以通过this.refs对象获得。

    如果React元素已经渲染到DOM树上,findDOMNode()方法将返回组件对象对应的DOM节 点对象,后续就可以使用标准的DOM API操作这个DOM对象了。

    右边的示例实现了一个简单的天气查询组件,在文本框中输入城市名称的拼音,点击按钮 就可以获得这个城市的当前天气信息。天气数据实时从openweathermap.org网站读取,所以 可能会慢点,也可能,失效:

    表单输入

    在React中,表单输入元素如 input, textarea, option等,和其他标准的HTML元素 相比需要特殊的注意:

    • 文本输入框

    不要使用value属性设置文本输入框元素的初值,应当使用defaultValue:

    • //JSX
      <input type = "text" defaultValue = "demo"/>

    • 复选按钮

    不要使用checked属性设置复选按钮的初始选中状态,应当使用defaultChecked:

    • //JSX
      <input type = "checkbox" defaultChecked/>

    • 单选按钮组

    不要使用option元素的selected属性设置单选按钮组的初始选中状态,应当使用 select元素的defaultValue:

    • //JSX
      <select defaultValue="A">
      <option value="A">China</option>
      <option value="B">India</option>
      <option value="C">Japan</option>
      </select>

        <!DOCTYPE html>
        <html>
      

    <head>
    <meta charset="utf-8">
    <title>EzLoginComp</title>
    <script src="lib/react.min.js"></script>
    <script src="lib/JSXTransformer.js"></script>
    </head>
    <body>
    <div id="content"></div>
    <script type="text/jsx">
    //组件定义
    var EzLoginComp = React.createClass({
    auth : function(event){
    var account = React.findDOMNode(this.refs.account).value,
    pass = React.findDOMNode(this.refs.password).value;
    alert([account,pass]);

            },
            render : function(){
    
                return     <div className = "ez-login">
                            <div className="row title">
                                <h1>登录</h1>
                            </div>
                            <div className="row account">
                                <label>用户</label>
                                <input type="text" defaultValue="asasassa" ref="account"/>
                            </div>
                            <div className="row pass">
                                <label>密码</label>
                                <input type="text" ref="password"/>
                            </div>
                            <div className="row remember">
                                <input type="checkbox" defaultChecked/>
                                <span>记住密码</span>
                            </div>
                            <div className="row button">
                                <button onClick={this.auth}>登录</button>
                            </div>
                        </div>;
            }
        });
        //渲染
        React.render(<EzLoginComp/>,document.querySelector("#content"));
           </script>
        </body>
        </html>

    相关文章

      网友评论

        本文标题:React 精简快速入门

        本文链接:https://www.haomeiwen.com/subject/jxcyjttx.html