精益 React 学习指南 (Lean React)- 1.3 React 组件

书本完全目次

1.3 React 组件

《精益 React 学习指南 (Lean React)- 1.3 React 组件》

1.3.1 React 组件引见

在 React 中组件是第一元素,是 React 的基本,一个 React 运用就是基于 React 组件的组合而成。
前面的 JSX 演习事后,人人应当对 React 组件不陌生了,在这一节我们将复习以及深切进修 React 组件。

1.3.2 建立一个 React 组件

建立一个 React 组件的要领为,挪用 React.createClass 要领,传入的参数为一个对象,对象必需定义一个 render 要领,render 要领返回值为组件的衬着构造,也可以理解为一个组件实例(React.createElement 工场要领的返回值),返回值有且只能为一个组件实例,或许返回 null/false,当返回值为 null/false 的时刻,React 内部经由历程 <noscript/> 标签替代。

eg:

    var MyComponent = React.createClass({
        render: function() {
            return <p>....</p>;
        }
    });

组件定名空间

可以看出 React.createClass 天生的组件类为一个 Javascript 对象。 当我们想设置定名空间组件时,可以在组件下面增添子组件:

eg:

    MyComponent.SubComponent = React.createClass({...});
    MyComponent.SubComponent.Sub = React.createClass({....});

在组件较多的情况下,可以借助定名空间优化组件保护构造以及处理组件称号争执题目。

无状况组件

除了可以经由历程 React.createClass 来建立组件之外,组件也可以经由历程一个一般的函数定义,函数的返回值为组件衬着的效果。

eg:

    function StatelessComponent(props) {
        return  <div> Hello {props.name} </div>
    }

无状况组件可以优化机能,由于其内部不会保护状况,React 内部不会有一个对应的组件实例,而且也没有生命周期 hook。

1.3.3 将组件衬着到 DOM 中

当建立好了组件事后,为了将组件衬着到 DOM 中显示出来,须要两个步骤

  1. 在 HTML 中定义一个元素,设置 id 属性

  2. JSX 中挪用 ReactDOM.render 要领, 第一个参数为 组件,第二个为适才定义的 DOM 元素

eg:

<!-- 定义的 DOM 元素 -->
<div id="example"></div>
<script type="text/babel">
    // 自定义组件 
    var MyComponent = React.createClass({
        render: function() {
            return <p>....</p>;
        }
    });
    // 挪用 render 要领
    ReactDOM.render(
    <MyComponent/>,
    document.getElementById('example')
    );
</script>

关于组件的衬着,能够涉及到的一些题目:

  • Q1: 只能 render 到一个元素吗?

  • Q2: 在顺序运行时可以动态的挪用 render 吗?

  • Q3: 修正了数据事后,还须要从新挪用 render 要领吗?

这里要先提一下 React 的设想初志,React 在开辟时刻的目的就是简朴精致,可以和其他框架结合起来运用。简朴而言我们可以当 React 是一个衬着数据对象到 DOM 中的 Javascript 函数东西类,东西类固然可以屡次运用。

那末关于上面的题目:

  • A1: 不是,React 可以衬着到多个元素,恣意位置的元素。

  • A2: 可以,比方以一个弹出层组件为例,我们愿望建立一个 append 到 body 末了的组件来完成全屏遮罩, 那末我们可以动态的建立一个 div append 到 body 末了,然后将弹出层 render 到谁人 div 内。

  • A3: 假定每次数据转变都从新挪用 render 要领,那末每次 render 带来的效果是从新建立一个顶级组件实例,以及子组件实例。 假如只挪用 render 一次,将数据的变动放在组件内部,那末就不会反复建立顶级组件。

1.3.4 组件状况 State

《精益 React 学习指南 (Lean React)- 1.3 React 组件》

React 中每一个组件可以存储本身的当前状况, 以一个 switch 开关组件为例,开关的状况可以存储在组件内部。

React 的衬着效果是由组件属性和状况配合决议的,状况和属性的区别是,状况保护在组件内部,属性是由外部掌握,我们先引见组件状况相干细节:

掌握状况的 API 为:

  1. this.state:组件的当前状况

  2. getInitialState:猎取组件的初始状况,在组件加载的时刻会被挪用一次,返回值给予 this.state 作为初始值

  3. this.setState:

    • 组件状况转变时,可以经由历程 this.setState 修正状况

    • setState 要领支撑按需修正,如 state 有两个字段,仅当 setState 传入的对象包含字段 key 才会修正属性

    • 每次挪用 setState 会致使重衬着挪用 render 要领

    • 直接修正 state 不会重衬着组件

eg:

    var Switch = React.createClass({
        // 定义组件的初始状况,初始为关
        getInitialState: function() {
            return {
                open: false
            }
        },
        // 经由历程 this.state 猎取当前状况
        render: function() {
            console.log('render switch component');
            var open = this.state.open;
            return <label className="switch"> 
                        <input type="checkbox" checked={open}/> 
                    </label>
        },
        // 经由历程 setState 修正组件状况
        // setState 事后会 React 会挪用 render 要领重衬着
        toggleSwitch: function() {
            var open = this.state.open;
            this.setState({
                open: !open
            });
        }
    })

1.3.5 组件属性 Props

前面已提到过 React 组件可以通报属性给组件,通报要领和 HTML 中无异, 可以经由历程 this.props 猎取组件属性

