Redux知识点记录

236 阅读5分钟

Redux

持续更新中…………

redux是独立的一个状态管理数据状态工具

应用中所有的state都以一个对象树的形式存在在一个单一的store中,唯一改变state的办法是触发action,一个描述发生什么的对象,为了描述action如何改变state,需要编写一个reduces

例如

function counter(state = 3, action){
    switch (action.type) {
    case "TODO_ADD": // 添加todo
      return ++state
    default:
      return state
  }
}

const store = createStore(counter)

在react中使用

import { createStore } from "react-redux"
function counter(state = 3, action){
    switch (action.type) {
    case "ADD": // 添加todo
      return ++state
    default:
      return state
  }
}

const store = createStore(counter)

render() // 初始化渲染

function render(){
    ReactDom.render(
        <div>
            <p onClick={()=>{
                store.dispatch({type:"ADD"})
            }}>{counter}</p>
        </div>,
        document.getElementById("root")
    )
}

// 当触发事件修改counter的值时候,页面并没有渲染,是因为没有感知到变化,使用subcribe可以监听变化,然后重新渲染

store.subcribe(()=>{
    render()
})

核心概念

Redux中不能直接修改state,因为他没有setter(修改器方法)只能使用action修改,action是一个普通的js对象

强制使用action修改state的好处

1、可以清楚的知道state为什么改变,在哪儿改变。把action和state串起来开发一些函数,这就是reducer

redux的三大原则

1、单一数据源

整个应用的state被存储在一个object tree中,并且这个object tree只存在于唯一一个store中

2、state是只读的

唯一改变state的方法是触发action,action是一个用于描述发生事件的普通对象。 这样确保了视图和网络请求都不能直接修改state,相反它们只能表达出想要修改的意图。因为state都是集中化处理,并且严格按照一个接一个的顺序执行,因此不用担心异步

3、使用纯函数修改

为了描述action如何改变state tree,需要编写reducers Reducer只是一些纯函数,接收先前的state和actin,并且返回新的state。一开始可以只用一个reducer。但随着项目的扩大,可以拆分成多个小的reducer,分别独立操作state tree 不同部分,可控制调用顺序

const todos = (state = [], action) => {
  switch (action.type) {
    case 'ADD_TODO':
      return [
        ...state,
        {
          id: action.id,
          text: action.text,
          completed: false
        }
      ]
    case 'TOGGLE_TODO':
      return state.map(todo =>
        (todo.id === action.id) ?
        {
          ...todo,
          completed: !todo.completed
        } :
        todo
      )
    default:
      return state
  }
}

export default todos


const visibilityFilter = (state = 'SHOW_ALL', action) => {
  switch (action.type) {
    case 'SET_VISIBILITY_FILTER':
      return action.filter
    default:
      return state
  }
}

export default visibilityFilter



// store/index.js
import {
  combineReducers
} from 'redux'
import todos from './todos'
import visibilityFilter from './visibilityFilter'

export default combineReducers({
  todos,
  visibilityFilter
})


// index.js
import { createStore } from "redux";
import todoApp from "./reducers";
import App from "./App";

let store = createStore(todoApp);

拆分Reducer之后使用combineReducers合并小的reducer

Action

Action是把数聚从应用传到store的有效载荷,是数聚store的唯一来源,可以通过store.dispatch()将action传到store

action对象中除type外,其他结构由自己决定,一般会传state数聚中的数据id,进行方便查找

例如:{type:"ADD",index:5}

Reducer

只是一个接受state和action并返回一个新的state函数

reducer指定了应用中状态的变化如何响应actions并发送到store中,记住actions只是描述了有事情发生了这一事实,没有描述应用如何更新state

要一直保持reducer纯净,永远不要在reducer里做一下操作

1、修改传入的参数

2、执行又副作用的操作,如API和路由跳转

3、调用非纯函数 如Math.random()

注意点:

1、 在返回新的state的时候使用Object.assign()会修改第一个参数的值,所以第一个参数要设置{} object.assign({},state)

2、在type是位置的情况下,一定要返回旧的state

store的职责

1、维持应用的state

2、提供getState()方法获取state

3、提供dispatch({})更新state

4、通过subcribe(()=>{}) 注册监听器

5、通过subcribe(()=>{}) 返回的方法取消监听

store只能有一个,需要拆分逻辑时,应该使用reducer组合,而不是创建多个store

在reducer中讲到使用combineReducers()将多个reduce合并成为一个,然后使用createStore()创建一个store

let store = createStore(todoApp);  // 导入合并之后的reducers

数据流

严格的单向数据流是Redux的设计核心,单向数据流可使得数据改变都是可预测的

Redux应用中的数据的生命周期遵循4个步骤

1、调用srore.dispatch(action)

action就是一个描述发生了什么的普通对象 ,可以在任何地方调用store.dispatch(action)

2、Redux store会调用传入的reducer函数

reducer是纯函数,仅仅用于计算下一个state,完全是可预测的:多次传入相同的输入,必须产生相同的输出

3、根reducer应该吧多个子reducer输出合并成一个单一的state树,使用combireReducer()合并

4、Redux store保存了根reducer返回的完成的state树

新的树就是下一个应用state,在所有订阅store.subscribe()的监听器都将被调用,监听器里可以调用store.getState()获得当前state

搭配React

使用 npm install react-redux -S  下载

传入store的方法

所有容器组件都可以访问Redux store,所以可以手动监听,一种方式是把它以props的形式传入到所有容器组件中,但这太麻烦,因为要使用store把组件包一层,仅仅因为恰好在组件数中渲染了一个容器组件

建议使用方式:使用指定的react redux组件,让所有容器组件都可以访问store,而不用显示传递,只需要渲染根组件就可以

render(
  <Provider store={store}>
    {/* <App /> */} <App> </App>
  </Provider>,
  document.getElementById("root")
);

在组件中获取store中state的值

1、使用高阶组件connect()传递参数返回新组件

export default connect(state=>({todos:state.todos}))(Todo) // 组件

2、有了hooks之后就可以使用hooks获取

hooksAPI

1、 传递store

2、useDispatch 获取dispatch方法

3、useStore获取store

4、useSelector 获取state

5、connect() 高阶函数:传入数据返回一个新的函数,然后再传入组件返回一个新的组件

后续会更新异步调用…………