跳到主要内容

React 生态核心笔记 - Redux 与 Router

· 阅读需 5 分钟

Redux 基础

安装 Redux

yarn add redux

src 目录下新建 store 文件夹,在 store 文件夹下新建 index.jsreducer.js

Store 配置(index.js)

import { createStore } from "redux";
import reducer from "./reducer";

// 配置 Redux DevTools 插件
const tools = window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__();

// 创建数据仓库,第二个参数为插件配置
const store = createStore(reducer, tools);

export default store;

Reducer 配置(reducer.js)

const defaultState = {}; // 写默认数据的地方

// state 为原始仓库的状态,action 为 action 新传入的状态
// action 包含两个参数:type(固定字段)和 value(自定义的字段)
export default (state = defaultState, action) => {
// 这里写更新 state 的状态,不能直接更改 state,需要深拷贝
// 再把新的值 return 出去
return state;
};

组件中使用 Redux

发送 Action(Test.js)

import store from './store'; // 需要配置正确的路径

// ...

changeInputValue(e) {
// action 接收两个参数:类型(type)和数据(value)
// value 为自定义的字段,可随意更换字段名
// type 为固定字段,不可更改
let action = {
type: "change_input_value",
value: e.target.value
};

store.dispatch(action); // 传递给 store
}

// ...

获取 State(TestDemo.js)

import store from './store';

// ...

constructor(props) {
super(props);
this.state = store.getState(); // 获取 Redux 中的值
}

// ...

订阅状态变化

// 订阅状态,提交 action 使用,写在 constructor 中
store.subscribe(() => this.setState(store.getState()));

代码组织技巧

技巧 1:Action 类型统一管理

// store/actionTypes.js
export const CHANGE_INPUT = 'changeInput';
export const ADD_ITEM = 'addItem';
export const DELETE_ITEM = 'deleteItem';

技巧 2:Action Creator 统一管理

// store/actionCreators.js
import { CHANGE_INPUT, ADD_ITEM, DELETE_ITEM } from "./actionTypes";

// 用箭头函数的方式存储类型和参数
const changeInputAction = (value) => ({
type: CHANGE_INPUT,
value,
});

const addItemAction = () => ({
type: ADD_ITEM,
});

const deleteItemAction = (index) => ({
type: DELETE_ITEM,
index,
});

export { changeInputAction, addItemAction, deleteItemAction };

Redux-Thunk 中间件

安装

yarn add redux-thunk

配置步骤

1. 引入 applyMiddlewarecompose

import { createStore, applyMiddleware, compose } from 'redux';

2. 引入 redux-thunk

import thunk from 'redux-thunk';

3. 创建 Store

import reducer from "./reducer";

// 使用 Redux DevTools 的 compose 增强器
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({})
: compose;

const enhancer = composeEnhancers(applyMiddleware(thunk));

const store = createStore(reducer, enhancer); // 创建数据存储仓库

export default store;

异步 Action Creator

配置完成后,可以在 actionCreators.js 中直接发送 axios 请求:

import axios from 'axios';

// 同步 action
const getListAction = (data) => ({
type: GET_LIST,
data,
});

// 异步 action(返回函数而不是对象)
export const getTodoList = () => {
return (dispatch) => {
axios
.get(`https://api.example.com/data`)
.then((res) => {
dispatch(getListAction(res.data.data));
});
};
};

Redux-Saga 中间件

安装

yarn add redux-saga

插件地址:https://github.com/redux-saga/redux-saga

Store 配置(index.js)

import { createStore, applyMiddleware, compose } from "redux";
import createSagaMiddleware from 'redux-saga'; // 引入 saga
import reducer from "./reducer";

// 创建 saga 中间件
const sagaMiddleware = createSagaMiddleware();

// 使用 Redux DevTools 的 compose 增强器
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({})
: compose;

const enhancer = composeEnhancers(applyMiddleware(sagaMiddleware));

const store = createStore(reducer, enhancer); // 创建数据仓库

export default store;

Saga 配置(sagas.js)

// store/sagas.js
import axios from "axios";
import { takeEvery, put } from "redux-saga/effects";
import { getListAction } from "./actionCreators";
import { GET_MY_LIST } from "./actionTypes";

// Generator 函数
function* mySaga() {
// 等待捕获 action
yield takeEvery(GET_MY_LIST, getList);
}

function* getList() {
const res = yield axios.get("https://api.example.com/data");
const action = getListAction(res.data.data);
yield put(action); // 派发 action
}

export default mySaga;

启动 Saga

// store/index.js
import mySagas from './sagas';

// 配置完就可以编写中间件了,具体配置查看官方文档
sagaMiddleware.run(mySagas);

React-Redux 连接器

安装

yarn add react-redux

Provider 提供器

import React from 'react';
import ReactDOM from 'react-dom';
import TodoList from './TodoList';
import { Provider } from 'react-redux';
import store from './store';

// 声明一个 App 组件,然后用 Provider 进行包裹
const App = (
<Provider store={store}>
<TodoList />
</Provider>
);

ReactDOM.render(App, document.getElementById('root'));

Connect 连接器

import { connect } from 'react-redux';  // 引入连接器

定义映射函数

// 将 state 映射到 props
const stateToProps = (state) => {
return {
inputValue: state.inputValue,
list: state.list,
};
};

// 将 dispatch 映射到 props
const dispatchToProps = (dispatch) => {
return {
inputChange(e) {
let action = {
type: "change_input",
value: e.target.value,
};
dispatch(action); // 派发 action
},
clickButton() {
let action = {
type: "add_item",
};
dispatch(action);
},
};
};

导出连接后的组件

export default connect(stateToProps, dispatchToProps)(TodoList);
// 第一个参数为 stateToProps,第二个为 dispatchToProps

React Router

(内容待补充...)