Redux

Redux

Store 数据的管理者和数据的存储者

actionCreators 动作的创建者,发送动作给 reducers

react Components 组件( 用来充当视图层 )

reducers 数据的修改者,返回一个新的 newstate 给store

React 只是 DOM 的一个抽象层,并不是 Web 应用的完整解决方案。有两个方面,它没涉及。

  • 代码结构
  • 组件之间的通信

2013年 Facebook 提出了 Flux 架构的思想,引发了很多的实现。2015年,Redux 出现,将 Flux 与函数式编程结合一起,很短时间内就成为了最热门的前端架构。

如果你不知道是否需要 Redux,那就是不需要它

只有遇到 React 实在解决不了的问题,你才需要 Redux

简单说,如果你的UI层非常简单,没有很多互动,Redux 就是不必要的,用了反而增加复杂性。

  • 用户的使用方式非常简单
  • 用户之间没有协作
  • 不需要与服务器大量交互,也没有使用 WebSocket
  • 视图层(View)只从单一来源获取数据

需要使用Redux的项目:

  • 用户的使用方式复杂
  • 不同身份的用户有不同的使用方式(比如普通用户和管理员)
  • 多个用户之间可以协作
  • 与服务器大量交互,或者使用了WebSocket
  • View要从多个来源获取数据

从组件层面考虑,什么样子的需要Redux:

  • 某个组件的状态,需要共享
  • 某个状态需要在任何地方都可以拿到
  • 一个组件需要改变全局状态
  • 一个组件需要改变另一个组件的状态

Redux的设计思想:

  1. Web 应用是一个状态机,视图与状态是一一对应的。
  2. 所有的状态,保存在一个对象里面(唯一数据源)。

注意:flux、redux都不是必须和react搭配使用的,因为flux和redux是完整的架构,在学习react的时候,只是将react的组件作为redux中的视图层去使用了。

Redux的使用的三大原则:

  • Single Source of Truth(唯一的数据源)
  • State is read-only(状态是只读的)
  • Changes are made with pure function(数据的改变必须通过纯函数完成)

使用Redux框架

1.store通过reducer创建了初始状态

2.view通过store.getState()获取到了store中保存的state挂载在了自己的状态上

3.用户产生了操作,调用了actions 的方法

4.actions的方法被调用,创建了带有标示性信息的action

5.actions将action通过调用store.dispatch方法发送到了reducer中

6.reducer接收到action并根据标识信息判断之后返回了新的state

7.store的state被reducer更改为新state的时候,store.subscribe方法里的回调函数会执行,此时就可以通知view去重新获取state

使用redux实现简单todolist

src/store文件夹内

  1. src/store/index.js
/* 
  store
    * 用于数据存储
*/

import { createStore } from 'redux'
import reducer from './reducer'

const store = createStore( reducer )
export default store 
  1. src/store/reducers.js
/* 
  reducer
    * reducer总部
    * options 中接收的是分片的reducer
*/

import {  combineReducers } from 'redux' 
import { reducer as todolist } from '../components/todolist/store'

// const reducer= combineReducers( options )
const reducer= combineReducers({
  //分片的reducer
  todolist
})


export default reducer

src/components/todolist文件夹内

  1. store.js
/* 
  它就是分片的数据包
*/
import * as type from './type'
import store from '../../store'

const state = {
  todos: [
    {
      id: 1,
      task: '任务一'
    },
    {
      id: 2,
      task: '任务二'
    }
  ]
}


export const actionCreators = {
  add_todos ( val ) {
    const action = {
      type: type.ADD_TODOS,
      payload: val
    }
    store.dispatch( action )
  }
}


export const reducer = ( previousState = state, action ) => {
  const newState = {
    ...previousState
  }

  switch (action.type) {
    case type.ADD_TODOS:
      newState.todos.push({
        id: newState.todos.length + 1, 
        task: action.payload
      })
      break;
  
    default:
      break;
  }

  return newState
}
  1. TodoList主组件
import React, { Component } from 'react';
import store from '../../store'
import { actionCreators } from './store'

class TodoList extends Component{

  constructor(props) {
    super(props)
  
    this.state = {
       todos: store.getState().todolist.todos
    }
  }
  
  renderItem = () => {
    return this.state.todos.map( item => {
      return (
        <li key = { item.id }> { item.task } </li>
      )
    })
  }

