React

103 阅读5分钟

React

优势:

Virtual DOM

  • VD 是一个 obj 结构, 能够反映出对应的 DOM 节点内容, 下面是一个根据 dom 转译出来的 VD
<div>
   Hello World
   <ul>
       <li id="1" class="li-1">
           第1
       </li>
   </ul>
</div>
{
   tag: "div",
   props: {},
   children: [
       "Hello World", 
       {
           tag: "ul",
           props: {},
           children: [{
               tag: "li",
               props: {
                   id: 1,
                   class: "li-1"
               },
               children: ["第", 1]
           }]
       }
   ]
}

diff 算法

有状态, 无状态组件

  • 有状态组件: class 类型的组件有state 数据, 没有生命周期函数, 有 props
  • 无状态组件: function 类型的组件, 没有state数据, 有生命周期函数, 有 props

React 与 Babel

jsx 来自于用户自定义的 render 方法里面

  • jsx 是 js 的扩展, 和 模版语言 ` ` 很接近
  • 一个看着很像 HTML的 语法糖, 其实质还是会 babel 编译之后的 js 代码
  • jsx 不会天然的被支持 js 支持, 而需要用 babel 去编译 React.createElement()

createElement(): Babel 转译 jsx 是通过 createElement() 的方法

  • 以对象形式传入, 主要用来格式化数据,没有其他复杂数据, 并返回ReactElement()

ReactElement() : 数据组装, 生成虚拟 DOM 树

  • 主要是用来组装数据
  • 里面有虚拟 DOM
  • 会扔到ReactDOM.render()方法之中

ReactDOM.render() : 虚拟 DOM => 真实 DOM

生命周期

  • 每个组件(渲染),每个组件都是自己内部单独的
  • 每个组件的关联只有数据的关联

渲染工作流

  • 组件数据改变 => 组件实际更新

Mounting(挂载)阶段

  1. constructor()

    只触发一次

  2. componentWillMount()

    只触发一次

  3. render()

    并不会去操作真实 DOM, 他的职责是把需要渲染出来的内容返回出来. (操作真实的 DOM 不是 render(), 而是 ReactDOM.render())

  4. componentDidMount()

    在渲染结束之后被触发, 真实 DOM 已经挂载了页面上, 可以在这个生命周期里面执行真实的 DOM 相关的操作

Updating(挂载)阶段

由父组件触发,或者组件自身通过 setState()方法触发

componentWillReceiveProps()

  • 只由父组件调用更新的时候触发, 组件自身更新(通过setState()调用)不触发
  • 如果父组件导致组件重新渲染,即使 props 没有更改, 也会调用此方法, 如果处理更改, 请确保当前值与变更值得比较. 也就是说只要父组件发生了更新, 这个方法就必然会调用, 当然子组件更不更新另说, 但是这个方法一定会被调用

shouldComponentUpdate(nextProps, nextState)

  • 组件是否应该执行更新, 返回 boolean, 如果返回是 true 那么就会更新, 否则不更新
  • 可以利用参数,来确定是否应该更新组件

componentWillUpdate()

  • 已经不怎么使用了

render()

  • update 阶段会再次触发 render()

componentDidUpdate( preProps, preState)

  • 组件完成更新后调用, 可以在这里面去操作 DOM
  • 可以接受两个参数 一个是 preProps 和 preState
  • 典型用法: 如果前后两次的 id 不一样, 可以从新发送 Http 请求

Unmounting 阶段: 组件的卸载

componentWillUnmount()

  • 组件在父组件中一处
  • 组件设置了 key 属性, 父组件在 render 的过程中,发现 key 值和上一次不一致,就会触发这个方法

受控组件与非受控组件

  • 受控组件:以表单, input 等需要输入值得组件, 都受react 的state来控制内容和值, 都叫做受控组件. 这里面值统一都由 react 来管理
  • 非受控组件 : 不由 react 去管理input表单里面的内容,而是由 dom 自身节点自己控制自己. ref经常用到,来取 dom 里面存储的值

Redux

