React 精简快速入门

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>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容

  • 原教程内容详见精益 React 学习指南,这只是我在学习过程中的一些阅读笔记,个人觉得该教程讲解深入浅出,比目前大...
    leonaxiong阅读 2,809评论 1 18
  • 本笔记基于React官方文档,当前React版本号为15.4.0。 1. 安装 1.1 尝试 开始之前可以先去co...
    Awey阅读 7,641评论 14 128
  • 以下内容是我在学习和研究React时,对React的特性、重点和注意事项的提取、精练和总结,可以做为React特性...
    科研者阅读 8,215评论 2 21
  • 已经记不清当我把这件事告诉妈妈时,妈妈说了什么。可是 当她听闻此事时后忧虑与焦急的神情以及送我走时,目中满盈着的对...
    未明海阅读 238评论 0 0
  • 感谢遇见,感恩陪伴。 我也算是富有的人了吧, 拥有视我如宝的家人, 待我如亲人的朋友。 这样的美好大概是来自是尘世...
    等待ye是一种幸福阅读 98评论 0 0