redux 专注于状态管理,和 react 解耦,redux 也可以结合 Angular 一起使用。本文结合实例讲解 Redux 的使用,可以更好的理解 Redux。
当你已经了解一些 redux 的基础概念后,现在开始尝试使用 redux 吧,redux 专注于状态管理,和 react 解耦,redux 也可以结合 Angular 一起使用。本文尝试在 react 应用中使用 redux 来开发应用,而并没有使用 react-redux,这有助于理解 redux 的数据流。
本文完整代码请查看 Github:https://github.com/YanYuanFE/redux-app
// clone repo
git clone https://github.com/YanYuanFE/redux-app.git
cd redux-app
// checkout branch
git checkout part-1
// install
npm install
// start
npm start
开始#
首先,初始化一个 react 应用,使用 creat-react-app 来进行创建,使用之前需要先安装,打开命令行,输入:
npm i create-react-app -g
进行全局安装。然后进入准备开发的目录,打开命令行,进入当前文件夹,输入:
create-react-app redux-app
,等待创建完成。然后
cd redux-app
,运行 npm start,react 应用会自动运行并打开浏览器。
下一步,需要安装 redux,命令行输入
npm i redux --save
,下面,开始编写 redux 部分。
redux#
由于应用比较简单,可以直接编写 reducer 部分,在 src 目录下新建 reducers 文件夹,新建 index.js,在 reducer 中,主要处理 action 来返回新的 state,在本应用中,计数器触发的 action 主要有加和减两种,分别将其定义为
'INCREMENT' 和 'DECREMENT',当触发计数器加 1 的时候,将 state+1, 触发计数器减 1 的时候,将 state-1, 否则,将返回原来的 satte。并且需要将整个 reducer export default 以供其他部分使用。代码如下:
export default (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}
reducer 编写完毕后,下一步需要生成 store 注入整个应用。此处,需要修改 src 目录下的 index.js,通过 import 导入 redux,需要使用 redux 提供的 APIcreateStore 将 reducer 生成整个应用的状态 store,并且将 store 通过 props 传入整个应用的根组件 App。同时,需要将原本的渲染逻辑封装成一个 render 方法并手动调用。同时,当 store 改变后,应用并不会自动重新渲染,需要使用 store 的方法 subscribe 来手动订阅,store.subscribe (render); 意思是让 store 订阅 render 方法,当 store 改变时,就调用 render 重新渲染整个应用。
ReactDOM.render(<App store={store}/>, document.getElementById('root'))
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { createStore } from 'redux';
import registerServiceWorker from './registerServiceWorker';
import counter from './reducers';
const store = createStore(counter);
const render = () => ReactDOM.render(<App store={store}/>, document.getElementById('root'));
render();
store.subscribe(render);
registerServiceWorker();
组件编写#
store 通过 props 传递到 APP 组件后,在 APP 组件内需要通过 store 来获取数据以及触发 action。在 APP 组件中,为了使组件逻辑分离,计数器相关的实现将会单独抽离成组件,APP 组件负责将数据和事件通过 props 传递到计数器组件中。
在 src 目录下新建 components 目录,在 components 目录下新建 Counter.js,下面是计数器的代码:
import React, { Component } from 'react';
class Counter extends Component {
constructor(props) {
super(props);
this.incrementAsync = this.incrementAsync.bind(this);
this.incrementIfOdd = this.incrementIfOdd.bind(this);
}
render() {
const { value, onIncrement, onDecrement } = this.props;
return (
<p>
Clicked: {value} times
{' '}
<button onClick={onIncrement}>
+
</button>
{' '}
<button onClick={onDecrement}>
-
</button>
</p>
)
}
}
export default Counter;
在 Counter 组件中,通过 props 接收父组件传递的 value 和加、减数值的方法,value 绑定到视图显示计数器的数值,加、减按钮分别用来控制计数器的加减操作,分别将父组件传递的方法进行绑定到按钮上。
然后在 src 目录下的 App.js 中引入计数器的组件,并在 render 中使用。
import React, { Component } from 'react';
import Counter from './components/Counter';
import logo from './logo.svg';
import './App.css';
class App extends Component {
render() {
const { store } = this.props;
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<p className="App-intro">
To get started, edit <code>src/App.js</code> and save to reload.
</p>
<Counter
value={store.getState()}
onIncrement={() => store.dispatch({ type: 'INCREMENT' })}
onDecrement={() => store.dispatch({ type: 'DECREMENT' })}
/>
</div>
);
}
}
export default App;
在 APP 组件中,使用 ES6 的对象解构语法在 props 中获取 store,在 render 中渲染计数器组件 Counter,同时,向 Couter 组件传入约定的 props,计数器数值 value 通过 store.getState () 来获取,增加数值方法 onIncrement 传入一个方法,调用 store.dispatch 来发起一个 Action,action 中传入代表增加数值的 type ‘Increment’,同理,减少数值的方法 onDecrement 中传入的 actionType 为‘DECREMENT’。
到这里,整个计数器应用就完全开发完成了。
npm start
启动应用,打开浏览器,最终效果如下:
点击 +、- 按钮可以控制数字的加减,而且数字是实时更新的。
写在最后#
通过 redux 实现的计数器应用已经开发完成了,你可以尝试梳理一下 redux 的流程,首先,redux 的核心包括 store、action、reducer,store 暴露到全局应用中,通过 store 可以获取 state,触发 action,订阅 state 改变后的事件。要想改变 state 的数据,必须触发 Action,action 可以通过一些交互和事件来触发,reducer 用来处理 action,并返回一个新的 state,当 state 改变后,store 的 subscribe 方法就会触发,可以用来更新视图。如果你使用 react 来开发应用,当你的应用变得复杂,仅仅使用 redux 会变得很繁琐,你可能需要将 store 通过 props 来一层层传递到你需要的组件中,为了解决这样的问题,react-redux 出现了,可以使用简单的方式获取到全局的状态,那么,拭目以待吧。