为了避免“props-drilling”的痛苦,开始使用 Redux 和 React-Redux
Redux
与后端 node,Express 一起使用;或者与前端:React, Vue, Angular 一起使用
action
- Actions 的格式无比自由,带有 type 属性就可以了
- 用来更新 state
- 事实上不做任何事情
- 让 action 做事情,你需要 dispatch。
{
type: "ADD"
}
dispatch 函数
- 每一次调用 dispatch 最终都会调用 reducer
- dispatch(action) -> reducer -> new state
const store = createStore(reducer);
store.dispatch({ type: "A" });
store.dispatch({ type: "B" });
store.dispatch({ type: "C" });
reducer 纯函数
- 使用 switch 语句来分类action
- 纯函数,不能有 side effect (除了 console.log())
- 不能修改 state 参数
function reducer(state = initialState, action) {
console.log('reducer', state, action);
switch(action.type) {
case 'A':
return {
count: state.count + 1
};
case 'B':
return {
count: state.count - 1
};
case 'C':
return {
count: 0
};
default:
return state;
}
}
store
- store是基于 reducer所建立的,现有reducer,再有store
import { createStore } from 'redux';
const store = createStore(reducer);
const App = () => (
<div>
<Counter/>
</div>
);
React-Redux 将数据连接到任何组件,让 Redux 和 React 之间通信
connect 函数 HOC
- call connect -> call package function(component) -> return packaging component
- connect 函数,可以将任何组件连接 Redux 的 store 并且取出需要的数据。
- 一把钥匙
- 这样我们就可以导出已连接的Counter
- connect 提供了: 1. 传递的state 和 2. dispatch 函数: this.props.dispatch
Counter.js
import { connect } from 'react-redux';
class Counter extends React.Component {
function mapStateToProps(state) { // mapStateToProps 只是使用惯例,可以随意命名
return {
count: state.count
};
}
increment = () => {
this.props.dispatch({ type: "INCREMENT" });
};
decrement = () => {
this.props.dispatch({ type: "DECREMENT" });
};
render() {
return (
<div className="counter">
<h2>Counter</h2>
<div>
<button onClick={this.decrement}>-</button>
<span className="count">{
// 把 state:
this.state.count
// 替换成:
this.props.count
}</span>
<button onClick={this.increment}>+</button>
</div>
</div>
);
}
}
}
// 然后把:
// export default Counter;
// 替换成:
export default connect(mapStateToProps)(Counter);
![e78c1de43eb1504f1649c861a68b26d0.png](https://img-blog.csdnimg.cn/img_convert/e78c1de43eb1504f1649c861a68b26d0.png)
Provider 组件
- 通过用
Provider
组件包装整个应用,如果它想的话,应用树里的每一个组件都可以访问 Redux store。 - 在
index.js
里,引入Provider
然后用它把App
的内容包装起来。store
会以 prop 形式传递 - 这样之后,
Counter
,Counter
的子元素,以及子元素的子元素等等——所有这些现在都可以访问 Redux store。 - 但不是自动的。我们需要在我们的组件使用
connect
函数来访问 store Provider
可能看起来有一点点像魔法。它在底层实际是用了 React 的 Context 特性- Context 就像是连接每个组件的秘密通道,使用
connect
就可打开秘密通道的大门。
import { Provider } from 'react-redux';
...
const App = () => (
<Provider store={store}>
<Counter/>
</Provider>
);
Redux Action 生成器
- import { functionname1, functionname2} from './actions.js'
- this.props.dispatch(function())
actions.js
两种写法:
export function increment() {
return { type: INCREMENT };
}
export const decrement = () => ({ type: DECREMENT });
Counter.js
import React from "react";
import { increment, decrement } from './actions';
class Counter extends React.Component {
state = { count: 0 };
increment = () => {
this.props.dispatch(increment()); // << 在这使用
};
decrement = () => {
this.props.dispatch(decrement());
};
render() {
...
}
}
(没有太大用)如何使用 React Redux mapDispatchToProps
- 你知道
connect
如何传递dispatch
函数吗? - 你知道你是如何厌倦一直敲
this.props.dispatch
并且它看起来多么混乱?(跟我来) - 写一个
mapDispatchToProps
对象(或者函数!但通常是对象) - 然后传给你要包装组件的
connect
函数,你将收到这些 action 生成器作为可调用 props。
import React from 'react';
import { connect } from 'react-redux';
import { increment, decrement } from './actions';
class Counter extends React.Component {
increment = () => {
// 我们可以调用 `increment` prop,
// 它会 dispatch action:
this.props.increment();
}
decrement = () => {
this.props.decrement();
}
render() {
// ...
}
}
function mapStateToProps(state) {
return {
count: state.count
};
}
// 在这个对象中, 属性名会成为 prop 的 names,
// 属性值应该是 action 生成器函数.
// 它们跟 `dispatch` 绑定起来.
const mapDispatchToProps = {
increment,
decrement
};
export default connect(mapStateToProps, mapDispatchToProps)(Counter);
文章出处:
A Complete React Redux Tutorial for Beginners (2019)daveceddia.com![618d913b96bb2ff53837ad9be788b234.png](https://img-blog.csdnimg.cn/img_convert/618d913b96bb2ff53837ad9be788b234.png)