最新版React入门

工欲善其事必先利其器, 由于react崇尚的是, react一体化. 即, 使用js拯救世界. 因此, 咱们须要先将支持react的webpack 工具解决.html

webpack 配置

这里主要使用的是这些模块:node

"babel-loader": "^6.2.4",
        "babel-core": "^6.8.0",
        "babel-loader": "^6.2.4",
        "babel-plugin-transform-es2015-arrow-functions": "^6.8.0",
        "babel-preset-es2015": "^6.6.0",
        "react-dom": "^15.2.1",
        "react" : "^15.2.1"

将这些文件放到package.json中,而后使用npm install 便可.
这里就不赘述了. 先放一个最简单的webpack.config.js文件.react

var path = require('path'),
    node_modules = path.resolve(__dirname, 'node_modules');

module.exports = {
    // context: __dirname + "/app/src/entry",
    entry: {
       app:"./dev/app"
    }, //演示单入口文件
    output: {
        path: path.join(__dirname, '/dev/dist'), //打包输出的路径
        filename: '[name].entry.js', //打包后的名字
    },
    module: {
        loaders: [{
                test: /\.js|\.jsx$/,
                exclude: /(node_modules|bower_components)/,
                loader: 'babel?presets[]=es2015' //加载使用loader
            }
        ]
    },
    plugins: [
    ],
    watch: true
};

这里须要注意一下, 因为版本的问题, webpack 在v1.13以后, 会默认给entry文件添加extensions. 因此若是你的entry写成了,./dev/app.js的话, 恭喜你, 踩坑了. 若是万一出错了, 你可使用webpack

webpack --display-error-details

来进行排查. ok , 如今咱们正式进入react时间web

react 入门

初期, react基本的操做无外乎就是围绕着,Component和ReactDOM进行编写和渲染。 之前, react并无分的太细化, 不过在version 0.14版本后, ReactDOM和Component就分开了, 主要仍是由于React Native的原因.
不过, 二者分开事后,形成的影响来讲, 仍是不小的. 主要影响到三个方面:算法

  • ReactDOM.render(): 渲染UI层npm

  • ReactDOM.findDOMNode(): 获取节点json

  • ReactDOM.renderToString(): 后端运用的转义String方法后端

上面, 咱们已经下载好了reactreact-dom. 咱们能够来简单看一个demo:安全

import React,{Component} from 'react';
import ReactDOM from 'react-dom';

class Hello extends Component{
    render(){
        return (
        <h1>Hello world</h1>
            );
    }
}
ReactDOM.render(<Hello />,document.getElementById('container'));

重要的是Hello 类中的render方法. 经过return, 返回虚拟的DOM, 而后通过ReactDOM将虚拟的DOM, 渲染到指定节点内部.

动态内容

假如咱们如今想要在render中, 使用变量,so how to do?
很简单, 只要在DOM里面用到curly braces({})便可.

class Hello extends Component{
    render(){
        let name="jimmy";
        return (
        <h1>Hello {name}</h1>
            );
    }
}

嵌套UI

React之因此这么流行,就是由于他的可复用性. 经过< classname /> 这样的调用, 就能够完美的实现, 组件的复用

class UI_item extends Component{
    render(){
        return (
                <UL></UL>
            );
    }
}
class UL extends Component{
    render(){
        return (
            <ul>
                <Li_item name="jimmy">ok</Li_item>
                <Li_item name="sam">yes</Li_item>
            </ul>
            )
    }
}

class Li_item extends Component{
    render(){
        return (
        <li>my name is {this.props.name} &nbsp; and my content is {this.props.children}</li>
            )
    }
}

在进行组件复用时, 重用UI 和写HTML同样, 使用闭合标签,添加属性等等. 不过,这里须要注意一下, 在JSX语法中, class属性须要换成 className(由于内部冲突).
另外, 说起一下上文出席那的两个内容. this.props.xx 和this.props.children

  • this.props.xxx : 是用来得到节点中的属性内容. 好比: name, data-name,data-set等等.

  • this.props.children: 用来获取闭合tag中的内容. 好比: < div>abc< /div> 获取获得为: abc

