为了账号安全,请及时绑定邮箱和手机立即绑定

React 精简快速入门

标签:
JavaScript

https://img1.sycdn.imooc.com//5d2d9ee400015b3902480226.jpg

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 class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="lib/react.min.js"></script>

<script class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="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 class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="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 class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="lib/react.min.js"></script>
<script class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="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>



作者:二月长河
链接:https://www.jianshu.com/p/56c820309ffa


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消