美文网首页React
ReactJS的学习笔记

ReactJS的学习笔记

作者: void_main | 来源:发表于2016-08-01 18:26 被阅读279次
    ReactReact

    React介绍

    React只是一个view层的解决方案,它做的主要事情就是

    • 前端控件组件化
    • 利用 props 形成单向的数据流
    • 根据 state 的变化来更新 view
    • 利用虚拟 DOM 来提升渲染性能

    React通过props和state去渲染界面,所以有个很形象的描述UI = f(props,state).
    初期, react基本的操作无外乎就是围绕着,Component和ReactDOM进行编写和渲染。 以前, react并没有分的太细化, 不过在version 0.14版本后, ReactDOM和Component就分开了, 主要还是因为React Native的缘由. 不过, 两者分开过后,造成的影响来说, 还是不小的. 主要影响到三个方面:

    • ReactDOM.render(): 渲染UI层

    • ReactDOM.findDOMNode(): 获取节点

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

    this.props 在组件复用中,是占很重要的地位的, 可以说,他是parent和children 组件通信的重要通道, 父组件赋值, 子组件处理

    props示意图props示意图

    react 提供另外一个状态属性this.state. React 通过改变父组件本身的state, 会导致DOM的重新渲染, 相当于重新调用ReactDOM.render().

    state示意图state示意图
    能够引起state变化的动作有
    • 页面上用户的活动
    • 外部例如服务器
      每个组件都有自己的setState方法来改变组件当前的state,可以把更改state的逻辑写在各自的组件中,但是当项目逻辑愈发复杂是,这样就存在问题,对于开发人员很难理清state和view之间的关系。最好的解决方案值对引起state变化的情况进行统一管理。

    JSX语法

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

    很简单, 就是所有标签必须闭合. 比如像[站外图片上传中……(10)]这样的, 后面的/ 可以写可不写. 但是, 现在在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.

    • 表单输入

    一旦你设置在input的value属性. 后面你所有的输入都是无效的.

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

    这里就需要使用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
    JSX所有语法注意点总结如下

    titletitle

    JSX组件

    JSX 组件分为 HTML 组件和 React 组件

    关于Virtual DOM的理解

    React的意思是,我提供一个Component,然后你只管给我数据,界面的事情完全不用你操心,我保证会把界面变成你想要的样子。
    你可以把一个React的Component想象成一个Pure Function,只要你给的数据是[1, 2, 3],我保证显示的是[1, 2, 3]。没有什么删除一个Element,添加一个Element这样的事情。NO。你要我显示什么就给我一个完整的列表。

    Virtual DOM和DOM是啥关系呢?
    首先,Virtual DOM并没有完全实现DOM,Virtual DOM最主要的还是保留了Element之间的层次关系和一些基本属性。因为DOM实在是太复杂,一个空的Element都复杂得能让你崩溃,并且几乎所有内容我根本不关心好吗。所以Virtual DOM里每一个Element实际上只有几个属性,并且没有那么多乱七八糟的引用。所以哪怕是直接把Virtual DOM删了,根据新传进来的数据重新创建一个新的Virtual DOM出来都非常非常非常快。(每一个component的render函数就是在做这个事情,给新的virtual dom提供input)
    所以,引入了Virtual DOM之后,React是这么干的:
    你给我一个数据,我根据这个数据生成一个全新的Virtual DOM,然后跟我上一次生成的Virtual DOM去 diff,得到一个Patch,然后把这个Patch打到浏览器的DOM上去。完事。

    最后,回到为什么Virtual Dom快这个问题上。
    其实是由于每次生成virtual dom很快,diff生成patch也比较快,而在对DOM进行patch的时候,我能够根据Patch的内容,优化一部分DOM操作,比如之前1.2里的那个例子。
    重点就在最后,哪怕是我生成了virtual dom,哪怕是我跑了diff,但是我根据patch简化了那些DOM操作省下来的时间依然很可观。所以总体上来说,还是比较快。
    而更糟糕的是,我们(以及很多框架)在调用DOM的API的时候做得不好,导致整个过程更加的慢。React的Virtual Dom解决的是这一部分问题,它并不能解决DOM本身慢的问题。
    比如说,现在你的list是这样,

    <ul>
    <li>0</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    </ul>
    

    你想把它变成这样

    <ul>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
    </ul>
    

    通常的操作是什么?
    先把0, 1,2,3这些Element删掉,然后加几个新的Element 6,7,8,9,10进去,这里面就有4次Element删除,5次Element添加。
    而React会把这两个做一下Diff,然后发现其实不用删除0,1,2,3,而是可以直接改innerHTML,然后只需要添加一个Element(10)就行了,这样就是4次innerHTML操作加1个Element添加,比9次Element操作快多了吧?

    作者:EMayej Bee
    链接:http://www.zhihu.com/question/29504639/answer/44680878
    来源:知乎
    著作权归作者所有,转载请联系作者获得授权。

    Flux组件

    Flux简介

    Flux 的思维模型1Flux 的思维模型1
    Flux 的思维模型2Flux 的思维模型2
    其中 Dispatcher 是 Flux 的核心枢纽,它相当于是一个事件分发器,将那些分散在各个组件里面的逻辑代码收集起来,统一在 Dispatcher 中进行处理

    完整的Flux处理流程如下

    • 用户通过与 view 交互或者外部产生一个 Action
    • Dispatcher 接收到 Action 并执行那些已经注册的回调,向所有 Store 分发 Action
    • 通过注册的回调,Store 响应那些与他们所保存的状态有关的 Action。
    • Store 会触发一个 change 事件,来提醒 controller-views 数据已经发生了改变。
    • Controller-views 监听这些事件并重新从 Store 中获取数据。这些 controller-views 调用他们自己的 setState() 方法,重新渲染自身以及组件树上的所有后代组件。

    Flux优点

    Flux 把所有的 View 都视作愚民,Store 视作资源的拥有者为统治者,统治者需要提供资源(数据)给平民,但是如果平民企图对资源修改(Mutation),必须得先通知给统治者,让统治者决定是否做处理。
    我们为 Flux 中的概念分配角色

    • View: 平民
    • Action: 资源修改操作
    • Dispatcher: 审核官
    • Store: 统治者

    一个企图修改资源的操作可以描述为:
    View Require Mutation -> Action -> Dispatcher -> Store -> Mutate Handler

    平民提交 Mutation 请求,由审核官控制,审核通过后递交给统治者,统治者再分配给亲信做资源 Mutation
    合而治之的策略也等于中心化控制策略, 作为统治者既要懂得放权利(资源的分配),也要懂得控制权利(资源的修改),这种收缩自如的合理性是 Flux 简洁的根本。
    同时这种思维带来的优点如下:

    • View 的独立性和简单性:View 自身的逻辑简单,不需要知道太多事情,只关心上级传来的数据,这种模式使得 View 是低耦合的,简洁的。
    • 高可维护性:中心化控制知道所有对资源的操作,如果发生 bug, 可以很快定位问题

    Flux实例

    学习flux的一些浅显理解
    结合github上flux的flux-todomvc项目进行介绍

    • Actions
      根据我们的需求在这个文件里定义不同的 action 函数,但这里的函数并不涉及逻辑的处理,这里函数只是告诉我们的 Dispatcher,用户进行了什么操作。所以我们只需要给 Dispatcher 传的一个对象,对象里一个必要的属性就是 actionType。如果用户进行这个操作有给我们传的参数的话。那参数也会放在这个对象里。
    import AppDispatcher from '../dispatcher/AppDispatcher';
    import TodoConstants from '../constants/TodoConstants';
    
    var TodoActions = {
      create (text) {
        AppDispatcher.dispatch({
          actionType: TodoConstants.TODO_CREATE,
          text: text
        });
      },
      // other actions
    }
    
    export default TodoActions;
    

    当我们执行 AppDispatcher.dispatch 这个方法,并传给他一个有 actionType 属性的对象时,他就会在大喊,“有人做了一个操作呀,这个操作就是 xxx (actionType 的值),还带了个参数,你们哪个来处理一下呀

    • Constants
      actionType: TodoConstants.TODO_CREATE
      ,这个 TodoConstants其实就是我们操作的名字,相当于一个常量,定义在 Constants 里方便管理和调用而已。
    • Store
      • Store 是一个保存数据的地方
      • Store 是一个充满逻辑的地方
    var TodoActions = {
    
      /**
       * @param  {string} text
       */
      create: function(text) {
        AppDispatcher.dispatch({
          actionType: TodoConstants.TODO_CREATE,
          text: text
        });
      },
    
    
    • Store 是一个响应 Dispatcher 呼喊的地方
      在 Store 里,我们通过 Dispatcher “注册”了一个回调函数,每当我们调用 dispatch 函数的时候,就是 Dispatcher 大喊的时候,我们根据不同的 actionType,来调用我们不同的逻辑处理函数,像这样
    import AppDispatcher from '../dispatcher/AppDispatcher';
    import TodoConstants from '../constants/TodoConstants';
    
    AppDispatcher.register((action) => {
      var text;
    
      switch(action.actionType) {
        case TodoConstants.TODO_CREATE:
          text = action.text.trim();
          if (text !== '') {
            create(text);
            TodoStore.emitChange();
          }
          break;
    
        // other case
      }
    });
    
    • Store 是一个鞭策 Controller View 改变的地方
    • store学会喊一句 TodoStore.emitChange();
    • 为controller view助听器 addChangeListener (callback) { this.on(CHANGE_EVENT, callback) }
    import assign from 'object-assign';
    
    var EventEmitter = require('events').EventEmitter;
    
    var TodoStore = assign({}, EventEmitter.prototype, {
      areAllComplete () {
        for (var id in _todos) {
          if (!_todos[id].complete) {
            return false;
          }
        }
        return true;
      },
      getAll () {
        return _todos;
      },
      emitChange () {
        this.emit(CHANGE_EVENT);
      },
      addChangeListener (callback) {
        this.on(CHANGE_EVENT, callback);
      },
      removeChangeListener (callback) {
        this.removeListener(CHANGE_EVENT, callback);
      }
    });
    
    export default TodoStore;
    
    • Controller View
      TodoApp.react.jsTodoApp.react.js
      当组件渲染完成后,就绑定了 Store 的 addChangeListener,并回调了自己的onChange方法。

    Redux介绍

    titletitle
    redux 可以理解为基于 flux 和其他一些思想(Elm,函数式编程)发展出来的前端应用架构库,作为一个前端数据状态容器体现,并可以在 React 和其他任何前端框架中使用。
    前端基本框架图前端基本框架图

    Redux 就是用来确保 state 变化的可预测性,主要的约束有:

    • state 以单一对象存储在 store 对象中
    • state 只读
    • 使用纯函数 reducer 执行 state 更新

    state 为单一对象,使得 Redux 只需要维护一棵状态树,服务端很容易初始化状态,易于服务器渲染。state 只能通过 dispatch(action) 来触发更新,更新逻辑由 reducer 来执行。

    区别点 flux redux
    store 多个store,在store中执行更新逻辑 只有一个 ,更新逻辑不再store中执行,而是放在reducer
    dispatcher

    React Reflux

    Action、Store和组件这三者是通过事件机制响应变化的,构建组件的时候首先需要监听Store的状态。先定义Action和Store
    React Reflux

    ╔═════════╗       ╔════════╗       ╔═════════════════╗
    ║ Actions ║──────>║ Stores ║──────>║ View Components ║
    ╚═════════╝       ╚════════╝       ╚═════════════════╝
         ^                                      │
         └──────────────────────────────────────┘
    
    var TodoActions = Reflux.createActions([
        'addItem'
    ]);
    
    var TodoStore = Reflux.createStore({
        items: [1, 2],
        listenables: [TodoActions],//store监听actions的行为
        onAddItem: function (model) {
            $.post('/server/add', {data: model}, function (data) {
                this.items.unshift(data);
                this.trigger(this.items);
            });
        }
    });
    
    
    var TodoComponent = React.createClass({
        mixins: [Reflux.listenTo(TodoStore, 'onStatusChange')],
        getInitialState: function () {
            return {list: []};
        },
        onStatusChange: function () {
            this.setState({list: TodoStore.items});
        },
        render: function () {
            return (
                <div>
                    {this.state.list.map(function (item) {
                        return <p>{item}</p>
                    })}
                </div>
            )
        }
    });
    
    
    React.render(<TodoComponent />, document.getElementById('container'));
    
    区别点 flux reflux
    store 多个store,在store中执行更新逻辑 stores可以监听actions的行为,无需进行冗杂的switch判断,stores可以监听actions的行为,无需进行冗杂的switch判断
    dispatcher 通过内部拓展actions的行为,移除了单例的dispatcher

    React

    React/React Native 的ES5 ES6写法对照表

    参考资料

    精益 React 学习指南 (Lean React)序
    精益 React 学习指南 (Lean React)- 1.1 React 介绍
    最新版React入门
    玩物圈前端技术栈总结(React+Redux)
    Redux 中文文档
    Redux 介绍
    浅谈 React、Flux 与 Redux

    相关文章

      网友评论

        本文标题:ReactJS的学习笔记

        本文链接:https://www.haomeiwen.com/subject/fsdojttx.html