一、概念
一个可预测的 JavaScript 应用状态管理容器(容器即为Store)。
- View:视图层,即React;
- Store:保持状态,分发状态给 View,使得 View 根据这些状态渲染不同的内容。
- Reducers:响应不同的动作,负责更新 Store 中状态的 JavaScript 函数。
二、项目引用
// 安装依赖
npm install redux
npm install react-redux
三、Store: 数据的唯一真相来源
1、React 状态 “危机”
在 React 中,状态存在每个组件的 this.state 中,每个组件的 state 为组件所私有,如果要在一个组件中操作另外一个组件,实现起来是相当繁琐的。
如上图,不仅要把 handleClick 方法通过很深的层级传给组件 B,当组件 B 调用 handleClick 方法时,修改组件 A 的 state,再反过来传递给组件 C 时,组件 A 到组件 C 之间的所有组件都会触发重新渲染,这带来了巨额的渲染开销。
2、解救者:Store
思路:抽离所有组件的状态,类比 React 组件树,用js对象来构造一个中心化的状态树,相当于对 React 组件树进行了状态化建模。
如下图,组件 B 中发起一个更新状态 C 的动作,此动作对应的更新函数更新 Store 状态树,之后将更新后的状态 C 传递给组件 C,触发组件 C 的重新渲染。
四、理解 Action: 改变 State 的唯一手段
更新 Store 状态唯一方式:调用 dispatch 函数,传递一个 action(简单的 JavaScript 对象) 给这个函数 。
dispatch({ type: 'ADD_TODO', text: '我是一只小小小图雀' , id: 0})
为了简化Action的写法,可定义函数并传入需要变化的参数即可,这个函数被称为Action Creators(动作创建器):
// Action Creators
let nextTodoId = 0;
const addTodo = text => ({
type: "ADD_TODO",
id: nextTodoId++,
text
});
// dispatch
dispatch(addTodo('我是一只小小小图雀'))
五、理解 Reducers: 响应 Action 的指令
Reducers:响应从组件中 dispatch 出来 Action,并更新 Store 中的状态;
1、纯化的 Reducers
reducer 是一个普通的 JavaScript 函数,它接收两个参数:state 和 action
- state: Store 中存储的那棵 JavaScript 对象状态树
- action:组件中 dispatch 的 Action
reducer 根据 action 的指示,对 state 进行对应的操作,然后返回操作后的 state,Redux Store 会自动保存这份新的 state。
reducer(state, action) {
// 对 state 进行操作
return newState;
}
2、纯化
- 定义:不直接修改原对象,而是返回一个新对象的修改;
- 例子: 对 state = { a: 1, b: 2 } 进行修改,将 a 替换成 3,应该是:newState = { ...state, a: 3 },而不是 state.a = 3。
六、Redux 上的函数
- dispatch(action): 用来在 React 组件中发出修改 Store 中保存状态的指令。
- reducer(state, action): 用来根据这一指令修改 Store 中保存状态对应的部分。
- connect(mapStateToProps) :用来将更新好的数据传给组件,然后触发 React 重新渲染,显示最新的状态。它架设起 Redux 和 React 之间的数据通信桥梁。
七、Redux 的项目实践
- 1、在入口文件中,创建store并利用Provider将store下发给组件
// index.js
import { createStore } from "redux";// 从 redux 中导出了 createStore
import { Provider } from "react-redux";// 从 react-redux 导出了 Provider
// 创建初始状态数据
const initialState = {}
// reducer
const rootReducer = (state, action) => {}
// 生成store
const store = createStore(rootReducer, initialState);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
- 2、在主组件中
// App.js
import { connect } from "react-redux";
class App extends React.Component {
render() {
const {} = this.props// 通过props获取store
return {
dispatch(ACTION);// 发出修改
}
}
// mapStateToProps同时操作组件的原 props 和 Store 的状态,然后合并成最终的组件 props
const mapStateToProps = (state, props) => ({
todos: state.todos,
filter: state.filter
});
// 获取 mapStateProps 返回的最终组合后的状态,然后将其注入到 App 组件中,返回一个新的组件
export default connect(mapStateToProps)(App);
- 3、在子组件中,无需合并props
// AddTodo.js
import { connect } from "react-redux";
const AddTodo = ({ dispatch }) => {
return (
<div dispatch(ACTION)>点击触发</div>
);
};
// 获取 mapStateProps 返回的最终组合后的状态,然后将其注入到 App 组件中,返回一个新的组件
export default connect()(AddTodo);