redux的使用

为什么要使用redux.PNG

redux工作流.PNG

安装Redux

通过yarn add redux安装

创建store

createStore创建store -> 组件中,通过store.getState()获取store中的数据 -> store.dispatch(action)派发action,通知store修改state -> store.subscribe()订阅数据的变化

在src文件夹下,创建store/index.js

1
2
3
4
5
6
7
8
import { createStore } from 'redux';
import reducer from './reducer.js'
const store = createStore(reducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
export default store;

创建reducer

reducer里,不能处理异步的修改

src/store/reducer.js

1
2
3
4
5
6
7
8
9
10
11
const defaultState = {
inputValue:'',
lists:[]
};
export default (state = defaultState, action) => {
switch(action.type){
default:
return state;
}
}

在组件中获取store中的数据

通过store.getState()可以获取store中存储的数据this.state = store.getState()

1
2
3
4
5
6
7
8
9
10
11
//组件中
import store from './store/index.js'
class Hello extends React.Component {
constructor(props){
console.log(store.getState())
this.state = store.getState();
}
}

订阅(监听)store中数据的变化

1
2
3
4
5
6
7
8
9
10
//组件中
constructor{
this.handleStoreChange = this.handleStoreChange.bind(this);
store.subscribe(this.handleStoreChange);
}
handleStoreChange(){
//订阅store里的数据变化
this.setState(store.getState())
}

将新数据发送给store

创建一个action,该action是个对象,包含type和要传递的值;然后store.dispatch(action)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//组件中
handleChange(ev){
const action = {
type: 'change_input_value',
inputValue: ev.target.value
}
store.dispatch(action);
}
btnClick(){
const action = {
type: 'add_todo_item',
}
store.dispatch(action);
}
deleteItem(index){
const action = {
type: 'delete_todo_item',
index
}
store.dispatch(action);
}
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
//reducer.js
const defaultState = {
inputValue:'',
lists:[1,2,3]
};
//reducer只能接收state,但禁止直接修改state,因此需要JSON.parse(JSON.stringify(state))或者Object.assign()进行拷贝,然后修改拷贝的内容,最后将拷贝的内容return出去
//reducer不能处理异步的修改
export default (state = defaultState, action) => {
switch(action.type){
case 'change_input_value':
return Object.assign({},state,{
inputValue: action.inputValue
})
case 'add_todo_item':
const newState = JSON.parse(JSON.stringify(state));
newState.lists.push(newState.inputValue);
newState.inputValue = '';
return newState;
case 'delete_todo_item':
const newState = JSON.parse(JSON.stringify(state));
newState.lists.splice(action.index,1);
return newState;
default:
return state;
}
}

查看在线demo

管理action

将分散在各个组件中的action放到actionCreators.js中

在store文件夹下,创建actionCreators.js

1
2
3
4
5
6
7
8
9
10
11
12
13
export const changeInputValueAction = (inPutValue) => ({
type: 'change_input_value',
inputValue
})
export const addTodoItemAction = () => ({
type: 'add_todo_item'
})
export const deleteTodoItemAction = (index) => ({
type: 'delete_todo_item',
index
})

在组件中使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//组件中
import { changeInputValueAction, addTodoItemAction, deleteTodoItemAction } from './store/actionCreators.js';
handleChange(ev){
const action = changeInputValueAction(ev.target.value)
store.dispatch(action);
}
btnClick(){
const action = addTodoItemAction()
store.dispatch(action);
}
deleteItem(index){
const action = deleteTodoItemAction(index)
store.dispatch(action);
}

ajax请求

1
2
3
4
5
6
7
8
9
10
11
12
//组件中
componentDidMount(){
axios.get('/api').then(res=>{
const data = res.data;
const action = {
type: 'set_lists',
data
}
store.dispatch(action); //派发给reducer.js
})
}

然后在reducer.js里进行处理,并return newState

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//reducer.js
const defaultState = {
lists:[]
};
export default (state = defaultState, action) => {
switch(action.type){
case 'set_lists':
const newState = JSON.parse(JSON.stringify(state));
newState.lists = action.data;
return newState;
default:
return state;
}
}

你可以使用redux-thunk,或者redux-saga,对异步请求进行管理

使用redux-thunk

如果在组件的componentDidMount中,有许多异步请求,会让该组件的代码杂乱,此时,建议使用redux-thunk,将异步请求拆分到actionCreators.js

github: redux-thunk
通过yarn add redux-thunk进行安装

在store/index.js里进行配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// store/index.js
import { createStore, applyMiddleware, compose } from 'redux';
import reducer from './reducer.js'
import thunk from 'redux-thunk';
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;
const enhancer = composeEnhancers(
applyMiddleware(thunk),
);
const store = createStore(reducer, enhancer);
export default store;

在store/actionCreators.js里进行设置:

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
//store/actionCreators.js
import axios from 'axios';
//return一个对象
export const deleteTodoItemAction = (index) => ({
type: 'delete_todo_item',
index
})
//使用redux-thunk之后,可以return一个函数,在该函数中进行异步请求
export const getTodoList = () => {
return (dispatch) => {
axios.get('/api').then(res=>{
const data = res.data;
const action = {
type: 'set_lists',
data
}
dispatch(action); //派发给reducer.js
})
}
}
```
在组件中派发异步请求:
```javascript
//组件中
import { getTodoList } from '../store/actionCreators.js';
componentDidMount(){
const action = getTodoList(); //getTodoList()返回一个函数
store.dispatch(action);
}

查看在线demo

使用redux-saga

redux-thunk将异步请求放在actionCreators.js里,而redux-saga放在新建的sagas.js内

redux-saga中文文档
通过yarn add redux-saga进行安装

在store/index.js里进行配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// store/index.js
import { createStore, applyMiddleware, compose } from 'redux';
import reducer from './reducer.js';
import createSagaMiddleware from 'redux-saga';
import mySaga from './sagas.js'
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;
const sagaMiddleware = createSagaMiddleware();
const enhancer = composeEnhancers(
applyMiddleware(sagaMiddleware),
);
const store = createStore(reducer, enhancer);
sagaMiddleware.run(mySaga)
export default store;

配置store/sagas.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { takeEvery , put} from 'redux-saga/effects';
import axios from 'axios';
function* setLists(action) {
try{
const res = yield axios.get('/api');
const data = res.data.lists;
const action = {
type: 'set_lists',
data
};
yield put(action);
} catch(err){
console.log(err);
}
}
function* mySaga() {
yield takeEvery('set_lists', setLists); //当派发set_lists这个action时,将其捕获
}
export default mySaga;

组件中派发action

1
2
3
4
5
6
7
8
//组件中
componentDidMount(){
const action = {
type: 'set_lists'
};
store.dispatch(action);
}

查看在线demo

使用react-redux

通过yarn add react-redux安装

-------------本文结束感谢您的阅读-------------