Redux 应该用来储存各个页面之间的共享数据, 例如: 登录数据, 购物车数据
Redux 不应该过于庞大, 各个页面的自身所有的数据,应该保存在各个页面自身当中

store

  • 存储仓库, 用来触发 reducer 去修改自身的值, 从而影响 component 的展示

store.subscribe( function A)

  • 时时刻刻去监听 functionA, 如果 functionA 发生变化, 那么 store 就会随之会产生对应的响应事件

reducer

  • 其实就是方法, 用来修改值

action

React-Redux (主要使用)

  • 核心思想就是把 store 给传递个需要 store 的子组件. 这样就不需要重新走 render 方法更新所有的组件, 只需要更新需要 store 的组件就可以了
  • Provider 能够把 store 传递给 Provider 里面包裹的组件, 把 store 给应用到子组件的实例中
  • connect 能够将组件连接到 store 的功能, 接收 store 传过来的东西, 可以利用装饰器
import React, { Component } from "react";
import { Button } from "antd";
import { connect } from "react-redux";
// 该方法是把 我们的 state 给包装成组件的 props
const mapStateToProps = (state) => {
  return {
    num: state,
  };
};
// 该方法是把我们的 dispatch 动作给包装成 props
const mapDispatchToProps = (dispatch) => {
  return {
    increment: () => {import React, { Component } from "react";
import { Button } from "antd";
import { connect } from "react-redux";
// 该方法是把 我们的 state 给包装成组件的 props
const mapStateToProps = (state) => {
  return {
    num: state,
  };
};
// 该方法是把我们的 dispatch 动作给包装成 props
// 来触发 reducer
const mapDispatchToProps = (dispatch) => {
  return {
    increment: () => {
      dispatch({ type: "INCREMENT" });
    },
    decrement: () => {
      dispatch({ type: "DECREMENT" });
    },
  };
};
// 装饰器原理
@connect(mapStateToProps, mapDispatchToProps)
class ReduxTest extends Component {
  render() {
    return (
      <div>
        <h3>{this.props.num}</h3>
        <Button type='success' onClick={() => this.props.increment()}>
          +1
        </Button>
        <Button type='success' onClick={() => this.props.decrement()}>
          -1
        </Button>
      </div>
    );
  }
}

export default ReduxTest;

      dispatch({ type: "INCREMENT" });
    },
    decrement: () => {
      dispatch({ type: "DECREMENT" });
    },
  };
};
@connect(mapStateToProps, mapDispatchToProps) // 装饰器
class ReduxTest extends Component {
  render() {
    return (
      <div>
        <h3>{this.props.num}</h3>
        <Button type='success' onClick={() => this.props.increment()}>
          +1
        </Button>
        <Button type='success' onClick={() => this.props.decrement()}>
          -1
        </Button>
      </div>
    );
  }
}

export default ReduxTest;

Redux 中间件

  • 应用在 store 当中
  • 中间件定义: 在通过action 去 dispatch 触发 reducer 修改 state 之前, 可以加一些其他的流程,就是中间件
  • redux-thunk : 处理异步 action
  • redux-logger: 处理日志记录的中间件

Mobx (React+ Mobx更适合中小型项目)

  • Mobx 是一个提供者, 用于存储和更新状态 state

react-router-dom

常用的组件有 Link, Route, Redirect, Switch, BrowserRouter, HashRouter

  • Redirect : 重定向组件, 如果没有匹配的 path 那么就会自动走 Redirect 中的 to 中所指定的路径
  • Link: 导航组件
  • Route: 路由定义, 定义不同的 path da

dva

  1. 把 react-redux 和 react-thunk 等一些数据控制的进行了整合
  2. dva 中的数据流向, 基本上与 react-redux 一致

数据改变发生通常是通过用户交互行为或者浏览器行为(如路由跳转)触发的, 当此类行为改变数据的时候, 可以通过 dispatch 发一个 action, 如果是同步行为会直接通过 reducer改变state, 如果是异步行为,会先出法副作用(effect), 然后流向Reducer最终改变state, 所以在 dva 中,数据也是跟redux一致的, 单向流