塔顶上的 Redux --核心概念
Redux
是天生用来管理应用 state 的,它有一个 store 容器来储存应用中的 state,任何组件都可以从 store 中读取 state
Redux store
1.创建 store
新建一个文件 src/store.js 文件,先添加一行代码:
import { createStore, compose } from 'redux';
redux 中分别导入 createStore 模块 和 compose 模块。
其中 createStore 这个接口就是用来创建 Redux store 容器的,
import { syncHistoryWithStore} from 'react-router-redux';
import { browserHistory } from 'react-router';
react-router-redux 包并不是 Redux 项目必须的,用它则可以在 redux-devtools-extension 中 显示页面浏览历史,不用它 Redux 和 React Router 也可以在一起完美工作。
2.构建状态树
import comments from './data/comments';
import courses from './data/courses';
const defaultState = {
courses: courses,
comments: comments
};
const store = createStore(rootReducer, defaultState);
导入在静态文件中存储的课程信息和课程的评论信息,然后用它们来定义一个对象常量 defaultState, 接下来使用 createStore 接口创建一个 store,createStore 接口的第一个参数是 rootReducer, 也就是构建的状态树,第二个参数就是状态树的初始值。
所谓的状态树就是一个普通的 JS 对象,本项目要构建的状态树其实是这样的:
{
courses: courses,
comments: comments
}
自定义了两个状态变量 courses 和 comments,其初始值分别是从文件 ./data/courses 和 ./data/courses 中导入的数据。
这样,我们就把课程信息和评论信息存储到 store 容器中了
接下来,就是调用 syncHistoryWithStore 把路由状态(routing state)信息存储到新创建的 store 容器内。
3. 存储到新创建的 store 容器内
export const history = syncHistoryWithStore(browserHistory, store);
最后再添加一行代码,把我们刚才创建的 store 容器导出去,供外部组件使用。
export default store;
Redux 的三原则之一:单一数据源保证在一个 Redux 应用中只有唯一的一个 store 用于储存应用中唯一的一个状态树。
Redux actions
创建了一个 Redux store 容器,也知道了 store 容器用来储存应用中的 state,那怎么来更新这些 state,就需要先了解一些关于 Redux actions 的事情。
什么是 Actions
Actions 描述了应用中所发生的事情,actions 可不是唯一的,因为应用中会发生很多事情,比如说本案例中会发生的事件就有点赞课程、添加评论等等。那怎么用代码来代表所发生的事情呢?
一个 action 就是一个平常的 JavaScript 对象,定义如下:
{
type: 'INCREMENT',
number: 1
}
一个 action 对象必须要有一个 type 属性,用来表明所发生事情的类型,type 属性值一般是大写的字符串常量。除 type 属性之外,还可以带有其它的属性,如代码中的 index,代表事情发生时产生的数据信息。
什么是 Action Creators
Action creators 就是用来创建 actions 的函数,函数返回值是 action 对象类型。一个 action creator 的定义是类似这样的:
function increment(number) {
return {
type: 'INCREMENT',
number
}
}
1.新建一个文件 actions/index.js,添加如下代码:
// action types
export const INCREMENT_LIKES = 'INCREMENT_LIKES';
export const ADD_COMMENT = 'ADD_COMMENT';
export const REMOVE_COMMENT = 'REMOVE_COMMENT';
首先定义本案例所需要的三个 action 类型,当项目中有很多 action 类型的时候,可以单独创建一个文件来存储所有的 action 类型。
2.定义点赞课程的 action creator
export function increment(index) {
return { type: INCREMENT_LIKES, index }
}
其中,index 代表被点赞课程在课程数组中的索引号
3.定义添加评论的 action creator
export function addComment(courseId, author, comment) {
return { type: ADD_COMMENT, courseId, author, comment }
}
其中,courseId 是被评论的课程 id 号,author 是评论者的名字,comment 是评论的内容
4.定义删除评论的 action creator:
export function removeComment(courseId, i) {
return { type: REMOVE_COMMENT, i, courseId }
}
其中,courseId 是被删除评论隶属课程的 id 号,i 是指被删除评论在隶属课程的评论数组中的索引号
Redux Reducers
一个 reducer 就是一个 JS 纯函数,这个函数有两个参数,一个是上一个 state 值,另一个就是上节视频介绍的 Redux action,它的返回值 state。一般一个 state 变量对应着一个 reducer 文件,本案例有 courses 和 comments 两个 state
1.编写courses reducer
新建一个文件 reducers/courses.js,添加代码:
function courses(state = [], action) {
console.log(state, action);
return state;
}
export default courses;
上面代码就定义了一个 courses reducer,不过这个 reducer 并没有对上一个 state 做任何处理,只是打印 state 和 action 的值,并返回 state 值
2.编写 comments reducer
接下来新建一个文件 reducers/comments.js,添加代码:
function comments(state = [], action) {
console.log(state, action);
return state;
}
export default comments;
3.合并 courses 和 comments 两个 reducers
新建一个文件 reducers/index.js,添加代码:
import { combineReducers } from 'redux';
import { routerReducer } from 'react-router-redux';
import courses from './courses';
import comments from './comments';
const rootReducer = combineReducers({courses, comments, routing: routerReducer });
export default rootReducer;
因为在 Redux 项目中只有唯一的一个状态树(state tree),所以通过 combineReducers 把刚才定义的 courses reducer 和 comments reducer 合并起来,生成一个 rootReducer 提供给创建 Redux store 的接口 createStore 使用。
routerReducer 作用是把路由状态添加到状态树中(用于开发调试,可以不添加),其对应的 state 变量名是 routing,最终本案例的状态树是这样的:
{
courses: courses,
comments: comments,
routing: routerReducer
}
这个 JS 对象的每一个 key 对应着存储在 store 中的一个状态变量的名字,每一个 value 则对应着一个 reducer,决定着状态变量值。