[React] 15 - Redux Toolkit

Ref: Redux 最佳实践 Redux Toolkit

 

前言

使用过 Vuex 再来使用 Redux 我自己的感觉就是 Redux 的写法太复杂、太分散了,不像 Vuex 在一个文件里聚合所有东西。但现在 Redux 官方推出了 Redux Toolkit,从此 Redux 写起来也能很爽了。

Redux 是什么?

Redux 是一个使用叫做 “action” 的事件来管理和更新应用状态的模式和工具库 它以集中式 Store 的方式对整个应用中使用的状态进行集中管理,确保状态只能以可预测的方式更新。

Redux Toolkit 是什么?

Redux Toolkit 是官方推荐的编写 Redux 逻辑的方法。 它包含我们对于构建 Redux 应用程序必不可少的包和函数。 Redux Toolkit 的构建简化了大多数 Redux 任务,防止了常见错误,并使编写 Redux 应用程序变得更加容易。可以说 Redux Toolkit 就是目前 Redux 的最佳实践方式。

 
 
# 建立 React 工程
$ npx create-react-app reactweb2
$ cd reactweb2
# 安装 Redux Toolkit $ npm install redux react
-redux @reduxjs/toolkit

 

 

创建 store

都写在了一个文件内:/src/store/index.js,之前则是 ./redux/store.js

Ref: https://cn.redux-toolkit.js.org/tutorials/quick-start

import { createSlice, configureStore } from '@reduxjs/toolkit';

 

  • initialState & reducers

之前,reducer与initialState放在reducer.py文件;现在,则都在 createSlice中处理。

/**
 * 初期状态数据
 */
const initialState = {
    sitename: '小马学React',
    viewCount: 0,
}

/**
 * 建立一个单独的状态分片
 */
const mywebSlice = createSlice({
    name: 'myweb',
    initialState,
    reducers: {          // 这里直接定义了若干函数~
        add(state) {
            state.viewCount++;
        },
        minus(state) {
            state.viewCount--;
        },
        multiply(state, action) {
            state.viewCount *= action.payload;
        },
    },
})

 

如果有另一个?可以定义在同一个文件,也可以定义在不同的文件然后被index.js引用即可。

/**
 * 认证授权状态数据
 */
const initialAuthState = {
    isAuthed: false,
}

/**
 * 建立一个认证授权状态分片
 */
const authSlice = createSlice({
    name: 'auth',
    initialState: initialAuthState,
    reducers: {
        login(state) {
            state.isAuthed = true
        },
        logout(state) {
            state.isAuthed = false
        },
    },
})

 

  • store & actions

导出了两部分:1) 以 store 为首的 reducer, state;  2) action 

但却没有导出 mywebSlice?不需要,“构建过程”中,应该为其他函数已经提供了足够的资源。

/**
 * 应用程序状态(共用)
 */
const store = configureStore({
    // reducer: { myweb: mywebSlice.reducer },
    reducer: mywebSlice.reducer,
... });
/** * 输出操作函数 */ export const mywebActions = mywebSlice.actions;
... ...
/** * 输出状态对象 */ export default store;

 

 

使用 store

一个组件的例子:/components/LearnRedux.js

注意 useSelector 将 store处的 state 拿了过来~

import React from "react";
import { useSelector, useDispatch } from "react-redux";
import { mywebActions } from "../store";

const LearnReduxToolkit = () => {
    const sitename  = useSelector(state => state.sitename)
    const viewCount = useSelector(state => state.viewCount)

// 下面的操作改变了上面的变量,然后自动进行渲染
const dispatch
= useDispatch() const btn_add_click = () => { dispatch(mywebActions.add()) } const btn_minus_click = () => { dispatch(mywebActions.minus()) } const btn_multiply_click = () => { dispatch(mywebActions.multiply(10)) } return ( <React.Fragment> <h1>{sitename}</h1> <h2>{viewCount}</h2> <hr /> <div> <button className="btn btn-primary btn-lg m-1" onClick={btn_add_click}>Add</button> <button className="btn btn-success btn-lg m-1" onClick={btn_minus_click}>Minus</button> <button className="btn btn-danger btn-lg m-1" onClick={btn_multiply_click}>Multiply</button> </div> </React.Fragment> ) } export default LearnReduxToolkit;

 

 

 

Thunk Async 异步处理


Ref: React.js 中文开发入门教学 - Redux - Redux Toolkit - Thunk Async 异步处理

 

客户端, click button 与 state updated 是分开进行的。 

 

先搞定 initialState & reducers。

const initialState = {
...
    datalist: [],
}
...

//////////////////////////////////////////////
reducers: { ... setDatalist(state, action) { state.datalist
= action.payload; }, ...

 

属于使用 store 以实现异步 loadData。这个作为 “过渡”;(有点增强的意思。异步的一个文件,其他原本的 在一个文件

/src/store/asyncActions.js

import { mywebActions } from "./myweb"; export const loadData= () => {
return async (dispatch) => {

// 定义好 const fetchData
= async () => { const response = await fetch('https://swapi.dev/api/films', { method: 'GET', // body: '', headers: { 'user-agent': 'Mozilla/99.0 MDN Example', 'content-type': 'application/json' }, }) if (!response.ok) throw new Error('HTTP Error!') const data = response.json() return data } try {
// 1. 先清空 dispatch(mywebActions.setDatalist([]))
// 2. 提交服务器取得数据(这里使用) const resultData = await fetchData() // 打印出返回的数据 console.log(resultData.results)
// 3. 更新状态数据 dispatch(mywebActions.setDatalist(resultData.results))
}
catch (err) { console.error(err) dispatch(mywebActions.minus()) }
} }

 

再被 component 调用。

注意 useSelector 将 store处的 state 拿了过来~

import { loadData } from "../store/asyncActions";
...
    const datalist = useSelector(state => state.myweb.datalist)
...
    const btn_loaddata_click = async () => {
        dispatch(loadData())   // 调用后,state会自动更新,然后下面相关部分就会 render
    }
...
    <div>
        <button className="btn btn-warning btn-lg" onClick={btn_loaddata_click}>LoadData</button>
        <hr />
        {datalist.map((item) => (
            <div key={item.episode_id}>
                <h3>{item.title}</h3>
            </div>
        ))}
    </div>

 

 

 
posted @ 2018-05-22 13:06  郝壹贰叁  阅读(124)  评论(0编辑  收藏  举报