this.props 在组件复用中,是占很重要的地位的, 能够说,他是parent和children 组件通讯的重要通道, 父组件 赋值, 子组件处理. like:

UI

一般来讲, 写一个总体的UI 有两种方式, 一种是Top-Down, 一种是Bottom-Up. 二者都行, 只是思考的方式不同, 不过通常TD(自顶向下)方式比较广泛些.

若是你想利用循环生成jsx的话, 可使用:

class UL extends Component{
    render(){
        let tasks = [];
        for(var i=1,len=this.props.number;i<=len;i++){
            tasks.push(
                <Li_item key={i} number={i}>list</Li_item>
                )
        }
        return (
            <ul>
                {tasks}
            </ul>
            );
    }
}

但须要注意的是, 你不能直接写为:

return (
    {tasks}
)

若是这样写的话,react是不会让你经过的. 由于他认为你这个是不合法数据, 通常来讲, 不能在第一层里面直接写入: arrar,object 对象.

状态改变

react 提供另一个状态属性-this.state. React 经过改变父组件自己的state, 会致使DOM的从新渲染, 至关于从新调用ReactDOM.render().

have a try

这里, 咱们经过简单的改变, 父组件的state, 来实现节点的重流和重绘.
实现的demo 放在jsFiddler上, 能够参考一下. 这里我只贴精华的demo:

class UI_item extends Component{
    constructor(){
        super();
        this.state={
            origin:true
        }
    }
    render(){
        let number = 5;
        if(!this.state.origin){
            number*=2;
        }
        return (
                <div>
                    <button onClick={()=>{this.doubleNumber()}}></button>
                    <UL number={number}></UL>
                </div>
            );
    }
    doubleNumber(){
        this.setState({
            origin:!this.state.origin
        });
    }
}

上面的代码其实有点绕的. 这里补充几点, 相信看过以后,再回去看代码也就明白了.

  • this.setState({xxx:xxx}): 该方法是父组件的专属方法, 其能够手动的修改state的状态, 来实现状态的更新.

  • this.state: 初始状况下,是在constructor 方法中, 直接设置。 不过, 你也能够放在render 方法中, 这也是没问题的.

  • 事件绑定: React中绑定事件的代码虽然有点奇葩, 但他确实是绑定事件最简洁的办法. 他会在后面的流程中,自动解析事件内容, 而后使用addEventListener进行绑定.

另外, 你新增this.props也是会从新渲染节点的.

结合,上面的this.props 能够大概了解, React 提供的精华架构.

framework

事件绑定解析

React 之因此高性能, 不只在于虚拟DOM的算法, 事件绑定也在必定程度提高性能. 由于React的全部事件都是绑定在document 根元素上.
比较好的绑定方式是,经过函数+bind方法进行绑定的

render(){
        let number = 5;
        if(!this.state.origin){
            number*=2;
        }
        return (
                <div>
                    <button onClick={this.doubleNumber.bind(this)}}></button>
                    <UL number={number}></UL>
                </div>
            );
    }

来看一下,React 提供的事件.
from pro react

event

当心JSX的坑

React 在提出自己的同时, 也提出了JSX语法. 这是为何呢?
咱们能够看一下,React 是如何翻译JSX语法, 你就应该知道为何JSX很受欢迎~

// JSX
<h1>Hello World</h1>

// React 方法调用
React.createElement("h1", null, "Hello World");

当你写出JSX 的时候,React在背后已经帮你解析成对应的方法了. 因此, 这样隐形的API, 为何不用呢?
不过JSX 中有部份内容须要注意一下.

驼峰命名的属性

在JSX中, 给tag添加属性时,须要使用驼峰命令. 即.

// HTML
<input type="text" name="usrname" maxlength="10">

// JSX
<input type="text" name="usrname" maxLength="10"><br>

但像,这样的data-set 使用dash链接的就不须要额外的注意. 另外, react 特别强调了class须要写为className. 由于在React内容,class 存在冲突, 因此强制性将class property改成了className.

