美文网首页
Redux - 给vuex开发者

Redux - 给vuex开发者

作者: 我叫Aliya但是被占用了 | 来源:发表于2021-03-17 14:42 被阅读0次

react语法 - 给vue开发者
Dva - react状态管理 - 给vuex开发者
React Router 5.x - 给vuex开发者

redux 官方 API阮一峰的网络日志

非响应式,不支持异步。

有 state、reducer(mutation)概念

创建 store

import { createStore } from "redux";
let { subscribe, dispatch, getState } = createStore(reducer, [preloadedState]);
  • reducer(state: State, action: Action): State 作用相当于 mutation,入口处只支持一个

    • Action: { type: any, payload: any }
  • preloadedState: 初始的 state

  • getState: 获取 state,只能获取整个 state

  • dispatch(action: Action): void : 触发 reducer

    • Action: { type: any, payload: any }
  • subscribe(() => void): 监听到 dispatch 调用(reducer 执行)后回调,比如用来更新视图。

例子:

const reducer = (state = 0, action) => {
  switch (action.type) {
    case "INCREMENT":
      return state + 1;
    case "DECREMENT":
      return state - 1;
    default:
      return state;
  }
};
let { subscribe, dispatch, getState } = createStore(reducer);

const Counter = ({ value, onIncrement, onDecrement }) => (
  <div>
    <h1>{value}</h1>
    <button onClick={onIncrement}>+</button>
    <button onClick={onDecrement}>-</button>
  </div>
);

const render = () => {
  ReactDOM.render(
    <Counter
      value={getState()}
      onIncrement={() => dispatch({ type: "INCREMENT" })}
      onDecrement={() => dispatch({ type: "DECREMENT" })}
    />,
    document.getElementById("root")
  );
};

render();
subscribe(render);

处理复杂 reducer: combineReducers

import { combineReducers, createStore } from "redux";

const todos = (state: string[] = [], action: actionType) => {
  if (action.type === "add") return [...state, action.payload];
  else return state;
};
const filterKeyword = (state: string = "", action: actionType) => {
  if (action.type === "filter") return action.payload || "";
  else return state;
};
const reducer = combineReducers({ todos, filterKeyword });

export const store = createStore(reducer); // { todos: [], filterKeyword: '' }

npm install react-redux

react-redux 官方 API

import { Provider } from "react-redux";
import { createStore } from "redux";
let store = createStore(reducer, [preloadedState]); // 参数如上

ReactDOM.render(
  <Provider store={store}>
    {" "}
    // 根部注入
    <App />
  </Provider>,
  document.getElementById("root")
);

与 react 组件关联:使用 connect(mapStateToProps, mapDispatchToProps)(Component)

import { connect } from "react-redux";

type propsType = {
  num: number,
  dispatch: Dispatch,
};

const App: React.FC<propsType> = (props: propsType) => {
  const { dispatch, num } = props;

  return <div onClick={dispatch({ type: "add" })}>{num}</div>;
};

connect((state) => ({ num: state.a || 1 }))(comp1);
  • mapStateToProps(state, ownProps) => props:每次存储状态更改时调用(会触发 rerender)。它接收整个存储状态,并应返回此组件需要的数据对象。

  • mapDispatchToProps :此参数可以是函数或对象。

    • 如果是函数,则在创建组件时将调用一次。它将 dispatch 作为参数接收,并应返回一个对象,该对象具有 dispatch 用于分派动作的完整功能。

    • 如果它是一个由动作创建者组成的对象,则每个动作创建者都将变成 prop 函数,该函数在被调用时会自动调度其动作。注意:我们建议使用此“对象简写”形式。

与 react 组件关联:使用 useSelector 和 useDispatch

// import { connect } from "react-redux";
import { useSelector, useDispatch } from "react-redux";

type propsType = {
  num: number,
  dispatch: Dispatch,
};

const App: React.FC<propsType> = (props: propsType) => {
  // const { dispatch, num } = props;
  const dispatch = useDispatch();
  const num = useSelector((state) => state.a || 1); // 返回不是对象

  return <div onClick={dispatch({ type: "add" })}>{num}</div>;
};

vuex 与 react-redux 对照表

VUEX dva
根部 new Vue({store }) 注入 <Provider store={store}><app/></Provider>
namespace 利用 combineReducers 分模块
state reducer 上的参数 state 默认值
getters 利用 connect、useSelector 整理数据
mutations reducers (只有一个入口;return 完整的 state 以更新)
actions 需要第三方 redux-saga 支持,本质是对指定reducer劫持
commit dispatch
subscribe(监听 mutation 调用) --

处理异步 redux-saga

基于 Generator 和 redux 的中间件机制

import { applyMiddleware, createStore } from 'redux';

const store = createStore(
  reducer,
  defualtVal,
  applyMiddleware(中间件1, 中间件2 ...)
);

applyMiddleware 会把中间件们依序洋葱式包裹 dispatch。redux-thunkredux-sage都是一个用来处理异步的中间件。

// 简单例子
import { createStore, applyMiddleware } from "redux";
import createSagaMiddleware from "redux-saga";

