redux简介
react组件间的通信往往只能是子组件和父组件之间的通信,如果一个子组件要与和父组件同级的其他组件的子组件通信。通俗意义上说是子组件与自己的堂兄弟通信,那么就要通过父组件通信等,较麻烦,而redux的出现就是为了解决这个,将数据全部放在redux中,react只负责渲染,这样,组件只需要改变redux中的数据,其余组件便能够得到响应。如下图所示
以前facebook也出过一个数据层框架名为flux,实际上redux = reducer + flux 来进行辅助编程和扩展
redux工作流程
redux的整体工作流程如下
我们可以进行这样的想象,把整个流程看做一个借书的管理过程
react component是借书的用户,当他要借书的时候,通过action creatures来说一句话,来创建动作,随后store便是一个图书馆,他接收到action说以后,自己不能执行,便通过reducer,reducer相当于一个图书管理员,通过他进行图书的登记借阅和归还等操作。
redux的实现
通过npm install redux –save-dev来加载redux库,随后创建store文件夹,在下面创建index.js函数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23import { createStore,applyMiddleware,compose } from 'redux';
//applyMiddleware表示可以使用中间件
import thunk from 'redux-thunk';
//引入reducer
import reducer from './reducer';
//创建公共存储仓库 使用redux-dev-tools
const composeEnhancers =
typeof window === 'object' &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
// Specify extension’s options like name, actionsBlacklist, actionsCreators, serialize...
}) : compose;
//使用thunk中间件
const enhancer = composeEnhancers(
applyMiddleware(thunk),
// other store enhancers if any
);
const store = createStore(reducer,
enhancer
);
export default store;
这里我们使用了redux的调试工具和redux-thunk的中间件,实际上thunk这个中间件工作在action和store之间。
随后再component组件文件中导入
通过reducer.js文件引入默认的state1
2
3
4
5
6
7//state指的是我整个图书馆书籍信息,仓库数据
import {CHANGE_INPUT_VALUE,ADD_TODO_ITEM,DELETE_TODO_ITEM,INIT_LIST_DATA} from './actionTypes';
const defaultState = {
inputValue:'',
list:[]
};
1 | import store from './store/index'; |
比如input输入框中,当input内容发生改变,自动更新state,就需要创建action,这里已经进行了封装
actionCreators.js函数是用来创建动作的
actionTypes.js函数是用来定义每个动作的类型的,如下
1 | //actionTypes.js文件 |
1 | //actionCreators.js文件 |
1 | const action = getAddItemAction(); |
随后通过store的dispatch方法来通知store
随后在reducer文件中便可以进行修改。通过传递过来的先前的state和最新的action,要注意不能修改state,只能通过拷贝state产生的拷贝对象后,通过修改拷贝对象的值,再返回拷贝对象,便可以反馈给store,store自动进行修改。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40//reducer必须返回函数 负责数据的存储 reducer必须是纯函数 纯函数指的是
//给定固定的输入 就一定会有固定的输出 而且不会有任何的副作用 例如new Date等就根据时间来了 不能改变state
export default (state = defaultState,action) => {
//将上一次的state和action都传递过来
if(action.type === CHANGE_INPUT_VALUE){
//reducer的原则 可以接受state 但是不能改变state
//将之前的state进行深拷贝 然后将newState改变
const newState = JSON.parse(JSON.stringify(state));
newState.inputValue = action.value;
return newState; //替换数据
}
if(action.type === ADD_TODO_ITEM){
//reducer的原则 可以接受state 但是不能改变state
//将之前的state进行深拷贝 然后将newState改变 将inputValue拿来
const newState = JSON.parse(JSON.stringify(state));
newState.list.push(newState.inputValue);
newState.inputValue = '';
return newState; //替换数据
}
if(action.type === DELETE_TODO_ITEM){
//reducer的原则 可以接受state 但是不能改变state
//将之前的state进行深拷贝 然后将newState改变 将inputValue拿来
const newState = JSON.parse(JSON.stringify(state));
newState.list.splice(action.index,1);
return newState; //替换数据
}
if(action.type === INIT_LIST_DATA){
//reducer的原则 可以接受state 但是不能改变state
//将之前的state进行深拷贝 然后将newState改变 将inputValue拿来
const newState = JSON.parse(JSON.stringify(state));
newState.list = action.data;
return newState; //替换数据
}
return state;
}
这样store便可以自动进行更新和修改。
在component中,通过store.getState()方法可以获取store内的值,赋值给每个component的自身state1
this.state = store.getState();
通过store.subscribe订阅store,在函数体中实现方法,当store更新后,自动更新state的值1
store.subscribe(this.handleStoreChange);
handlStoreChange的实现1
2
3console.log("store change");
//进行替换state
this.setState(store.getState());
通过setState的方法来更新state。
整体的流程大致如上。