标签闭合

很简单, 就是全部标签必须闭合. 好比像<img src="...">这样的, 后面的/ 能够写可不写. 可是, 如今在JSX中,全部的都必须写.

<img src="..." />

only one node

这里,应该是不少初入React 童鞋经常犯的~ 可能对函数的了解还未透彻. 好比一个函数:

function add(){
    return (1,2);
}
add();

上面的结果是多少?
很简单是2. 这是解析引擎所决定的. 由于, 直接经过return 语句返回, 永远只能返回一个值.因此, 这也决定了在React中, 你使用render返回JSX时, 只能带上一个节点.

// 正确
return(
  <h1>Hello World</h1>
)

// go die
return (
   <h1>Hello World</h1>
    <h2>Have a nice day</h2>
 )

改写一下, 你只能返回一个节点:

return (
    <p>
        <h1>Hello World</h1>
        <h2>Have a nice day</h2>
    </p>
 )

don't use if-else

在JSX, 通常不要乱用if-else. 由于if-else 是不会返回任何值的。

// 报错
return (
            <li data-set={if(true){"ok"}}>jimmy</li>
        )

推荐状况是, 使用三元运算(ternary). 由于他能够返回值.

return (
            <li data-set={true?'ok':0}>jimmy</li>
        )

置于为何, 咱们能够在这里剖析一下JSX语法的结构. 前文已经提到了, JSX其实就是React.createElement(). 咱们的属性其实,就是当作createElment参数的

// JSX
<div className={if (condition) { "salutation" }}>Hello JSX</div>

// 翻译
React.createElement("div", {className: if (condition) { "salutation"}}, "Hello JSX");

这里, 有点基本常识的应该知道, 对象里面怎么执行... 除非你有返回值.

空格省略

React在渲染的时候,会默认忽略掉元素间的空格. 估计是考虑到了inline-block 形成的3~4px的影响.

<li >{this.props.children}_{this.props.number}
                <a href="">ok</a>
                <a href="">yes</a>
</li>

这样渲染的结果是

omit space

不过, 若是你仅仅是填写文本的话, 里面的空格就不会被忽略。若是, 你想在元素之间添加上空格的话. 能够这样写:

<li >
                <a href="">ok</a> {" "}
                <a href="">yes</a>
</li>

JSX的评论

在JSX中,写评论的话, 须要注意他的注释方式:

/* comment */

另外,若是你的注释是childElement, 则须要使用{}括起来. 但在元素内部评论的话,就不须要了

<Nav>
    {/* this is a child comment */}
    <Person
/* multi line
         comment */
      name="sam" // end of line comment
/> </Nav>

上面的demo 基本上把全部注释状况都包含了.

动态插入HTML

之前,咱们纯原始写组件的时候, 经常利用的就是element的innerHTML属性. 即, 直接在html tag里面添加string, 而后利用内部渲染,将element渲染出来.

<li>
    {this.dynamicP()}
</li>
// 动态脚本

dynamicP(){
        let p = "<p>123</p>";
        return p;
    }

可是, 这样容易犯的一个错误就是XSS, 由于XSS最经常使用的手段就是动态恶意脚本的插入. 有兴趣的童鞋,能够参考一下个人xss之网页安全.
React考虑到这点, 果断将全部一切插入的String进行转义.
因此, 上面渲染出来的会是这样的:

p

当有时候,咱们又不得不使用动态的String当作HTML插入, 那应该怎么作呢?
官方给出的解决办法是, 使用dangerouslySetInnerHTML这个属性.

<span dangerouslySetInnerHTML={{__html:dynamicP()}} />

这样, React就会对插入的HTML解除XSS的限制.

表单输入

为何说表单输入在React里面也是一块须要注意的呢?
由于, 一旦你设置在input的value属性. 后面你全部的输入都是无效的.

<input type="search" value="React" />

so how to solve it?
这里就须要使用onChange和this.state来帮助咱们进行重绘.