// 创建sage中间件
const sagaMiddleware = createSagaMiddleware();
const store = createStore(reducer, applyMiddleware(sagaMiddleware));
// 注册异步事件们
sagaMiddleware.run(sagaFn); // * sagaFn
// sagaFn为一个方法,run时执行,一般用来(使用takeEvery)劫持dispatch
import { put, call, takeEvery, takeLatest, all } from "redux-saga/effects";
function* sagaFn() {
  // 使用 takeEvery 劫持 async_add action
  yield takeEvery("async_add", asyncAdd);
}

function* asyncAdd() {
  const res = yield call(axios.post, "/api/test", { uid: 123 });
  yield put({ type: "add", payload: res }); // 触发正常的 add dispatch
}
  • takeEvery, takeLatest区别是后者仅执行最后一个异步方法,即不支持并发。

  • call 很像 js 原生 call(它会自己 next?)

  • put 触发 dispatch

  • 多个 sagaFn 可以

    function* allSageFn() {
      yield all([sagaFn1(), sagaFn2()]);
    }
    sagaMiddleware.run(allSageFn);
    

Redux Toolkit @reduxjs/toolkit

另一种对 Redux 的封装,此工具包中还包含一个强大的数据获取和缓存功能(RTK Query

create-react-app 默认集成了它

import { configureStore } from '@reduxjs/toolkit'

export const store = configureStore({
  reducer: { counter: counterReducer, …… }, // 切片们
})

import { Provider } from 'react-redux'

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

创建 counterReducer 切片

import { createSlice } from '@reduxjs/toolkit'

export const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    value: 0,
  },
  reducers: {
    add: (state) => {
      // 实际上不会改变状态,因为它使用Immer库,
      // 它检测对“草稿状态”的更改,并根据这些更改生成一个全新的不可变状态
      state.value += 1
    },
  },
})

export const { add } = counterSlice.actions // 导出actions

export default counterSlice.reducer // 导出切片

调用方法:

import { useSelector, useDispatch } from 'react-redux'
import { add } from './counterSlice'

export function Counter() {
    const count = useSelector((state) => state.counter.value)
    const dispatch = useDispatch()
  
  return (
    <button onClick={() => dispatch(add())}>
        点击+1,现在为:{count}
    </button>
  )
}

[TS写法在这里](https://redux-toolkit.js.org/tutorials/typescript)和这里

Redux 操作类型并不意味着对单个 slice 来说是专有的。从概念上讲,每个 slice reducer “拥有”自己的 Redux 状态,但它应该能够监听到任何动作类型。例如,“用户注销”时清除数据。???

异步操作:

  • redux-thunk:复杂同步逻辑 + 简单异步(toolkit推荐)

  • redux-saga:复杂异步逻辑,基于 ES6 generator 控制粒度更细

import { configureStore } from '@reduxjs/toolkit'

export const store = configureStore({
  reducer: { counter: counterReducer, …… }, // 切片们
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: false, // 关闭可序列化检查
    }),
  devTools: process.env.NODE_ENV !== "production",
})
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'

// First, create the thunk
const thunkUserList = createAsyncThunk('users/query', async (pageIndex) => API.getUserList(pageIndex))

// Then, handle actions in your reducers:
const usersSlice = createSlice({
  name: 'users',
  initialState: { entities: [], loading: 'idle' },
  reducers: {
    // standard reducer logic, with auto-generated action types per reducer
  },
  extraReducers: (builder) => {
    // Add reducers for additional action types here, and handle loading state as needed
    builder
      .addCase(thunkUserList.pending, state => state.loading = true)
      .addCase(thunkUserList.fulfilled, (state, action) => { 
        state.loading = false
        state.entities.push(action.payload);
      })
  },
})

// Later, dispatch the thunk as needed in the app
dispatch(thunkUserList(123))

根据 createEntityAdapter 格式化返回值

相关文章

  • Redux - 给vuex开发者

    react语法 - 给vue开发者[https://www.jianshu.com/p/726ed37f1c74]...

  • 8 - Redux 简介

    简介 Redux 是 JavaScript 状态管理器。跟 Vuex 很相似,但又不同于 Vuex。 Redux ...

  • vuex介绍

    一、vuex介绍(1)vuex是什么? 借鉴 了Flux、Redux、 The Elm Architecture ...

  • Redux 入门

    系列文章:Redux 入门(本文)Redux 进阶番外篇: Vuex — The core of Vue appl...

  • Redux 进阶

    系列文章:Redux 入门Redux 进阶(本文)番外篇: Vuex — The core of Vue appl...

  • redux

    redux: react中的状态管理工具 相当于vue中的vuex redux官方文档:https://redux...

  • Redux

    redux: react中的状态管理工具 相当于vue中的vuex redux官方文档:https://redux...

  • react redux

    redux: react中的状态管理工具 相当于vue中的vuex redux官方文档:https://redux...

  • 说说redux和vuex的不同?

    vuex是吸收了Redux的经验并且对redux的进行了调整,从而对仓库的管理更加明确,vuex还放弃了一些特性做...

  • 搞定 Mobx 小程序状态管理

    1. 前言 从vuex到 redux ,react-redux , pinia, 最后的Mobx全部都得搞;还好...

网友评论

      本文标题:Redux - 给vuex开发者

      本文链接:https://www.haomeiwen.com/subject/wwqecltx.html