  add = ( e ) => {
    if ( e.keyCode === 13 ) {
      actionCreators.add_todos( e.target.value )
      e.target.value = ''
    }
  }
  componentDidMount () {
    store.subscribe(() => {
      this.setState({
        todos: store.getState().todolist.todos
      })
    })
  }

  render() {
    return (
      <div>
        <input  onKeyUp = { this.add } name="" id="" className="btn btn-primary" type="text" defaultValue="" />
        <hr/>
        <ul>
          { this.renderItem() }
        </ul>
      </div>
    )
  }
}

export default TodoList
  1. type.js
export const ADD_TODOS = 'add_todos'

Reducer必须是一个纯函数:

Reducer 函数最重要的特征是,它是一个纯函数。也就是说,只要是同样的输入,必定得到同样的输出。Reducer不是只有Redux里才有,之前学的数组方法reduce, 它的第一个参数就是一个reducer

纯函数是函数式编程的概念,必须遵守以下一些约束。

  • 不得改写参数
  • 不能调用系统 I/O 的API
  • 不能调用Date.now()或者Math.random()等不纯的方法,因为每次会得到不一样的结果

由于 Reducer 是纯函数,就可以保证同样的State,必定得到同样的 View。但也正因为这一点,Reducer 函数里面不能改变 State,必须返回一个全新的对象,请参考下面的写法。

// State 是一个对象
function reducer(state = defaultState, action) {
  return Object.assign({}, state, { thingToChange });
  // 或者
  return { ...state, ...newState };
}

// State 是一个数组
function reducer(state = defaultState, action) {
  return [...state, newItem];
}

最好把 State 对象设成只读。要得到新的 State,唯一办法就是生成一个新对象。这样的好处是,任何时候,与某个 View 对应的 State 总是一个不变(immutable)的对象。

我们可以通过在createStore中传入第二个参数来设置默认的state,但是这种形式只适合于只有一个reducer的时候。

划分reducer:

因为一个应用中只能有一个大的state,这样的话reducer中的代码将会特别特别的多,那么就可以使用combineReducers方法将已经分开的reducer合并到一起

注意:

  1. 分离reducer的时候,每一个reducer维护的状态都应该不同
  2. 通过store.getState获取到的数据也是会按照reducers去划分的
  3. 划分多个reducer的时候,默认状态只能创建在reducer中,因为划分reducer的目的,就是为了让每一个reducer都去独立管理一部分状态

关于action/reducer/store的更多概念,请查看官网

Redux异步

通常情况下,action只是一个对象,不能包含异步操作,这导致了很多创建action的逻辑只能写在组件中,代码量较多也不便于复用,同时对该部分代码测试的时候也比较困难,组件的业务逻辑也不清晰,使用中间件了之后,可以通过actionCreator异步编写action,这样代码就会拆分到actionCreator中,可维护性大大提高,可以方便于测试、复用,同时actionCreator还集成了异步操作中不同的action派发机制,减少编码过程中的代码量

常见的异步库:

  • Redux-thunk
  • Redux-saga
  • Redux-effects
  • Redux-side-effects
  • Redux-loop
  • Redux-observable

基于Promise的异步库:

  • Redux-promise
  • Redux-promises
  • Redux-simple-promise
  • Redux-promise-middleware

容器组件(Smart/Container Components)和展示组件(Dumb/Presentational Components)

展示组件容器组件
作用描述如何展现(骨架、样式)描述如何运行(数据获取、状态更新)
直接使用 Redux
数据来源props监听 Redux state
数据修改从 props 调用回调函数向 Redux 派发 actions
调用方式手动通常由 React Redux 生成

使用react-redux

可以先结合context来手动连接react和redux。

react-redux提供两个核心的api:

  • Provider: 提供store
  • connect: 用于连接容器组件和展示组件
  1. Provider

    根据单一store原则 ,一般只会出现在整个应用程序的最顶层。

  2. connect

    语法格式为

    connect(mapStateToProps?, mapDispatchToProps?, mergeProps?, options?)(component)

    一般来说只会用到前面两个,它的作用是:

    • store.getState()的状态转化为展示组件的props
    • actionCreators转化为展示组件props上的方法

特别强调:

官网上的第二个参数为mapDispatchToProps, 实际上就是actionCreators

只要上层中有Provider组件并且提供了store, 那么,子孙级别的任何组件,要想使用store里的状态,都可以通过connect方法进行连接。如果只是想连接actionCreators,可以第一个参数传递为null

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值