Redux 详细使用流程(React)

一、下载相关依赖包

yarn add redux react-redux redux-actions redux-logger redux-saga

依赖包说明:

  • redux:redux 状态机的核心文件
  • react-redux:用于关联 react 组件和 redux 状态机
  • redux-actions:提供便捷创建 action 对象和 reducer 函数的方法
  • redux-logger:redux 中间件,用来显示 redux 中数据的操作日志
  • redux-saga:redux 中间件,用来处理 redux 中的异步操作

二、搭建 redux 目录结构

  • 在项目的 src 目录中创建一个 redux 目录,用来保存所有关于状态机相关的代码;
  • 在 redux 中创建 store.js 文件,用来作为仓库主文件;
  • 在 redux 中依次创建 actions、reducers、sagas 目录,用来保存所有功能模块各自的 action
    对象、reducer 函数以及 saga 方法;
  • 在 redux 中创建 actionTypes.js 文件,用来保存所有 action 的 type 值常量;
  • 在 redux 中创建 combineReducers.js 文件,用来合并 reducers 目录中的所有 reducer 函数;
  • 在 redux 中创建 rootSaga.js 文件,用来启动 sagas 目录中的所有侦听函数;

image-20220114152651538

三、配置仓库主文件

在 store.js 中完成对 redux 仓库的创建:

import { createStore } from 'redux';
const store = createStore();
export default store;

在 src/index.js 文件中引入仓库主文件,并将仓库对象注入到全局:

// ...
import store from './redux/store.js'
import { Provider } from 'react-redux'
ReactDOM.render(
    <Provider store={store}>
        <App />
    </Provider>,
    document.getElementById('root')
);

四、设置商品分类初始值

在 /src/redux/reducers 目录中创建一个 categoriesReducers.js 文件,作为商品分类的 reducer 函数配置文件:

import { handleActions } from 'redux-actions'
// 初始值
const initState = {};
const categoriesReducer = handleActions({
    // ...
}, initState)

export default categoriesReducer;

将暴露出去的 categoriesReducer 在 combineReducers.js 文件中引入并进行合并:

import { combineReducers } from 'redux'
import categoriesReducers from './reducers/categoriesReducers.js'

export default combineReducers({
    categories: categoriesReducers
})

再回到仓库主文件 store.js 中,将合并好的 reducer 添加到仓库中:

import combineReducers from './combineReducers.js'
const store = createStore(combineReducers);

到这一步,商品分类的初始值才成功的保存到仓库中。

五、组件关联仓库

在组件中,通过 react-redux 提供的 connect 方法,将组件和仓库关联起来:

import { connect } from 'react-redux'

class Categories extends Component {
    // ...
}

const mapStateToProps = state => {
    return {}
}
export default connect(mapStateToProps)(Categories)

六、创建 action 对象(异步获取分类数据)

接下来我们希望能在组件中通过 dispatch 触发 redux 中的异步请求,来获取商品分类数据。因此需要先创建 dispatch 需要的 action 对象。

创建 action 的 type 常量
创建 action 对象需要 type 值,因此我们先在 actionTypes.js 文件中将“发送请求获取分类商品数据”这个操作的 type 值设置出来:

const types = {
    GET_CATEGORIES_ASYNC: 'getCategoriesAsync'
}
export default types;

type 常量值创建成功后,就可以在 actions 目录中创建一个 categoriesActions.js 文件,用来创建商品分类相关的 action 对象:

import { createAction } from 'redux-actions'
import types from '../actionTypes'

export const getCategoriesAsyncAction = createAction(types.GET_CATEGORIES_ASYNC);

最后暴露出去的 getCategoriesAsyncAction 是一个函数,该函数内部返回了一个 action 对象。

七、组件中使用 dispatch 发出命令

在商品分类组件中,我们希望组件挂载完成时,就通过 dispatch 方法发出一个命令,让仓库中去发送异步请求获取商品分类数据:

import { getCategoriesAsyncAction } from '../../../redux/actions/categoriesActions.js'

class Categories extends Component {
    state = {
        data: []
    }
    componentDidMount() {
        this.getCategories();
    }
    getCategories = async () => {
        this.props.dispatch(getCategoriesAsyncAction({ parentId: 0 }))
    }
}

八、仓库中配置 saga 侦听函数

组件中发出的命令,需要在 saga 中通过 takeEvery() 方法去侦听。因此,我们在 sagas 目录中,创建一个 categoriesSagas.js 文件,作为商品分类的 saga 处理文件:

import { takeEvery } from 'redux-saga/effects'
import types from '../actionTypes'

function* getCategories() {

}


// 1. 设置侦听函数
function* watchCategories() {
    // 第一个参数:侦听的操作对应的 type 值
    // 第二个参数:侦听的 type 被 dispatch 时要执行的函数
    yield takeEvery(types.GET_CATEGORIES_ASYNC, getCategories)
} 

export default watchCategories;

九、启动 saga 侦听函数

考虑到项目中,不止一个侦听函数,因此,我们在 rootSaga.js 中通过 all() 方法来实现对所有侦听函数的并行启动:

