Redux及Vuex相关内容梳理

225 阅读4分钟

Redux相关

一 、Redux

1、Store

个人理解Store是redux的核心,通过createStore创建store,并通过store的函数操作里面的数据,如dispacth。

const store = createStore(reducer);

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

store.dispatch(actions.increase()); // {count: 1}
store.dispatch(actions.increase()); // {count: 2}
store.dispatch(actions.increase()); // {count: 3}

2、Action

个人理解action是判定进行哪些操作的行为。其中根据type选项,筛选Reducer中执行那些操作

export const actions = {
    increase: () => ({ type: "INCREASE" }),
    decrease: () => ({ type: "DECREASE" })
};

3、Reducer

reducer接收state和action,返回新的state,state是redux的数据。reducer主要是通过筛选目标action执行相关数据操作并更新state。

const reducer = (state = { count: 0 }, action: { type: any }) => {
    switch (action.type) {
        case "INCREASE":
            return { count: state.count + 1 };
        case "DECREASE":
            return { count: state.count - 1 };
        default:
            return state;
    }
};

二、react-redux

Provider

个人理解,通过Provider组件把store导入到子组件中,可以在子组件中接受到相关数据。

import { Provider } from "react-redux";
import { store } from "./redux/store";
...
            <Provider store={store}>
                <App a="1"></App>
            </Provider>
...

connect()

个人理解,connect接收两个参数,mapStateToProps,mapDispatchToProps,第一个参数mapStateToProps(名称可变)目的是从store中获取参数映射到props中,第二个参数是将dispatch也封装函数导入到props直接使用

import { connect } from "react-redux";
const mapStateToProps = (state: any) => {
    return {
        // prop : state.xxx  | 意思是将state中的某个数据映射到props中
        foo: state.count
    };
};

const mapDispatchToProps = (dispatch: any) => {
    return {
        increase: () => {
            dispatch({
                type: "INCREASE"
            });
        }
    };
};

const UseRedux = (props: any) => {
    return (
        <>
            <p>{props.foo}</p>
            <button onClick={props.increase}>increase</button>
        </>
    );
};
export default connect(mapStateToProps, mapDispatchToProps)(UseRedux);

useSelector

通过useSelector直接拿到store中的数据

import { useSelector } from "react-redux";
export default () => {
    const { value } = useSelector((store: any) => {
        return store.counter;
    });

    return (
        <>
            <p>{value}</p>
        </>
    );
};

useDispatch

通过useDispatch返回dispatch函数


import { counterSlice } from "../redux/tookit";
const { increment, decrement } = counterSlice.actions;
import { useDispatch } from "react-redux";
export default () => {
    const dispatch = useDispatch();

    return (
        <>
            <button onClick={() => dispatch(increment())}>increment</button>
        </>
    );
};

useStore

通过useStore返回useStore对象

    const store = useStore();

三、Redux Toolkit

Redux Toolkit简化了redux开发流程

createReducer

帮你将 action type 映射到 reducer 函数,而不是编写 switch...case 语句。另外,它会自动使用 [immer 库]

const initialState: CounterState = {
    value: 0,
    title: "redux toolkit pre"
};
// 创建一个 Slice
export const counterSlice = createSlice({
    name: "counter",
    initialState,
    // 定义 reducers 并生成关联的操作
    reducers: {
        // 定义一个加的方法
        increment: (state) => {
            state.value += 1;
        },
        // 定义一个减的方法
        decrement: (state) => {
            state.value -= 1;
        }
    }
});

configureStore

封装了createStore,简化配置项,提供一些现成的默认配置项。它可以自动组合 slice 的 reducer,可以添加任何 Redux 中间件,默认情况下包含 redux-thunk,并开启了 Redux DevTools 扩展。

// configureStore创建一个redux数据
const store = configureStore({
    // 合并多个Slice
    reducer: {
        counter: counterSlice
    }
});
  • configureStore():封装了createStore,简化配置项,提供一些现成的默认配置项。它可以自动组合 slice 的 reducer,可以添加任何 Redux 中间件,默认情况下包含 redux-thunk,并开启了 Redux DevTools 扩展。
  • createReducer() 帮你将 action type 映射到 reducer 函数,而不是编写 switch...case 语句。另外,它会自动使用 immer 库来让你使用普通的 mutable 代码编写更简单的 immutable 更新,例如 state.todos[3].completed = true
  • createAction() 生成给定 action type 字符串的 action creator 函数。该函数本身已定义了 toString(),因此可以代替常量类型使用。
  • createSlice() 接收一组 reducer 函数的对象,一个 slice 切片名和初始状态 initial state,并自动生成具有相应 action creator 和 action type 的 slice reducer。
  • createAsyncThunk: 接收一个 action type 字符串和一个返回值为 promise 的函数, 并生成一个 thunk 函数,这个 thunk 函数可以基于之前那个 promise ,dispatch 一组 type 为 pending/fulfilled/rejected 的 action。
  • createEntityAdapter: 生成一系列可复用的 reducer 和 selector,从而管理 store 中的规范化数据。
  • createSelector 来源于 Reselect 库,重新 export 出来以方便使用。

