欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ReactJS的学习笔记

程序员文章站 2024-02-26 21:15:22
...
React

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示意图

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

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所有语法注意点总结如下

title

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 的思维模型1

Flux 的思维模型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.js

    当组件渲染完成后,就绑定了 Store 的 addChangeListener,并回调了自己的onChange方法。

Redux介绍

title

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

转载于:https://www.jianshu.com/p/4b17a8b5f466