目录
扩展学习资料
Redux基础
Redux动机
Redux核心概念
Redux的三个原则
Redux运转图
React & Redux的搭配使用
Redux API
React-Redux API(关联组件)
从头创建一个工程
@package.json
@/src/reducer/index.js
@/src/reducer/home/index.js
@/src/actions/home/index.js
@/src/actions/mutation-types.js
@/src/store/index.js
@/src/index.jsx
@/src/routes/index.js
@/src/view/index.html
@/src/app.jsx
@/src/containers/home/index.jsx
小结
扩展学习资料
名称 | 链接 |
Redux 文档 | Redux 中文文档 · Redux |
Redux 插件 | redux middleware 详解 - 知乎 |
构建复杂React应用
Redux基础
Redux动机
为什么需要Redux?
- Redux适合于大型复杂的单页面应用。
单页面应用;需要管理的状态;多且复杂;页面之间共享状态
Redux核心概念
state : 应用全局数据的来源,数据驱动视图的核心
action: 数据发生改变动作的描述
reducer : 结合state和action,并返回一个新的state
Redux的三个原则
三大原则
- 单一数据源 整个应用的state被储存在一棵object tree中,并且这个object tree 只存在于唯一一个store中。
- State 是只读的 唯一改变state的方法就是触发action,action是一个用于描述已发生事件的普通对象。
- 使用纯函数来执行修改State 可纯函数意味着同样的输入就会有同样的输出。
Redux运转图
全局状态Store操控->视图View变更触发->Actions->Reducers接收->返回给Store不同的小state构成全局状态Store
React & Redux的搭配使用
Redux API
- createStore 创建一个Reudx store 来存放应用中所有的state。
- combineReducers 将多个不同reducer函数作为value的object,合并成一个最终的reducer函数。
- applyMiddleware 接受自定义功能的middleware来扩展Redux。
- compose 函数式编程中的方法,右到左来组合执行参数。
React-Redux API(关联组件)
- connect 将React组件与Redux链接起来。
- Provider 提供被connect链接起来的组件能够访问得到Store。
从头创建一个工程
@package.json
// yarn
// 报错,清一下缓存:yarn cache clean
{
"name": "redux-reselect",
"version": "1.0.0",
"description": "reselect",
"main": "index.js",
"scripts": {
"start": "webpack-dev-server --hot --color --progress --host localhost --config webpack.config.js --env.dev",
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/luzuoquan/redux-reselect.git"
},
"keywords": [
"reselect",
"redux"
],
"author": "luzuoquan",
"license": "MIT",
"bugs": {
"url": "https://github.com/luzuoquan/redux-reselect/issues"
},
"homepage": "https://github.com/luzuoquan/redux-reselect#readme",
"devDependencies": {
"@babel/cli": "^7.8.4",
"@babel/core": "^7.9.6",
"@babel/plugin-proposal-class-properties": "^7.8.3",
"@babel/plugin-proposal-decorators": "^7.8.3",
"@babel/plugin-proposal-export-default-from": "^7.8.3",
"@babel/plugin-transform-runtime": "^7.9.6",
"@babel/preset-env": "^7.9.6",
"@babel/preset-react": "^7.9.4",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.1.0",
"eslint": "6.8.0",
"eslint-config-airbnb": "^18.1.0",
"eslint-import-resolver-webpack": "^0.12.1",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-react": "^7.19.0",
"eslint-plugin-react-hooks": "3.0.0",
"html-webpack-plugin": "^4.3.0",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.11.0"
},
"dependencies": {
"@babel/runtime": "^7.9.6",
"core-js": "^3.6.5",
"immer": "^7.0.1",
"prop-types": "^15.7.2",
//react
"react": "^16.13.1",
"react-dom": "^16.13.1",
// router
"react-router": "^5.1.2",
"react-router-dom": "^5.1.2",
// redux
"react-redux": "^7.2.0",
"redux": "^4.0.5",
"redux-thunk": "^2.3.0",
"regenerator-runtime": "^0.13.5",
"reselect": "^4.0.0",
"whatwg-fetch": "^3.0.0"
}
}
@/src/reducer/index.js
import { combineReducers } from 'redux';
import homeReducer from './home';
// console.log(reSelectReducer());
// 合并多个reducer
// 扩展性
export default combineReducers({
homeReducer,
//...
});
@/src/reducer/home/index.js
import * as types from '@/actions/mutation-types';
// 初始值
const initialState = {
homeName: '云',
};
// 操作
const mutations = {
// 获取
[types.QUERY_GLOBAL_NAME](state) {
return { ...state }; // 解构
},
// 更新
[types.UPDATE_GLOBAL_NAME](state, action) {
return {
...state,
homeName: action.payload,
};
},
};
export default function (state = initialState, action) {
// 如果当前动作不存在,返回初始值
if (!mutations[action.type]) return state;
// 执行对应方法
return mutations[action.type](state, action);
}
@/src/actions/home/index.js
import * as types from '../mutation-types';
// 请求数据方法
export function queryName(params) {
return {
type: types.QUERY_GLOBAL_NAME,
payload: params,
};
}
// 改变数据方法
export function updateName(params) {
return {
type: types.UPDATE_GLOBAL_NAME,
payload: params,
};
}
// 异步请求数据
export function queryAsyncName(params) {
return (dispatch) => {
setTimeout(() => {
dispatch({
type: types.QUERY_GLOBAL_NAME,
payload: params,
});
}, 2000);
};
}
// 异步修改数据
export function asynUpdatecName(params) {
return async (dispatch) => {
setTimeout(() => {
dispatch(updateName(params));
}, 3000);
};
}
@/src/actions/mutation-types.js
// 所有动作枚举文件
// 查询
export const QUERY_GLOBAL_NAME = 'QUERY_GLOBAL_NAME';
// 更新
export const UPDATE_GLOBAL_NAME = 'UPDATE_GLOBAL_NAME';
export const FILTER_ALL_DATA = 'FILTER_ALL_DATA';
export const FILTER_SUCCESS_STATUS = 'FILTER_SUCCESS_STATUS';
export const FILTER_FAIL_STATUS = 'FILTER_FAIL_STATUS';
export const UPDATE_FILTER_STATUS = 'UPDATE_FILTER_STATUS';
export const UPDATE_IMMUTABLE_DATA = 'UPDATE_IMMUTABLE_DATA';
export const UPDATE_REDUX_ACTIONS_DATA = 'UPDATE_REDUX_ACTIONS_DATA';
@/src/store/index.js
import { createStore } from 'redux';
import reducers from '@/reducer';
export default createStore(
reducers
);
@/src/index.jsx
import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import store from './store';
import App from './app';
render(
// Provider提供被connect链接起来的组件能够访问得到Store。
<Provider store={store}>
<App />
</Provider>,
document.querySelector('#app'),
);
@/src/routes/index.js
import React from 'react';
import {
BrowserRouter,
Route,
} from 'react-router-dom';
import Home from '@/containers/home';
export default function () {
return (
<BrowserRouter>
<Route exact path="/" component={Home} />
</BrowserRouter>
);
}
@/src/view/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React Redux Demo</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
@/src/app.jsx
import React from 'react';
import Routes from '@/routes';
export default () => <Routes />;
@/src/containers/home/index.jsx
/* eslint-disable react/no-unused-prop-types */
import React, { Component } from 'react';
import {
updateName,
queryAsyncName
} from '@/actions/home';
import { connect } from 'react-redux';
// react-redux API connect将组件与react链接起来
// connect与home页面关联起来,装饰器写法
@connect(
(state) => state.homeReducer,
(dispatch) => ({
updateName: (params) => dispatch(updateName(params)),
}),
)
export default class Home extends Component {
handleClick = () => {
const {
updateName,
} = this.props;
updateName('修改云课堂');
}
render() {
const { homeName } = this.props;
return (
<div>
<div>
{homeName}
</div>
<button
type="button"
onClick={this.handleClick}
>
更改
</button>
</div>
);
}
}
小结
Redux基础:核心原则【改变数据的方式只能事action】
React-Redux :只做一个单页面应用的流程