四、redux-thunk(感觉没必要)

redux-thunk目的是将dispatch原本只能接受object数据,扩展了一些,可以传输函数。 功能:

const mapDispatchToProps = (dispatch: any) => {
    return {
        useThunk: () => {
            dispatch(() => {
                setTimeout(() => {
                    dispatch({
                        type: "USETHUNK"
                    });
                }, 1000);
            });
        }
    };
};

源码相当于

function createThunkMiddleware(extraArgument) {
    return ({ dispatch, getState }) =>
        (next) =>
        (action) => {
            if (typeof action === "function") {
                return action(dispatch, getState, extraArgument);
            }

            return next(action);
        };
}

const thunk = createThunkMiddleware(null);
thunk.withExtraArgument = createThunkMiddleware;

export default thunk;

vuex

vuex核心概念

State

State是vuex的数据源,所有共享的数据统一放到store的state进行储存,相似与data。

const state = {
  token: getToken(),
  name: '',
  avatar: '',
  introduction: '',
  roles: []
}

使用方法

  • 1、this.$store.state.settings.theme
  • 2、使用mapState混入到computed
import { mapState } from 'vuex'

····
  computed: {
    ...mapState({
      sidebar: state => state.app.sidebar,
      device: state => state.app.device
    }),
  },
····

Mutation

mutation是同步修改数据,更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。mutation里面包含修改state的具体函数操作。

const mutations = {
  CLOSE_SIDEBAR: (state, withoutAnimation) => {
    Cookies.set('sidebarStatus', 0)
    state.sidebar.opened = false
    state.sidebar.withoutAnimation = withoutAnimation
  },
  TOGGLE_DEVICE: (state, device) => {
    state.device = device
  },
  SET_SIZE: (state, size) => {
    state.size = size
    Cookies.set('size', size)
  }
}

Action

Action异步修改数据,actions中可以进行异步操作,然后调用mutation间接变更state。

const actions = {
  toggleSideBar({ commit }) {
    commit('TOGGLE_SIDEBAR')
  },
  closeSideBar({ commit }, { withoutAnimation }) {
    commit('CLOSE_SIDEBAR', withoutAnimation)
  },
  toggleDevice({ commit }, device) {
    commit('TOGGLE_DEVICE', device)
  },
  setSize({ commit }, size) {
    commit('SET_SIZE', size)
  }
}

Getter

相当于计算属性,虽然组件component中有computed,但是getter可以再多个组件复用

const getters = {
  sidebar: state => state.app.sidebar,
  size: state => state.app.size,
  device: state => state.app.device,
  visitedViews: state => state.tagsView.visitedViews,
  cachedViews: state => state.tagsView.cachedViews,
  token: state => state.user.token,
  avatar: state => state.user.avatar,
  name: state => state.user.name,
  introduction: state => state.user.introduction,
  roles: state => state.user.roles,
  permission_routes: state => state.permission.routes,
  errorLogs: state => state.errorLog.logs
}

调用方式this.$store.getters.errorLogs

Modules

Modules即模块,为了解决数据量大store会显得很臃肿问题,所以store可以分割为module,每个模块拥有自己的 state、mutation、action、getter、甚至是可以嵌套子模块。 以下为整合modules并生成store。

// 导入各个module文件
const modulesFiles = require.context('./modules', true, /\.js$/)

// you do not need `import app from './modules/app'`
// it will auto require all vuex module from modules file
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
  // set './app.js' => 'app'
  const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
  const value = modulesFiles(modulePath)
  modules[moduleName] = value.default
  return modules
}, {})

const store = new Vuex.Store({
  modules,
  getters
})

参考内容

Redux 最佳实践 Redux Toolkit 🔥🔥

Redux Toolkit

# Vuex详解,一文彻底搞懂Vuex