属性相干的 API 为:

  1. this.props: 猎取属性值

  2. getDefaultProps: 猎取默许属性对象,会被挪用一次,当组件类建立的时刻就会被挪用,返回值会被缓存起来,当组件被实例化事后假如传入的属性没有值,会返回默许属性值

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

  4. propTypes: 属性范例搜检

以一个代办事项的列表项组件为例:

    // props.name 示意代办事项的称号
    var TodoItem = React.createClass({
        render: function() {
            var props = this.props;
            return <div className="todo-item">
                        <span className="todo-item__name">{props.name}</span>
                    </div>
        }
    });

    ReactDOM.render(
        <TodoItem name="代办事项1"/>, 
         document.getElementById('example'));

children 属性

组件属性中会有一个特别属性 children ,示意子组件, 照样以上面一个组件为例子,我们可以换一种体式格局定义 name:

    var TodoItem = React.createClass({
        render: function() {
            var props = this.props;
            return <div className="todo-item">
                        <span class="todo-item__name">{props.children}</span>
                    </div>
        }
    });

    ReactDOM.render(
        <TodoItem>代办事项1</TodoItem>, 
         document.getElementById('example')); 

须要注重的是,children 只能为一个元素,不能为多个组件

属性范例搜检

为了保证组件通报属性的正确性, 我们可以经由历程定义 propsType 对象来完成对组件属性的严厉校验:

    var MyComponent = React.createClass({
        propTypes: {
            optionalArray: React.PropTypes.array,
            optionalBool: React.PropTypes.bool,
            optionalFunc: React.PropTypes.func,
            optionalNumber: React.PropTypes.number,
            optionalObject: React.PropTypes.object,
            optionalString: React.PropTypes.string,
            // 任何可以被衬着的包含,数字,字符串,组件,或许数组
            optionalNode: React.PropTypes.node,
            // React 元素
            optionalElement: React.PropTypes.element,
            // 罗列
            optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),
            // 恣意一种范例
            optionalUnion: React.PropTypes.oneOfType([
              React.PropTypes.string,
              React.PropTypes.number,
              React.PropTypes.instanceOf(Message)
            ]),
            // 细致范例的数组
            optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),
            // 细致范例的对象
            optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),
            // 相符定义的对象
            optionalObjectWithShape: React.PropTypes.shape({
              color: React.PropTypes.string,
              fontSize: React.PropTypes.number
            }),
            requiredFunc: React.PropTypes.func.isRequired,
            requiredAny: React.PropTypes.any.isRequired,
            // 自定义校验
            customProp: function(props, propName, componentName) {}
        }
    });

属性通报的单向性

我们已提到过 React 的单向数据流形式,数据的活动管道就是 props,活动的方向就是组件的层级自定向下的方向。所以一个组件是不能修正本身的属性的,组件的属性一定是经由历程父组件通报而来(或许默许属性)。

无状况组件属性

关于无状况组件,可以增添 .propTypes.defaultProps 属性到函数上。

1.3.6 组件的嵌套组合

在 1.2 节的 JSX 实例子中,当我们轮回输出 todo 列表的时刻,React 会提醒关于轮回输出的组件,须要有一个唯一的 key 属性。这个题目的缘由在于 React 的折衷机制(Reconciliation)上。

什么叫折衷?

在每次数据更新事后,React 会从新挪用 render 衬着出新的组件构造,新的构造运用到 DOM 中的历程就叫做折衷历程。

为何须要折衷?

想想,假定我们有一个输入组件,这个时刻我们正聚焦在输入框中,当修正值事后触发事宜致使了数据转变,数据转变致使了重衬着, 这个时刻输入框被替代成了新的 DOM。 这个历程对用户来讲应当是无感知的,所以那本来的聚焦状况应当被保留, 那怎样做到的呢? DOM 都被替代了,输入状况,挑选状况为何还能保留。 我们先不急着晓得 How,现在只须要晓得这就是折衷历程,背面我们会在 React 完成道理章节举行细致引见。

除了保留状况之外,折衷历程还做了许多 DOM 优化。 比方输出一个数组的时刻,数据新增添或许减少了一下,或许数组项值转变了,实际上我们没有必要删除本来的 DOM 构造,只须要修正 DOM 的值或许删除 DOM 就可以完成重衬着。

这就是为何要有 key 属性,key 属性可以协助定位 DOM 与数组元素的关联,在重衬着的时刻可以完成衬着优化。

1.3.7 实例演习:经由历程组件化的体式格局优化之前的待办事项列表

题目

优化 JSX 语法演习的 TODOMVC 页面, 经由历程组件化的体式格局拆分页面!

组件以下:

  1. App 组件:全部页面的最完成组件

  2. Header 组件:头部输入组件

  3. TodoList 组件:列表组件

  4. TodoItem 组件: 列表项

  5. Footer 组件:底部操纵组件

Tips

轮回输出组件的体式格局

体式格局一:先盘算出组件

 function render() {
    var todos = this.props.todos;
    var $todos = todos.map(function(todo) {
        return <Todo data={todo}/>
    });
    return <div>
        {$todos}
    </div>
 }

体式格局二:{} 内直接盘算

 function render() {
    var todos = this.props.todos;
    return <div>
        {todos.map(function(todo) {
            return <Todo data={todo}/>
        })}
    </div>
 }  

参考答案

https://github.com/leanklass/leanreact/tree/component

    原文作者:陈学家_6174
    原文地址: https://segmentfault.com/a/1190000005151182
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