import { all } from 'redux-saga/effects';
import watchCategories from './sagas/categoriesSagas.js'

function* rootSaga() {
    yield all([watchCategories()])
}

export default rootSaga;

十、在仓库中引入 saga 中间件

最后,要让 saga 中间件在 store 中生效,需要在 store.js 中配置:

import { createStore, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';
const saga = createSagaMiddleware();
const store = createStore(combineReducers, applyMiddleware(saga));

saga 生效后,还要让 saga 去运行 rootSaga.js 中的函数:

import { createStore, applyMiddleware } from 'redux';
import combineReducers from './combineReducers.js'
import createSagaMiddleware from 'redux-saga'
import rootSaga from './rootSaga.js'
const saga = createSagaMiddleware();
const store = createStore(combineReducers, applyMiddleware(saga));
saga.run(rootSaga);
export default store;

十一、saga 函数中发送异步请求

到这一步为止,我们基础配置就已经完成了。

接下来,找到 categoriesSagas.js 文件,在侦听函数执行的 getCategories 方法中,输出 action 对象,来检测组件中 dispatch 时能不能成功触发该方法,同时也查看一下能否接收到组件中传递的 action 对象:

import { takeEvery } from 'redux-saga/effects'
import types from '../actionTypes'

// 2. 组件中 dispatch 时真正要执行的函数
function* getCategories(action) {
    console.log(action)
}

// 1. 设置侦听函数
function* watchCategories() {
    // 第一个参数:侦听的操作对应的 type 值
    // 第二个参数:侦听的 type 被 dispatch 时要执行的函数
    yield takeEvery(types.GET_CATEGORIES_ASYNC, getCategories)
} 

export default watchCategories;

如果确保该函数能成功执行,也能接收到 action 对象,就下来,就可以在该函数中调用封装好的 api 接口,发送异步请求了:

import { call } form 'redux-saga/effects'
import { getCategoriesAsync } from '../../api/categories'

// 2. 组件中 dispatch 时真正要执行的函数
function* getCategories(action) {
    const res = yield call(getCategoriesAsync, action.payload);
    console.log(res);
}

如果输出 res 能够接收到后端返回的数据,就说明我们组件通过 redux 发送异步请求成功了。

十二、创建 action 对象(修改仓库分类数据)

当我们在 saga 中成功获取到后端返回的仓库数据后,下一步,我们就希望通过 dispatch 发出一个新的命令:用新数据修改仓库中保存的初始旧数据。

因此,针对这个新的操作,我们又需要在 actionTypes.js 中创建新的 type常量值,以及在 categoriesActions.js 中创建对应的 action 对象。

创建 action 的 type 常量

const types = {
    GET_CATEGORIES_ASYNC: 'getCategoriesAsync',
    SET_CATEGORIES: 'setCategories'
}
export default types;

常量创建完成后,就可以创建 action 对象了:

import { createAction } from 'redux-actions'
import types from '../actionTypes'

// 表示“通过异步请求获取分类数据”
export const getCategoriesAsyncAction = createAction(types.GET_CATEGORIES_ASYNC);

// 表示“修改仓库中的分类数据”
export const setCategoriesAction = (payload) => {
    // return 的就是 action 对象
    return {
        type: types.SET_CATEGORIES,
        payload
    }
}

十三、saga 中使用 put 发出命令

action 创建完成后,就可以使用了。

但是,由于在 saga 中获取不到 dispatch,因此,我们可以用 redux-saga 提供的 put 方法来代替 dispatch:

import { getCategoriesAsync } from '../../api/categories'
import { setCategoriesAction } from '../actions/categoriesActions.js'

function* getCategories(action) {
    const res = yield call(getCategoriesAsync, action.payload);
    if(res.code) {
        // 将数据保存到仓库中:希望 dispatch 发出一个命令,调用 reducer 修改仓库数据
        yield put(setCategoriesAction(res.data));
    }
}

当 put 方法执行时,就会调用 categoriesReducers.js 文件中的 reducer 函数了。

十四、配置 reducer

一开始的 reducer 中,我们只保存了分类数据的初始值。

接下来,我们要在 reducer 中配置“修改分类数据”的操作:

import { handleActions } from 'redux-actions'
import types from '../actionTypes.js'

const initState = {};

const categoriesReducer = handleActions({
    [types.SET_CATEGORIES]: (state, action) => {
        // console.log('接收到的是 saga 中通过 put 传递的值', action);
        return action.payload;
    }
}, initState)

export default categoriesReducer;

配置完成后,当 saga 中调用 put 方法时,就会执行 reducer 函数中对应的 type 的操作了。

我们就能成功的将后端返回的数据保存到仓库中了。

十五、组件获取仓库中的分类数据

我们在前面第五步时,就用组件去关联了仓库。

现在,只需要在 mapStateToProps 方法中将仓库的分类数据传递给组件的 props 即可:

const mapStateToProps = state => {
    console.log('组件中获取仓库中所有的数据', state);
    return {
        data: state.categories.data
    }
}

这样,组件中就可以通过 this.props.data 来访问仓库中的分类数据了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值