React

头像
alogy
    阅读 22 分钟
    2

    React简介

    FeceBook开源的一套框架,专注于MVC的视图V模块。实质是对V视图的一种实现。

    React框架的设计没有过分依赖于某个环境,它自建一套环境,就是virtual DOM(虚拟DOM)。

    提供基础API:创建元素,渲染元素。

    React的独特之处:

    组件的组合模式单向数据流的设计(Date Flow)高效的性能(Virtual DOM)分离的设计

    React的核心思想:封装组件,各个组件维护自己的状态和 UI, 当状态变更,自动重新渲染整个组件。

    浏览器环境中渲染

    <script src="lib/react.js" type="text/javascript" charset="utf-8"></script>
    <script src="lib/react-dom.js" type="text/javascript" charset="utf-8"></script>
    

    react.js: 构建虚拟DOM, React.createElement(); React核心库,在应用中必须先加载核心库。
    react-dom.js: 将虚拟DOM渲染页面中,ReactDOM.render(); DOM渲染器,React将核心库和渲染器分离,目的:在Web页面中显示开发的组件。

    JSX

    JSX是React自定义的语法,最终JSX会转化为JS运行与页面当中

    组件

    组件是React中核心概念,页面当中的所有元素都通过React组件来表达,将要写的React代码绝大部分都是在做React组件的开发。

    组合模式: 组合模式又称之为:部分-整体模式。使树形结构的问题中,模式了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂的元素,从而使得客户程序与复杂元素的内部结构解耦。

    无论是应用等级还是一个表单亦或是一个按钮,都视为一个组件。然后基于组件的组合构建整个应用。

    clipboard.png

    组合模式优点:

    • 构建可以重用的组件:组件的开发能够形成公司的组件,每个业务的开发都能积累课重用的组件。

    • JSX语法

    • 具有弹性的架构: 能够构建简单的页面也能构建大型的前端应用。

    • 维护性高。

    VIRTUAL DOM

    React抽象出来的虚拟DOM树,虚拟树是React高性能的关键。(让需要改变的元素才去重新渲染)

    单项数据流

    单项数据流:one-way reactive data flow

    React应用的核心设计模式,数据流向自顶向下。

    页面的UI和数据的对应是唯一的。

    基础API

    createElement

    React.createElement();

    创建虚拟DOM

    参数1:元素名称, 例如: div,p, h1
    参数2:属性集合,例如:title,calssName,id,style
    从参数3开始,表示该元素的子元素,通常这些元素通过createElement();创建, (文本文件可以直接插入)

    let ul = React.createElement('ul', {
        
        'title': '嘻嘻哈哈'
        
    },'这是');
    

    render

    ReactDOM.render();
    DOM渲染器,将元素渲染到页面中。

    参数1:虚拟DOM元素
    参数2:HTML的容器元素。

    ReactDOM.render(ul, document.querySelector('.app'));
    

    示例:

    
    <script src="lib/react.js" type="text/javascript" charset="utf-8"></script>
    <script src="lib/react-dom.js" type="text/javascript" charset="utf-8"></script>
    
    
    <script type="text/javascript">
        
        'use strict';
        
        let ul = React.createElement('ul', {
            
            'title': '嘻嘻哈哈'
            
        },'这是');
        
        
        ReactDOM.render(ul, document.querySelector('.app'));
        
    </script>
    
    

    crateClass

    React.createClass();
    定义组件

    参数:配置对象。
    对象中可以添加任何方法,但一些属性,方法是特殊的。

    render: 组件中渲染输出的虚拟DOM元素。

    
    // component
    let Uls = React.createClass({
        render: function () {
            
            return React.createElement(
                'ul',
                null,
                React.createElement(
                    'li',
                    null,
                    'a'
                ),
                React.createElement(
                    'li',
                    null,
                    'b'
                ),
                React.createElement(
                    'li',
                    null,
                    'c'
                )
            )
            
        }
    });
    
    // 组件变成虚拟DOM
    let ul = React.createElement(Uls, null);
    
    // 渲染页面
    ReactDOM.render(ul, document.querySelector('.app'));
    

    JSX语法

    创建JSX语法的本质:使用基于XML的方式表达组件嵌套,保持和HTML一致的结构。最终所有的JSX都会编译为原生JavaScript

    嵌套规则:标签可以任意嵌套。标签闭合,必须严格闭合,否则无法编译通过。

    编译JSX语法:
    工程化工具:fis-parse-babel2

    
    fis.match('**.jsx', {
        parser: fis.plugin('babel2'),
        rExt: '.js'
    });
    
    
    // 渲染HTML内部的JSX语法
    
    fis.match('**.html:jsx', {
        parser: fis.plugin('babel2')
    });
    

    JSX示例:

    
    // 创建组件
    let Uls = React.createClass({
        render: function () {
            return (
                <ul>
                    <li>a</li>
                    <li>b</li>
                    <li>c</li>
                </ul>
            );
        }
    });
    
    
    // 渲染组件成 虚拟DOM
    let ul = (<Uls></Uls>);
    
    // 渲染页面中
    ReactDOM.render(ul, document.querySelector('.app'));
    

    HTML内部JSX语法

    
    <div class="app"></div>
    
    <script src="lib/react.js" type="text/javascript" charset="utf-8"></script>
    <script src="lib/react-dom.js" type="text/javascript" charset="utf-8"></script>
    
    <script type="text/x-jsx">
        
        let div = (
            <div id="red">
                JSX
            </div>
        );
        
        ReactDOM.render(div, document.querySelector('.app'));
        
    </script>
    

    组件大致分类

    • APP 组件: 整个页面的最完整组件

    • Header 组件: 头部输入组件

    • TodoList组件: 列表组件

    • TodoItem 组件: 列表项

    • Footer 组件: 底部操作组件

    虚拟DOM属性

    为虚拟DOM添加属性,传递属性的方式和HTML相同。

    属性可以是字符串,也可以是任意的JavaScrip变量。需要使用插值方式解析变量。

    特殊属性:
    class,要使用成className
    for, 要使用成htmlFor

    // 创建组件
    let Uls = React.createClass({
        render: function () {
            return (
                <ul className="listNone">
                    <li>a</li>
                    <li>b</li>
                    <li>c</li>
                </ul>
            );
        }
    });
    

    对HTML组件

    fuunction render () {
        return <p title={tit}>Hello</p>
    }
    

    React自定义组件

    fuunction render () {
        return <p><CustomComponent></CustomComponent></p>
    }
    

    JSX花括号

    插值形式,动态的改变虚拟DOM中属性值,或者内容,或使用JavaScript表达式,做简单的运算。

    语法: {表达式}

      
    'use strict';
    
    // Component
    let Header = React.createClass({
        render: function () {
            
            let userName = 'cyan';
            let date = new Date();
            
            return (
                <div className="header">
                    <div className="inner">
                        <div className="left">
                            <span>{userName}</span>
                            &emsp;
                            <span>{date.getHours() > 12 ? '下午' : '上午'}</span>    
                        </div>
                    </div>
                </div>    
            );
        }
    });
    
    // 渲染
    ReactDOM.render(<Header />, document.querySelector('.app'));
    

    JSX注释

    let Header = React.createClass({
        render: function () {
            {/* 这里是注释 */}
        }
    });
    

    Component

    props属性

    组件中特殊属性:props
    作用:获取组件上添加的属性。

    设置默认的属性,通过getDefaultProps()来设置,是React内置方法名,在自定义方法的时候,不能重写。

    • this.props : 获取属性值

    • geetDefaultProps(); : 获取默认属性对象,会被调用一次,当组件类创建的时候会被调用,返回值会被缓存起来,当组件被实例化过后如果传入的属性没有值,会返回默认值属性值。

    • this.props.children : 子节点属性

    • propTypes : 属性类型检查

    一般的,props规定是只能读取,应该禁止被修改。
    原因: React 不能帮检查属性类型(propTypes),修改props对象可能会导致预料之外的结果。

    属性数据的单项性

    React的单项数据流模式,数据的流动管道就是 props,流动的方向就组件的层级自顶向下的方向。所以一个组件是不能修改自身的属性,组件的属性一定是通过父组件传递而来(或默认属性)

    'use strict';
    
    // Component
    let Prat = React.createClass({
        
        getDefaultProps: function () {
            return {
                title: ['默认标题']
            }
        },
        
        createLi: function () {
            
            return this.props.title.map( ( val, idx ) => {
                return (<li key={idx} >{ val }</li>);
            } );
            
        },
        
        render: function () {
            
    //                    console.log( this.props.children );
            
    //                    console.log( this.props );
            return (
                <div className="part">
                    <ul className="header">
                        {this.createLi()}
                    </ul>
                </div>
            );
            
        }
        
    });
    
    // 渲染
    ReactDOM.render(<Prat />, document.querySelector('.app'));
    ReactDOM.render(<Prat title={['新闻', '今日话题']} />, document.querySelector('.app1'));
    

    style

    设置style的样式

    • 普通的CSS样式, 遵循驼峰式命名规则

    • CSS3样式,遵循大驼峰式命名规则

    注意:样式并不能像HTML行内一样,需要使用插值方式,插值中使用对象。

    
    'use strict';
    
    // Componedt
    let Style = React.createClass({
        
        render: function () {
            
            let sty = {
                color: 'red',
                border: '1px solid #000',
                borderBottom: '2px solid tan'
            }
            
            return (
                <h1 style={sty}>
                    title
                    <h1 style={{'background': 'tan' }}>titile2</h1>
                </h1>
            );
            
        }
        
    });
    
    // 渲染
    ReactDOM.render(<Style />, document.querySelector('.app'));
    

    Event

    React中为虚拟DOM添加事件与HTML为DOM添加事件一样: <div onClick="fn"></div>

    一般的为React添加的DOM事件,并不要字符串,需要使用插值符号为虚拟DOM添加事件回调函数。

    
    // Componedt
    let Style = React.createClass({
        
        changeContent: function ( ev ) {
            
            ev.target.innerHTML = '修改后的文案';
            
        },
        
        render: function () {
            
            let sty = {
                color: 'red',
                border: '1px solid #000',
                borderBottom: '2px solid tan'
            }
            
            return (
                <div style={sty}>
                    title
                    <h1 style={{'background': 'tan' }} onClick={this.changeContent}>titile2</h1>
                </div>
            );
            
        }
        
    });
    
    // 渲染
    ReactDOM.render(<Style />, document.querySelector('.app'));
    

    state状态

    无状态组件属性

    对于无状态组件,可以添加 .propTypes 和 .defaultProps 属性到函数上。

    如果一个在渲染页面之后组件不会变化,可以通过props就可以实现对组件的样式设置以及行为渲染,此时组件不会收到外界的影响,组件是一成不变的,这类组件叫做: 无状态satateless组件.

    state

    对于大部分的组件来说,通常是要通与外界交流,此时组件要处于不同的状态,此时的组件就要有状态,对于组件内部的状态控制,可以通过state属性控制.

    state属性: 控制组件的内部状态.

    getInitialState() : 初始化状态,
    返回一个对象,或者数据,指代的就是 state

    setState() : 设置状态
    参数:设置的值

    state每次更新都会触发一次render() 方法.
    state一般的都是内部自定义方法来控制改变其状态.

    
    // 创建 Component
    let Dom = React.createClass({
        
        getInitialState: function () {
            
            return {
                index: 0,
                txt: '嘻嘻哈哈'
            }
            
        },
        
        render: function () {
            
    //                    console.log( this.state );
            
            return (
                <div>
                    <button onClick={this.clickContent}>点击显示内容</button>
                    <p>{this.state.txt}</p>
                </div>
            );
            
        },
        
        clickContent: function () {
            
            this.setState({
                txt: '么么哒'
            });
            
        }
        
    });
    
    // 渲染组件
    ReactDOM.render(<Dom />, document.querySelector('.app'));
    
    

    Component生命周期

    clipboard.png

    生命周期的方法都是在调用 React.createClass(); 的参数配置对象传入.

    组件规格

    mixins

    mixins: React的插件列表。通过这种模式在不同组件之间共享方法数据或者行为只需共享mixin即可。
    mixins内定义的生命周期方法在组件的生命周期内都会被调用

    statics

    statics : 定义组件的类方法。

    
    // Component
    let oDiv = React.createClass({
        
        // 定义组件类方法
        statics: {
            statisMethod: () => {
                return true;
            }
        },
        // Class 分为类方法和实例方法, 实例方法可以访问this,而类方法不能。
        // 不能在Class中返回状态或者属性。
        
        render: function () {
            return (
                <div>嘻嘻哈哈</div>
            );
        }
    });
    
    // 渲染组件
    ReactDOM.render(<oDiv />, document.querySelector('.app'));
    

    displayName

    displayName : 组件的名称,JSX在转为JavaScript的时候自动设置displayName。 也可以手动设置。

    组件生命周期方法

    整个组件的生命周期,包含:

    • 组件被实例化

    • 组件属性改变

    • 组件状态被改变

    • 组件被销毁

    clipboard.png

    组件实例化

    • getDefaultProps() : 设置组件的属性(props属性)

    • getInitialSate() : 设置初始化状态(state)

    • componentWillMount() : 组件即将被创建

    • render() : 渲染输出虚拟DOM

    • componentDidMount() : 组件构建完成

    componentWillMount()
    条件: 第一次渲染阶段在调用render方法前会被调用
    作用: 该方法在整个生命组件只会被调用一次,可以利用该方法做一些组件内部的初始化工作。

    componentDidMount();
    条件: 第一次渲染成功后,组件对应的DOM已经添加到页面后调用.
    作用: 这个阶段表示组件对应的DOM已经存在,可以在这个时候做一些依赖DOM的操作,或者其他一些, 例如:请求数据,和第三方库整合的操作。
    如果嵌套了子组件,子组件会比父组件优先渲染,所以这个时候可以获取子组件对应的DOM。

    
    // Component
    let GoBack = React.createClass({
        
        getDefaultProps: function () {
            
            console.log(111);
            
            return {
                title: ''
            }
            
        },
        
        getInitialState: function () {
            console.log(222);
            
            return {
                sateteTitle: this.props.title
            }
            
        },
        
        componentWillMount: function () {
            
            console.log(333,this.satate, this.props);
            
        },
        
        render: function () {
            
            console.log(444);
            return (<div className="go-back">返回顶部</div>);
            
        },
        
        componentDidMount: function () {
            
            console.log(555);
            
            const _this = this;
            
            setTimeout(() => {
                
                _this.setState({
                    stateTitle: '修改后title'
                });
                
            }, 1000);
            
        }
        
    });
    
    // 渲染 
    ReactDOM.render(<GoBack />, document.querySelector('.app') );
    

    在未初始化props之前,无法使用this.props.xxx

    组件存在期

    一旦组件被创建,那么就进入了组件的存在期,在存在期中,每次组件更新的时候,会进入新的5个阶段.

    • componentWillReceivePros() : 表示组件将要接收新的属性.

    • shouldComponentUpdate() : 组件是否应该更新.

    • componentWillUpdate() : 组件将要被更新

    • render() : 重新渲染组件

    • componentDidUpdate() : 组件已经被更新

    componentWillReceivePros(newProps);
    条件:当组件获取新属性的时候, 第一次渲染不会调用.
    用处:这个时候可以根据新的属性来修改组件的状态

    获取新的属性,但并不能确定属性一定改变了,例如: 一个组件被多次渲染到DOM中.

    shouldComponentUpdate()
    参数1:nextprops 下一个属性
    参数2: nextstate 下一个状态
    返回:返回布尔值,true表示更新组件,false表示不要对组件进行更新,后面阶段不会执行.

    条件:接收到新属性或新状态的时候在render前 会被调用(除了调用forceUpdate 和 初始化渲染以外)
    用处:有机会绝对是否重新渲染组件。可以优化应用性能(在多组件的情况中)

    componentWillUpdate()
    参数1: nextProps 下一个属性
    参数2:nextState 下一个状态

    条件: 当组件确定要更新,在render()之前被调用.
    用处:可以确定一定会更新组件,可以执行更新前做一些操作。
    这个方法中不能使用 setState(); setState();的操作应该是在componentWillReceiveProps();方法中调用.

    componentDidUpdate()
    参数1:prevProps 前一个属性
    参数2:prevState 前一个状态

    条件:更新被应用到DOM之后
    用处:可以执行组件更新之后的操作。

    存在期中的方法,在组件第一次渲染的时候,不会执行,componentWillReceiveProps();方法在组件内部状态更新的是不会被调用.

    销毁期

    组件生命周期的最后个阶段,到了这个阶段,也就是说,组件要被销毁了。

    componentWillUnmount()
    组件即将在DOM树中删除
    条件:组件销毁的时候执行

    生命周期与单项数据流

    React的核心模式是单项数据流。在组件内部的生命周期中也是符合单项数据的模式。数据从组件的属性流入,再结合组件的状态,流入生命周期的方法,直到渲染结束,都应该是一个单向的过程,其间不能随意改变组件的状态。

    子组件

    子组件: 在组件内部使用其它组件的时候,组件被嵌套该组件中,作为子组件使用.

    作为一个父组件的子组件,可以通过属性传递数据信息,直接在父组件中,对子组件添加属性.
    React是单项数据流,只能从父组件中的信息,传递给子组件.

    注意:渲染组件的时候,只需要渲染父组件即可.

    父组件传递数据信息给子组件方法:

    1: 通过属性传递数据信息,直接在父组件中对子组件添加属性信息。

    let Main = React.createCalss({
        
        render: function () {
            
            return (
                <div className="main">
                    {/* 子组件 */}
                    <GoBack title="返回组件title"/>
                </div>
            );
            
        }
        
    });
    // 缺点: 父组件向子组件中传递数据的时候,是固定的,当父组件更新的时候,没拌饭更新子组件的属性.
    

    2: 通过父组件的属性 {props}。 将父组件内部的数据传递子组件中.

    
    let Main = React.createClass({
        
        getDefaultProps: function () {
            
            return {
                title: ''
            }
            
        },
        
        render: function () {
            
            return (
                <div className="main">
                {/* 子组件 */}
                    <GoBack title={this.props.title} />
                </div>
            );
            
        }
        
    });
    

    3: 通过父组件的状态 {state}。 将父组件内部的数据传递子组件中.

    let Main = React.createClass({
        
        getDefaultProps: function () {
            
            return {
                title: ''
            }
            
        },
        
        getInitialState: function () {
            
            return {
                title: '么么哒'
            }
            
        },
        
        render: function () {
            
            return (
                <div className="main">
                    {/* 子组件 */}
                    <GoBack title={this.state.title} />
                </div>
            );
            
        }
        
    });
    
    

    组件的作用域,与JavaScript变量的作用域机制一样.

    子组件会寻找自身的prop属性,state状态。然后寻找父组件的prop属性,state状态。

    兄弟组件的信息传递

    每个组件都有自己的完整空间,彼此之间没有联系,如何实现兄弟组件之间的通信。

    父组件和子组件通信,可以通过设置子组件的属性: 传递固定值,属性值,状态值,还可以传递方法或者函数。

    注意: 传递方法或者函数时:事件对象是组建绑定的元素。this指向父组件。

    子组件向父组件传递消息,可以通过父组件为子组件添加函数,子组件通过调用该函数,传递参数数据来实现。

    
    // InputMsg Component
    const InputMsg = React.createClass({
        
        render: function () {
            
    //                    console.log( this.props.changeMsg() );
            
            return (
                <div>
                    <input type="text" onChange={this.props.changeMsg} />
                </div>
            );
        }
        
    });
    
    // App Component
    const App = React.createClass({
        
        getInitialState: function () {
        
            return {
                msg: 'world'
            }
        
        },
        
        render: function () {
            
            return (
                <div className="mian">
                    {/* 父组件传递方法 */}
                    <InputMsg changeMsg={this.changeMsg} />
                </div>
            );
            
        },
        
        changeMsg: function ( ev ) {
    //                    
            let vals = ev.target.value;
            
            console.log( vals );    
    //                    console.log( ev );
    //                    console.log( this );
            
        }
        
    });
    
    // render
    ReactDOM.render(<App />, document.querySelector('.app')); 
    

    兄弟组件之间的通讯,需要通过它们共同的父组件的state或者props来实现。
    一般的,通过父组件的state来实现.

    
    'use strict';
    
    // 实现 组件之间的  双向数据绑定
    
    // InputMsg Component
    const InputMsg = React.createClass({
        
        render: function () {
            
    //                    console.log( this.props.changeMsg() );
            
            return (
                <div>
                    <input type="text" onChange={this.props.changeMsg} />
                </div>
            );
        }
        
    });
    
    // ShowMsg Component
    const ShowMsg = React.createClass({
        
        getDefaultProps: function () {
            return {
                msg: '嘻嘻哈哈' 
            }
        },
        
        render: function () {
            return (
                <div>
                    <p>{ this.props.msg }</p>
                </div>
            );
        }
        
    });
    
    // App Component
    const App = React.createClass({
        
        getInitialState: function () {
        
            return {
                msg: 'world'
            }
        
        },
        
        render: function () {
            
            return (
                <div className="mian">
                    <InputMsg changeMsg={this.changeMsg} />
                    <ShowMsg msg={this.state.msg} />
                </div>
            );
            
        },
        
        changeMsg: function ( ev ) {
            
            let vals = ev.target.value;
            
            this.setState({
                msg: vals
            });
            
        }
        
    });
    
    // render
    ReactDOM.render(<App />, document.querySelector('.app')); 
    

    4,子组件传递信息给父组件

    子组件向父组件传递消息,可以通过父组件为子组件添加函数实现,子组件通过调用该方法,并通过处理之后的数据用参数形式传递给父组件来完成。

    父组件定义方法,子组件调用方法

    事件处理与合成事件

    React只需把事件处理器,以驼峰命名形式当作组件props传入。就像是用普通HTML事件一样。
    React内部创建一套合成事件系统来使所有在IE8和以上浏览器表现一致,也就是说,React懂得处理冒泡和捕获事件,事件对象的参数与W3C规范一致。

    需要在手机或平板等触摸设备上使用React,在React版本0.14自动开启触屏事件。

    findAllInRenderedTree

    自动绑定和事件代理

    AutoBinding: 在JavaScript里创建回调函数的时候,保证this的正确性,一般都需要显示的绑定方法到它的实力上, React所有方法被自动绑定到它的组件实例上。

    事件代理: React并没有把时间处理器绑定到节点本省。当React启动的时候,它在最外层使用一个唯一的事件监听器处理所有时间。当组件被加载和销毁时,只是在内部映射里添加或删除事件处理器。当事件触发,React根据映射来决定如何分发。当映射里处理器时,会当作空操作处理。

    组件其实是状态机

    React 把用户界面当作简单状态机。把用户界面想象成拥有不同状态然后渲染这些状态,可以轻松让用户界面与数据保持一致。

    React中,只需要更新组件的state,然后根据新的state重新渲染用户界面(不要操作DOM)。React来决定如何最高效的更新DOM。

    state工作原理

    常用的通知React数据变化的方法时调用 setState(data, callback); 这个方法会合并(merge) data 到 this.state ,并重新渲染组件。渲染完成后,调用可选的callback回调。大部分情况下不需要提供callback,因为React会负责把界面更新到最新的状态。

    哪些组件应该有State

    大部分组件的工作应该是冲 props 里面 取出数据并渲染。但是,有时候需要和用户俗话如,服务器请求数据,或者时间变化等做出相应,这时才需使用State。

    尝试把尽可能多的组件无状态化这样做能隔离state , 作用: 把它放到最合理的地方,也能减少冗余,同时易于解释程序运作过程。

    常用的模式是:创建多个只负责渲染数据的无状态组件,在它们的上层创建一个有状态的组件并把它的状态通过props传给子级。这个有状态的组件封装了所有用户的交互逻辑,而这些无状态组件负责声明式的渲染数据。

    哪些应该作为State

    state应该包括那些可能被组件的事件处理器改变并触发用户界面更新的数据。真实的应用中这种数据一般都很小且能被JSON序列化。当创建一个状态化的组件时,想象一下表示它的状态最少需要哪些数据,并只会把这些数据存入 this.state。在render() 里再根据state来计算需要的其它数据。
    如果在state里添加冗余数据或计锁的数据,需要经常手动保持数据不同步,不能让React来帮助处理。

    • 用户相关

    • 后台数据

    • 事件需要的数据

    哪些不应该作为 State

    this.state 应该仅包括能够表示用户界面状态所需的最少数据。 不应该包括state:

    • 计算所得数据: 不要担心state 来预先计算数据 -- 把所有的计算都放在render() 里面更容易保证用户界面和数据的一致性。

    • React组件: 在render()里使用当前 props和state 来创建它。

    • 基于props的重复数据: 尽可能的使用props来作为唯一数据源。把props保存到state的一个有效的场景是需要知道它以前的值的时候,因为未来的props可能会变化。

    React与DOM

    获取DOM元素

    第一种方式:
    对于表单使用:ref="names" 来定义表单中的属性

    获取使用: this.refs.names
    作用:一般使用获取表单元素中的值

    第二种方式:
    findDOMNode();
    参数:组件实例。

    一般在组件实例化完成阶段使用componentDidMount
    获取整个实例化后的真实DOM

    注意:不能使用在无状态组件上.

        
    const Checkbox = React.createClass({
        
        getInitialState: function () {
            
            return {
                cb1: false,
                cb2: false
            }
            
        },
        
        render: function () {
            
            return (
                
                <div>
                    <button onClick={this.showReslut}>结果</button>
                    <input ref="cb1" type="checkbox" defaultChecked="true" onChange={this.change} />篮球
                    <input ref="cb2" type="checkbox" />足球
                </div>
                
            );
            
        },
        
        componentDidMount: function () {
            
            let dom = ReactDOM.findDOMNode(this);
            
            let inps = ReactDOM.findDOMNode( this.refs.cb1 );
            // 获取 this.refs.cb1 的 所在DOM,并不能传入 this.refs。
            
        },
        
        showReslut: function () {
            
            console.log( this.refs.cb1.checked, this.refs.cb2.checked );
            
        },
        
        change: function ( ev ) {
            
            let cheVals = ev.target.checked;
            
            this.setState({
                'cb1': cheVals 
            });
            
        }
        
    });
    
    // render
    ReactDOM.render(<Checkbox />, document.querySelector('.app'));
    

    非元素属性

    非元素属性: 不是DOM元素原生就有的属性。(例如:自定义属性,React提供的特殊属性,ref等)

    
    'use strict';
    
    let Search = React.createClass({
        render: function () {
            
            // 模拟搜索之后文案显示
            let content = {
                __html: '<span style="color: cyan">搜索结果,么么哒</span>'
            }
            
            return (
                <div className="search-grpup">
                    <input ref="serachInput" type="text" />
                    <button onClick={this.clickSearch}>搜索</button>
                    <span dangerouslySetInnerHTML={content}></span>    
                    {/* 使用行内式的样式,需要通过 dangerouslySetInnerHTML属性设置 */}
                </div>
            );
        },
        clickSearch: function ( ev ) {
            
            let vals = this.refs.serachInput.value;
            
            console.log(vals);
            
        }
    });
    
    // 渲染
    ReactDOM.render(<Search />, document.querySelector('.app'));
    

    key: 列表中元素的ID。通过设置key是的每个列表元素获取ID
    ref : 获取表单或组件内部的元素的 文本节点,value值
    dangerouslySetInnerHTML : 设置元素的内容,该属性对应的值为一个对象, 对象中是React定义的: __html属性对应值,会渲染到元素中. (对应值:可以是文本节点,标签节点);

    定义:

    let content = {
        __html: '<span style="color: cyan">搜索结果,么么哒</span>'
    }

    使用:

    <span dangerouslySetInnerHTML={content}></span>    
    

    约束性组件和非约束性组件

    约束性组件:状态是交由组件自身管理(state是通过初始化,自定义方法设置状态)
    非约束性组件:状态是交由元素自身管理

    一般的,约束性组件与非约束性组件是对表单元素而言的。

    非约束性组件

    非约束性组件,表单值与是由用户输入。

    
    'use strict';
    
    // Component
    const Search = React.createClass({
        
        clickBtn: function ( ev ) {
            
            let vals = this.refs.serchInput.value;
            
            console.log(vals);                    
            
        },
        
        render: function () {
            return (
                <div className="serach">
                    <div className="serach-logo">
                        {/* <input ref="serchInput" type="text" placeholder="用户输入的内容" /> */}
                        <input ref="serchInput" type="text" defaultValue="用户输入的内容" />
                        <button onClick={this.clickBtn}>搜索</button>
                    </div>
                </div>
            );
        }
        
    });
    
    // render
    ReactDOM.render(<Search />, document.querySelector('.app'));
    

    placeholder与defaultValue的区别:
    placeholder与defaultValue都是显示文案,defaultValue在编译后会变成value值

    获取表单内的内容需要设置ref="names",获取需要:this.refs.names。
    这种方式,元素的状态信息保存在元素本身,因此它是一种非约束性组件.

    约束性组件

    表单元素的value值交给组件的state管理,称之为: 约束性组件。
    当表单元素改变的时候,可以通过onChange()事件来获取,显性修改state,通过state来渲染新的input的value值。

    优点:元素的值交由组件管理,表单验证更加灵活。

    
    'use strict';
    
    const Search = React.createClass({ 
        
        getInitialState: function () {
            
            return {
                inp: '默认状态',
                txt: ''
            }
            
        },
        
        render: function () {
            return (
                <div className="search">
                    <div className="search-group">
                        <input type="text" placeholder={this.state.inp} onChange={this.inpChange} />
                        <button>百度一下</button>
                        <span>{this.state.txt}</span>
                    </div>
                </div>
            );
        },
        
        inpChange: function ( ev ) {
            
            let vals = ev.target.value;
            
            if ( vals.length > 10  ) {
                
                this.setState({
                    inp: vals,
                    txt: '不能超过10个字符'
                });
                
            }
            
        }
    });
    
    // 渲染
    ReactDOM.render(<Search />, document.querySelector('.app'));
    
    

    几种约束性组件

    select
    通过value,或者defaultValue值来控制.

    
    'use strict';
    
    const  Select = React.createClass({
        
        // 初始化 状态
        getInitialState: function () {
            
            return {
                selectValue: ''
            }
            
        },
        
        render: function () {
            
            return (
                <div>
                    <select defaultValue={this.state.selectValue} onChange={this.changeSelect}>
                        <option value="cyan">cyan</option>
                        <option value="tan">tan</option>
                        <option value="khaki">khaki</option>
                    </select>
                    <span></span>
                </div>
            );
            
        },
        
        changeSelect: function ( ev ) {
            
            let vals = ev.target.value;
            
            this.setState({
                selectValue: vals
            });
            
        }
        
    });
    
    // render    
    ReactDOM.render(<Select />, document.querySelector('.app'));
    
    

    如果使用ref来获取表单元素中的内容,使用default加前缀,例如: defaultValue,defaultChecked. 。通过refs来获取值

    
    
    'use strict';
    
    const Checkbox = React.createClass({
        
        getInitialState: function () {
            
            return {
                cb1: false,
                cb2: false
            }
            
        },
        
        render: function () {
            
            return (
                
                <div>
                    <button onClick={this.showReslut}>结果</button>
                    <input ref="cb1" type="checkbox" defaultChecked="true" onChange={this.change} />篮球
                    <input ref="cb2" type="checkbox" />足球
                </div>
                
            );
            
        },
        
        showReslut: function () {
            
            console.log( this.refs.cb1.checked, this.refs.cb2.checked );
            
        },
        
        change: function ( ev ) {
            
            let cheVals = ev.target.checked;
            
            this.setState({
                'cb1': cheVals 
            });
            
        }
        
    });
    
    // render
    ReactDOM.render(<Checkbox />, document.querySelector('.app'));
    

    与其它库一起使用

    侵入式插件

    并不一定是使用React的组件的生命周期事件

    需要在componentDidMountcomponentDidUnUpdate 放置其它库的逻辑代码.

    也可以这种方式来绑定事件监听,甚至事件流

    混合

    React支持混合, 将混合中的方法赋值到组件对象上。组件对象可以使用混合中定义的方法。

    一般是自定义方法,放置mixin中。

    使用混合,值是一个数组,复制多个对象上面的属性和方法。混合可以看做是一种多继承。

    定义:

    let MixinMethod = {}
    

    使用:

    mixins: [MixinMethod]
    
    

    Airbnb React

    基本规则

    • 每个文件只包含一个React组件
      但是 无状态,或者Pure组件允许一个文件包含多个组件。

    • 始终使用JSX语法

    • 不要使用React.createElement方法,除非初始化app的文件不是JSX格式.

    • 一个组件实现一个功能。

    • 组件的生命周期方法按照排序编写

    React组件的内部方法命名不要使用下划线前缀。

    命名

    扩展名: React组件使用.jsx扩展名
    文件名:文件名使用帕斯卡命名。 例如: ReservationCard.jsx
    引用命名:React组件使用帕斯卡命名,引用实例采用骆驼命名

    
    import reservationCard from './ReservationCard';
    
    const ReservationItem = <ReservationCard />
    

    组件命名: 组件名称应该和文件名一致。 例如:Reservation.jsx 中 有一个Reservation 的引用名称。但是,如果是在目录中的组件,应该使用 index.jex作为文件名并且使用文件夹名称作为组件名.


    alogy
    1.3k 声望119 粉丝

    // Designer and Developer


    « 上一篇
    ECMAScript6
    下一篇 »
    Webpack