class Search extends Component {
    constructor(){
        super();
        this.state={
            value:"React"
        }
    }
    render() {
        return ( <div>
        Search Term: <input type="search" value={this.state.value} onChange={this.handleChange.bind(this)} /> </div>
        )
    }
    handleChange(event){
        this.setState({
            value:event.target.value
        })
    }
}

经过输入,触发onChange, 而后onChange 触发this.setState, 从新渲染DOM。get~ 线上demo

另外,表单输入,还须要注意另外两个ele. textarea和select.

textArea 在React中, textarea的书写格式和HTML中有些不一样

// HTML
<textarea>This is the description.</textarea>

// React
<textarea value="This is a description." />

该element 也须要绑定onChange时间才行.

select 元素的写法和原始HTML差异不大,只是里面的选取默认的option须要改变一下。 在HTML中, 书写默认的option 只须要添加selected属性便可. 但在React, 则须要手动指定value才行.

<select value="B">
    <option value="A">A</option>
    <option value="B">B</option>
    <option value="C">C</option>
</select>

反模式表单

这里所谓的anti-pattern(反模式) 听起来逼格挺高的. in fact, 他仍是表单. 只是你不用写value属性. 而这里的反模式实际体如今, 你不用绑定onChange事件, 元素中的内容,也能随着用户的输入自动变化.
看个demo:

render() {
        return (
            <form>
                    {/*
                    controled component
                     */}
                <input    type="text" value="fixed" /><br/>
                    {/*
                    uncontroled component
                     */}
                <input type="text" />
            </form>
        );

线上demo请参考: JSfiddle
那 uncontroled component 和 controled component 之间的区别是神马嘞?
简而言之, 若是你的表单须要有不少限制那么就用controled component, 若是没有能够考虑uncontroled.

咱们总结一下:

JSX

内部属性trick

key的使用

React 以他Virtual DOM 而闻名遐迩, 经过造出一个Virtual DOM, 而后, 经过一种比较算法,得出最新的DOM结构, 从而让页面性能损耗降到最低. 如今咱们考虑一种状况.
即, 渲染重复的list.即:

return (
            <ul>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
            </ul>
        );

当其中的几个节点须要变为:

<ul>
                <li></li>
                <li></li>
                <li>1</li>
                <li></li>
                <li>2</li>
                <li></li>
            </ul>

React会怎么作... 他首先会提示你, 孩纸, 你这样不行... 由于, 这样的实现方法是在是太多了. CRUD 哪种均可以实现上述行为. 因此,React须要你手动的设置一个key值,来帮助他标识, 你改动的list是哪个~
上面的render咱们就须要改成:

render() {
        let lis = [];
        for(var i=0;i<4;i++){
            lis.push((
            <li key={i} >{i}</li>
            ))
        }
        return (
            <ul>
                {lis}
            </ul>
        );
    }

谨慎的refs

refs 其实是一种,黑魔法,又能够称为语法糖. 由于他不须要咱们手动的使用document.getElementxxx 来获取节点. 他已经帮你把dirty work 给干好了. 咱们只须要使用this.refs.xx 来获取指定节点便可. 可是, 官方是不提倡这种作法的,由于这样破坏了数据的流向性. React原本是用过render, 来改变元素的状态, 可是, 若是从外面使用this.refs 改变 DOM的话, 有可能会形成virtual DOM和actual DOM不统一的状况.
若是你真的想用的话, 那就须要使用ref了, 这样至少可能保证DOM状态的统一. 能够说, 在React中,你基本上能够和document.xxx系列说拜拜了.

constructor(){
        super();
        this.number = 0;
    }
    render() {
        return(
            <div>
                <button onClick={this.clickButton.bind(this)}>click me</button>
                <span ref="text">I will be changed</span>
            </div>
            )
    }
    clickButton(){
        let text = this.refs.text;
        text.innerHTML = this.number++;
    }

注意一下, 属性书写是用ref, 获取是使用refs. 线上demo, 参考:JSfiddle

相关文章
相关标签/搜索