首先简单说一下 Redux 在 React 项目中的用法。Redux
和 React
之间并没有什么关系,脱离了 React
,Redux
也可以与其它的 js 库(甚至是原生 js)搭配使用,Redux
只是一个状态管理库,但它与 React
搭配使用时却很好用,使开发 React 应用更加简介。
这里实现一个简单的计数器功能,当鼠标点击按钮时数字就会加一。使用 React-Hooks
写一个 App 组件用来实现该功能:
import React,{
useState } from "react";
function App(){
let [count,setCount] = useState(0);
function handleClick(){
setCount(count + 1);
}
return (
<div>
<div>
<h1>{
count}</h1>
<button onClick={
handleClick}>Click</button>
</div>
</div>
);
}
export default App;
然后渲染到页面的方法,写在 index.js
中:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<App />,
document.getElementById('root')
);
这样一个计数器组件就写好了。但是还没有使用 Redux。如果使用 Redux 就要把 React 中的状态(state)交给 Redux 管理。
创建 store
单纯的只使用 Redux 库时,需要先做“配置”,因为这些代码的书写是必不可少的。
这里直接说一下代码分离,代码分离后更好管理,有利于日后代码的改动。
下面是 Redux 的工作流:
首先,react 组件从 store 中获取原始的数据,然后渲染。当 react 中的数据发生改变时,react 就需要使用 action,让 action 携带新的数据值派发给 store,store 把数据发给 reducer 函数,reducer 函数处理新的数据然后返回给 store,最后 react 组件拿到更新后的数据渲染页面,达到页面更新的目的。
store 就是储存数据的地方。在 redux 中使用 createStore
存储数据。
这里新建一个 store 目录,里面是一个 index.js 文件,为了生成并导出一个 store:
import {
createStore } from "redux";
import AppReducer from "../reducer/App.reducer.js";
// 该函数须传入一个 reducer 函数
// 要不然怎么与 reducer 进行通信
// 然后返回
const store = createStore(
AppReducer
);
export default store;
在写组件时(当然,除了 UI 组件),我们都应该创建一个自己的 reducer 函数,这样方便管理。假如有两个组件:App 和 Home,那就最好创建两个 reducer 函数:appReducer 和 homeReducer。redux 中提供了一个 combineReducers
函数,这个函数可以将小的 reducer 合并成大的 reducer,并将合并后的 reducer 返回出去。于是可以进行改进上面的代码:
import {
createStore, combineReducers, applyMiddleware } from "redux";
// App 组件的 reducer
import appReducer from "../reducer/app.reducer.js";
// Home 组件的 reducer
import homeReducer from "../reducer/home.reducer.js";
// 合并 reducer
const rootReducer = combineReducers({
appReducer,
homeReducer
});
// 给合并后的 reducer 创建 store
const store = createStore(
rootReducer,
);
export default store;
reducer 函数
reducer 函数的默认格式是这样的:
// 首先定义一个默认的 state 对象,里面的属性和值是你这个页面的状态(props/state)默认现实的内容
// 在这个实例中,count 的默认值假如是 0
const DEFAULT_STATE = {
count: 0
}
// 下面是 reducer 函数:
function reducer(state,action){
switch(action.type){
// 默认情况下,就返回原始的 state
// 页面初始渲染的结果
default: return state;
}
}
一个 reducer 就编写好了,可以发现 reducer 函数中的第二个参数叫 action,通过上面的流程图应该就明白了,action 就是最左边的 action,它是组件与 store 通信的东西,action 通常是个对象,这个对象一般由两部分组成,一部分是数据,而另一部分就是 type
属性,这个属性用来标志 state 中更新哪些数据。type 的值其实就是唯一标识的字符串。比如下面的 对象就符合一个 action 的书写规范:
var action = {
type: "SET_COUNT",
count: 1
}
一般不把 action 直接写成一个对象,新建一个 action 目录,里面专门存放各个组件的 action,而且把 action 写成函数形式:
export function setCount(count){
// 调用这个函数就会返回一个对象
return {
type: "SET_COUNT",
count: count
}
}
action 导出后,在组件中接收 action 函数,然后使用 action 函数。还有一点不足是,action.type
的书写不太好,这样写不好管理,因为 reducer 中也要用到 action.type
,我们可以把字符串抽离出来专门由一个文件去维护。比如建立一个 types 目录,目录下存放每个组件会用到的 type 字符串。使用时引入即可。
export const SET_COUNT = "app/set_count";
那么 reducer 的函数就可以写成这样:
import {
SET_COUNT } from "../types/appTypes";
const DEFAULT_STATE = {
count: 0
}
// 下面是 reducer 函数:
function reducer(state,action){
switch(action.type){
// 如果 type 是 SET_COUNT 时,
// count 值就变成 action 对象中的 count 值
case SET_COUNT:
return {
count: action.count
}
// 默认情况下,就返回原始的 state
// 页面初始渲染的结果
default: return state;
}
}
写到这里,就只剩下 react 与 action 的通信ÿ