安装
npm install --save redux@4.X
使用之前
了解 Redux 的一些核心概念:
- action
- reducer
- store
使用
引入
import { createStore } from 'redux';
// 或
const { createStore } = require('redux');
定义一些 action creators:
function increment() {
return { type: 'INCREMENT' };
}
function decrement() {
return { type: 'DECREMENT' };
}
定义一个 reducer,用来根据 action 的 type 生成新的 store:
function counter(state = 0, action) {
switch(action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default :
return state;
}
}
根据上面定义的 reducer 创建 store:
const store = createStore(counter);
模拟 action:
let currentValue = store.getState();
const listener = () => {
const previousValue = currentValue;
currentValue = store.getState();
console.log(` 之前的值:${previousValue},现在的值:${currentValue}`);
};
// 订阅监听函数,动作分发后回调
store.subscribe(listener);
// 分发动作
store.dispatch(increment());
store.dispatch(increment());
store.dispatch(decrement());
结果:
使用 react-redux 与 React 集成
安装
npm install --save react-redux@5.X react@16.X react-dom@16.X
使用之前
先定义一些 React 组件:
// Counter.js
import React from 'react';
import { connect } from 'react-redux';
import * as ActionCreators from './ActionCreators';
function Counter({value, increment, decrement}) {
return (
<p>
Click: {value} times {' '}
<button onClick={increment} >+</button>{' '}
<button onClick={decrement} >-</button>{' '}
</p>
);
}
export default connect(
state => ({ value: state}),
ActionCreators
)(Counter);
在 ActionCreators.js
文件中定义动作创建函数:
// ActionCreators.js
export function increment() {
return { type: 'INCREMENT' };
}
export function decrement() {
return { type: 'DECREMENT' };
}
使用 react-redux
// App.js
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import Counter from './Counter';
// ... 省略上面已经定义好的 reducer 和 store
ReactDOM.render(
<Provider store={store}>
<Counter />
</Provider>,
document.getElementById('root')
);
可以看到,我们使用了一个 react-redux 提供的 Provider
组件包裹了我们需要传入 state 的组件(即 Counter),并且在将 store 传入。在 Counter 中使用 react-redux 提供的 connect
将 Counter 组合成了一个高阶组件,将 state 和 action 传入了 Counter 中的 props
,这样我们就可以在 Counter 组件中使用 state 和分发 action 了,可以直接通过 action creators 发起 action,跳过了 dispatch
这个冗余的过程,因为 react-redux 中的 connect
已经帮我们做过了。
结果
用后思考
当然,这个例子非常简单,根本不需要用到 redux,因为这个例子只有一个组件。如果你有过使用 props
来层层嵌套传递父级容器组件的 state
给子级展示组件的话,你一定非常厌恶这种不那么优雅的写法,不过使用 react-redux 就不需要这么麻烦了,我们只需要使用 react-redux 提供的 connect
将组件组合成一个高阶组件导出,即可在子级展示组件内部通过 props
使用父级容器组件的 state
,而父级容器组件的 state
由 redux 中的 store
来提供。例如,我们将 App.js
改成多层嵌套的组件:
// App.js
// ...
ReactDOM.render(
<Provider store={store}>
<SomeComponent />
</Provider>,
document.getElementById('root')
);
function SomeComponent(props) {
return (
<div>
<h1>SomeComponent</h1>
<OtherComponent />
</div>
);
}
function OtherComponent(props) {
return (
<div>
<h2>OtherComponent</h2>
<Counter />
</div>
);
}
上述组件应该在各自独立的文件中定义,为了节省篇幅,因此我把它们都写在 App.js
这个文件中。
结果
可以看到,我们嵌套了两层组件,但是 Counter 组件不需要层层嵌套来获取祖先级组件的 state,我们只需要将所有的 state 提取到 Provider
组件中,然后使用 connect
将子级展示组件组合成高阶组件,即可各子级展示组件之间共享使用父级容器组件的 state,避免了丑陋的嵌套过多。
我们学到了什么❓
通过使用 redux 和 react-redux 来集中管理 state,以更加优雅的方式传递父级容器组件的 state。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。