1.什么是Redux?
Redux
是一个管理状态(数据)的容器,提供了可预测的状态管理
2.什么是可预测的状态管理?
数据在什么时候? 因为什么?发生了什么改变?都是可以控制和追踪的, 我们就称之为预测的状态管理
3.为什么要使用Redux?
- React是通过数据驱动界面更新的,React负责更新界面, 而我们负责管理数据
- 默认情况下我们可以在每个组件中管理自己的状态, 但是现在前端应用程序已经变得越来越复杂
状态之间可能存在依赖关系(父子、共享等),一个状态的变化会引起另一个状态的变化 - 所以当应用程序复杂的时候, 状态在什么时候改变,因为什么改变,发生了什么改变,就会变得非常难以控制和追踪
- 所以当应用程序复杂的时候,我们想很好的管理、维护、追踪、控制状态时, 我们就需要使用Redux
4.Redux核心理念
- 通过
store
来保存数据 - 通过
action
来修改数据 - 通过
reducer
将store
和action
串联起来
模拟数据表示三者之间的关联
const initialState = { heroes:[ {name:'鲁班', age:18}, {name:'虞姬', age:22}, ] } const action = {type:'CHANGE_NAME', playload:{index:0, newName:'黄忠'}} const action = {type:'CHANGE_AGE', playload:{index:1, newAge:66}} function reducer(state = initialState, action){ switch(action.type){ case: 'CHANGE_NAME': // 修改姓名 return newState; case: 'CHANGE_AGE': // 修改年龄 return newState; } }
------------- ---------> | Component | --------- | ------------- | | ↓ ------------- ------------- ------------- | Store | <---- | Reducer | <---- | Action | ------------- ------------- -------------
1.Redux三大原则
- 单一数据源
- 整个应用程序的state只存储在一个 store 中
- Redux并没有强制让我们不能创建多个Store,但是那样做并不利于数据的维护
- 单一的数据源可以让整个应用程序的state变得方便维护、追踪、修改
- State是只读的
- 唯一修改State的方法一定是触发action,不要试图在其他地方通过任何的方式来修改State
- 这样就确保了View或网络请求都不能直接修改state,它们只能通过action来描述自己想要如何修改stat;
- 这样可以保证所有的修改都被集中化处理,并且按照严格的顺序来执行,所以不需要担心race condition(竟态)的问题;
- 使用纯函数来执行修改
- 通过reducer将 旧state和 action联系在一起,并且返回一个新的State:
- 随着应用程序的复杂度增加,我们可以将reducer拆分成多个小的reducers,分别操作不同state tree的一部分
- 但是所有的reducer都应该是纯函数,不能产生任何的副作用
2.什么是纯函数?
- 返回结果只依赖于它的参数,并且在执行过程里面没有副作用
// 纯函数 function sum(num1, num2){ return num1 + num2; } // 非纯函数 let num1 = 10; function sum(num2){ return num1 + num2; } // 纯函数 const 定义的变量是不能改变的,因此不会影响到外部变量,是纯函数 const num1 = 10; function sum(num2){ return num1 + num2; }
官方文档: https://www.redux.org.cn/docs/introduction/ThreePrinciples.html
3.Redux 的使用
Redux 除了和 React 一起用外,还支持其它界面库
- 安装稳定版:
npm install --save redux
- 使用redux
const redux = require('redux'); // 定义一个状态 let initialState = { count: 0 }; // 利用store来保存状态(state) const store = redux.createStore(reducer); // 利用action来修改状态 const addAction = {type:'ADD_COUNT', num: 1}; const subAction = {type:'SUB_COUNT', num: -1}; // 利用reducer将store和action串联起来 function reducer(state = initialState, action) { switch (action.type) { case 'ADD_COUNT': return {count: state.count + action.num}; case 'SUB_COUNT': return {count: state.count - action.num}; default: return state; } } // 在组件中如何监听状态的改变? store.subscribe((a)=>{ console.log(store.getState()); }); // 在组件中如何从Store中获取存储的状态? console.log(store.getState()); // 在组件中如何修改Store中存储的状态? store.dispatch(addAction); // console.log(store.getState());
4.Redux的优化
当前代码存在的问题:
- store、action、reducer代码都写在一个文件中, 不利于维护
- action和reducer中都是使用字符串来指定和判断操作类型, 写错不报错
- action中的操作写死了, 不够灵活
image.png
// app.js import React from 'react'; import store from './store/store'; import {addAction, subAction} from './store/action'; class App extends React.PureComponent{ constructor(props){ super(props); this.state = { count: store.getState().count } } componentDidMount() { store.subscribe(()=>{ this.setState({ count: store.getState().count }) }) } componentWillUnmount() { store.unsubscribe(); } render(){ return ( <div> <p>{this.state.count}</p> <button onClick={()=>{this.btnClick()}}>增加</button> </div> ) } btnClick(){ store.dispatch(addAction(5)); } } export default App;
//store.js import {createStore} from 'redux'; import reducer from './reducer'; // 利用store来保存状态(state) const store = createStore(reducer); export default store;
// constants.js export const ADD_COUNT = 'ADD_COUNT'; export const SUB_COUNT = 'SUB_COUNT';
//action.js import { ADD_COUNT, SUB_COUNT } from './constants'; // 利用action来修改状态 // const addAction = {type:ADD_COUNT, num: 1}; // const subAction = {type:SUB_COUNT, num: -1}; export const addAction = (num)=>{ return {type:ADD_COUNT, num: num}; }; export const subAction = (num)=>{ return {type:SUB_COUNT, num: num}; };
//reducer.js import { ADD_COUNT, SUB_COUNT } from './constants'; // 定义一个状态 let initialState = { count: 666 }; // 利用reducer将store和action串联起来 function reducer(state = initialState, action) { switch (action.type) { case ADD_COUNT: return {count: state.count + action.num}; case SUB_COUNT: return {count: state.count - action.num}; default: return state; } } export default reducer;