你需要知道的Redux知识

南山隐士 2022年06月25日 24 0

什么是Redux

Redux 是 JavaScript 状态容器, 一般用于react中, 可以存放一些数据状态, 类似于vuex, 但是它不仅仅只有react可以使用, 使用redux最主要功能是可以将一些共享的数据存放到一个store中, 你可以很方便地实现多个组件之间改变相应的数据, 熟悉 Redux 是学习dva的前提

store

想要存放数据(state),那么你必须调用 ==createStore== 函数来创建一个store用来存放, ==注意一个应用中只能允许一个store==

action

==要想更新state中的数据, 那么你需要触发action==, 它是就是一个普通的javascript对象, 里面存放了对应的action名称以及需要变更的数据

reducer

只有store和action显然是没法改变数据的, ==reducer可以帮助到我们, 它描述action如何去修改state的值==,其实它就是一个接受之前state以及action的普通函数, 来判断对应的aciton名称, 然后返回一个新的state

如何编写?

首先,我们得明确我们的state是长什么样的, 确定state的数据状态

创建action-types.js(名称你可以自行定义)存放一些action名称, 这个不是必须的, 但是当你项目比较大的时候,这个将会有所帮助

export const ADD_TODO = 'ADD_TODO'
// 更多

导入,并且 使用action创建函数返回action

export const addTodo = (text) => ({ type: types.ADD_TODO, text })
// 更多

创建reducer

// reducer/todo.js
import { ADD_TODO } from '../action-types'

// 创建初始state
const initState = []

export default function todos(state = initState, action) {
  switch (action.type) {
    case ADD_TODO:
      return [
        ...state,
        {
          id: initState[initState.length - 1].id ? 0 : initState[initState.length - 1].id + 1,
          completed: false,
          text: action.text,
        },
      ]
// 未知的情况下, 一定要返回之前的state
    default:
      return state
  }
}

当有多个reduces的时候,可以使用==combineReducers== 合并

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

const rootReducer = combineReducers({
  todos,
})

export default rootReducer

现在我们有了state数据以及改变数据对应的reduces函数, ==然后我们在添加一个变化监听器(subscribe)==, 它会在==触发action的时候(通过store.dispatch)==,执行里面对应的逻辑, 一般我们会更新我们的React的state 数据

store.subscribe(() =>
  console.log(store.getState())
);

现在,你应该已经理解redux的基本工作流程了,它其实就是通过将我react中需要共享的数据状态都放到了store中, 而唯一改变store中的数据是触发action, 你需要通过store.dispatch(action)进行触发, 它会执行reduces中对应描述如何改变state的函数, 返回新的state, 最后我们通过subscribe监听数据变化, 一旦发生变化,来改变react的数据, 从而达到视图以及数据的更新

react-redux

state是单数据流的, 所以, 正常开发中,我们不可能将store一层层地往下传递, 而react-redux 这个官方提供的绑定库可以很方便地实现我们想要的

你只需要在根组件中包裹 ==Provider== 标签即可, 这样, 你的子组件都可以访问store中的数据了

如果你不想每个组件都可以访问store数据, 只想某些组件可以访问, 你可以通过==connect== 函数, ==它可以让你的组件跟store进行连接(通过mapStateToProps), 并且它还可以传递相应的action做为props到你的组件中(通过mapDispatchToProps)==

const mapStateToProps = (state, ownProps) => ({
  active: ownProps.filter === state.visibilityFilter,
})

const mapDispatchToProps = (dispatch, ownProps) => ({
  setFilter: () => {
    dispatch(setVisibilityFilter(ownProps.filter))
  },
})

export default connect(mapStateToProps, mapDispatchToProps)(Link)

==connect会函数会返回一个新的与 Redux store 连接的组件==

==bindActionCreators 可以把一个 value 为不同 action creator 的对象,转成拥有同名 key 的对象==, 你可以很方便的通过对象点的形式直接触发action

reselect

使用content来连接 redux, 第一个函数它会在 Redux store 发生改变的时候就会调用, 如果你这个函数中, 返回一个很大的对象数据, 而这个对象某些数据又没有必要去重复计算(例如某个数据中需要进行过滤), 要解决这个问题, 我们就得使用到 ==reselect==

import { createSelector } from 'reselect'
import { SHOW_ALL, SHOW_COMPLETED, SHOW_ACTIVE } from '../constants/TodoFilters'

const getVisibilityFilter = state => state.visibilityFilter
const getTodos = state => state.todos

export const getVisibleTodos = createSelector([getVisibilityFilter, getTodos], (visibilityFilter, todos) => {
  switch (visibilityFilter) {
    case SHOW_ALL:
      return todos
    case SHOW_COMPLETED:
      return todos.filter(t => t.completed)
    case SHOW_ACTIVE:
      return todos.filter(t => !t.completed)
    default:
      throw new Error('Unknown filter: ' + visibilityFilter)
  }
})

export const getCompletedTodoCount = createSelector([getTodos], todos =>
  todos.reduce((count, todo) => (todo.completed ? count + 1 : count), 0),
)

==createSelector== 函数接受 inputSelectors 参数和 resultFunc 函数(函数最后一个参数)

上述例子中: getVisibilityFilter 以及 getTodos 为 inputSelectors 参数

inputSelectors 参数你可以理解为它是一个返回你想要缓存state的函数, 它可以有多个,并且可以接受组件的state以及props(需要你调用时候传递)

inputSelectors 只有在 inputSelectors 中任意一个值与上次缓存的值不一致才会执行

redux-thunk

我们可以看到上述我们改变state都是同步的方式修改数据, 想实现异步更新数据,我们可以通过react-thunk

它可以让你action created 返回的不是一个对象, 而是一个函数, 并且函数中有dispatch以及getState做为参数, 我们就可以在函数中,执行一些异步操作再更新state了

要使用react-thunk 必须通过applyMiddleware来使用该中间件

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers/index';
 
// Note: this API requires redux@>=3.1.0
const store = createStore(
  rootReducer,
  applyMiddleware(thunk)
);
// 例子
export const addToCart = productId => (dispatch, getState) => {
  if (getState().products.byId[productId].inventory > 0) {
    dispatch(addToCartUnsafe(productId))
  }
}
Last Updated: 2022/06/25 19:17:07
搜索栏实现联想功能 React基础速览