React-Redux是一个React生态中常用组件,它可以简化Redux流程。(需要注意的是概念:React、Redux、React-redux是三个不同的东西)
1、安装react-redux依赖
npm install --save react-redux
2、<Provider>提供器
<Provider>是一个提供器,只要使用了这个组件,组件里边的其它所有组件都可以使用store
了,这也是React-redux的核心组件了
import React from 'react';
import ReactDOM from 'react-dom';
import TodoList from './TodoList'
import { Provider } from 'react-redux'
import store from './store'
//声明一个App组件,然后这个组件用Provider进行包裹。
const App = (
<Provider store={store}>
<TodoList />
</Provider>
)
ReactDOM.render(App, document.getElementById('root'));
3、connect连接器
react-redux提供了connect 方法来连接mapStateToProps 、mapDispatchToProps 和组件
1)TodoList.js组件引入connect
import { connect } from 'react-redux';
2)映射关系制作
映射关系就是把原来的state映射成组件中的props
属性
mapStateToProps
const mapStateToProps = (state) => {
return {
inputValue : state.inputValue,
list: state.list,
}
}
mapDispatchToProps
const mapDispatchToProps = (dispatch) => {
return {
getTodoList() {
const action = getTodoListAction();
dispatch(action);
},
inputChange(e) {
const action = changeInputAction(e.target.value);
dispatch(action);
},
clickButton() {
const action = addItemAction();
dispatch(action);
},
deleteItem(index) {
const action = deleteItemAction(index);
dispatch(action);
}
}
}
由于react-redux不支持异步操作,想支持则需要引入中间件 redux-thunk
TodoList案例中有用到组件加载完成时,获取List操作(实际项目中List中的DataSource是从后端获取的默认结果,这里为了方便,模拟了一个假数据)
前端Mock假数据
在public文件夹下新建getList文件夹,getList文件夹下新建mock.json文件
mock.json文件
{
"list":[
"早上4点起床,锻炼身体",
"中午下班游泳一小时",
"晚上8点到10点,学习两小时"
]
}
store文件夹
一般情况下的store文件夹里分为reducer.js index.js constants.js(或者是actionTypes.js) 以及actionCreators.js
首先组件要获取数据,会先创建一个action,这个action是一个对象,包含action的类型(就是actionType)和值 然后store去派发这个action,store接受到action之后会交给reducer.js来处理,这里存放了默认数据和处理之后的数据,reducer处理好数据之后,返回一个新的state给store; 然后组件需要获取这个新的state,一般情况是通过setState来获取函数store; 设置当前组件的state; ;this.setState(store.getState())
index.js
这个引入了redux-thunk中间件
import {createStore, applyMiddleware, compose} from 'redux';
import reducer from './reducer'; //引入ruducer
import thunk from 'redux-thunk';
// 利用compose创建一个compose增强函数,相当于建立了一个链式函数
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;
// 增强函数和thunk结合起来
const enhancer = composeEnhancers(applyMiddleware(thunk))
// 创建数据存储仓库
const store = createStore(reducer, enhancer)
export default store;
actionTypes.js
这里面存放了TodoList案例的所有action
export const CHANGE_INPUT = 'changeInput';
export const ADD_ITEM = 'ADD_ITEM';
export const DELETE_ITEM = 'DELETE_ITEM';
export const GET_LIST = 'GET_LIST';
actionCreators.js
这里面对应所有处理action的方法
import { CHANGE_INPUT, ADD_ITEM, DELETE_ITEM, GET_LIST } from "./actionTypes";
import axios from 'axios';
export const changeInputAction = (value) => ({
type: CHANGE_INPUT,
payload: value
})
export const addItemAction = () => ({
type: ADD_ITEM,
})
export const deleteItemAction = (index) => ({
type: DELETE_ITEM,
payload: index
})
export const getListAction = (data) => ({
type: GET_LIST,
payload: data
})
export const getTodoListAction = () =>{
return (dispatch) => {
axios.get('/getList/mock.json')
.then((res) => {
const data = res.data;
const action = getListAction(data);
dispatch(action);
})
}
}
reducer.js
这里对应action的一个业务处理逻辑
import { CHANGE_INPUT, ADD_ITEM, DELETE_ITEM, GET_LIST } from './actionTypes'
const defalutState = {
inputValue : 'Write Something',
list :[]
}
export default (state = defalutState, action) =>{
if (action.type === CHANGE_INPUT) {
let newState = JSON.parse(JSON.stringify(state));
newState.inputValue = action.payload;
return newState;
}
if (action.type === ADD_ITEM) {
let newState = JSON.parse(JSON.stringify(state));
newState.list.push(newState.inputValue);
newState.inputValue = '';
return newState;
}
if (action.type === DELETE_ITEM) {
let newState = JSON.parse(JSON.stringify(state));
newState.list.splice(action.payload, 1);
return newState;
}
if(action.type === GET_LIST){ //根据type值,编写业务逻辑
let newState = JSON.parse(JSON.stringify(state))
newState.list = action.payload.list //复制性的List数组进去
return newState
}
return state
}
class类组件结合componentDidMount生命周期实现TodoList案例
TodoList.js
// eslint-disable-next-line
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Input, Button, List } from 'antd';
import { getTodoListAction, changeInputAction, addItemAction, deleteItemAction } from './store/actionCreators';
import 'antd/dist/antd.css';
// class类组件写法
class TodoList extends Component {
componentDidMount() {
this.props.getTodoList()
}
render() {
const { inputValue, inputChange, clickButton, list, deleteItem } = this.props;
return (
<div style={{margin: "10px"}}>
<div>
<Input value={inputValue} onChange={inputChange} style={{ width:'250px', marginRight:'10px'}}/>
<Button type="primary" onClick={clickButton}>增加</Button>
</div>
<div style={{margin:'10px',width:'300px'}}>
<List
bordered
dataSource={list}
renderItem={(item, index)=>(<List.Item key={index} onClick={() => deleteItem(index)}>{item}</List.Item>)}
/>
</div>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
inputValue : state.inputValue,
list: state.list,
}
}
const mapDispatchToProps = (dispatch) => {
return {
getTodoList() {
const action = getTodoListAction();
dispatch(action);
},
inputChange(e) {
const action = changeInputAction(e.target.value);
dispatch(action);
},
clickButton() {
const action = addItemAction();
dispatch(action);
},
deleteItem(index) {
const action = deleteItemAction(index);
dispatch(action);
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(TodoList);
无状态组件结合hooks实现TodoList案例
import React, { useEffect } from 'react';
import { connect } from 'react-redux';
import { Input, Button, List } from 'antd';
import { getTodoListAction, changeInputAction, addItemAction, deleteItemAction } from './store/actionCreators';
import 'antd/dist/antd.css';
// 无状态组件写法
const TodoList = (props) => {
const { inputValue, inputChange, clickButton, list, deleteItem, getTodoList } = props;
useEffect(() => {
getTodoList()
},[])// eslint-disable-line react-hooks/exhaustive-deps
return (
<div style={{margin: "10px"}}>
<div>
<Input value={inputValue} onChange={inputChange} style={{ width:'250px', marginRight:'10px'}}/>
<Button type="primary" onClick={clickButton}>增加</Button>
</div>
<div style={{margin:'10px',width:'300px'}}>
<List
bordered
dataSource={list}
renderItem={(item, index)=>(<List.Item key={index} onClick={() => deleteItem(index)}>{item}</List.Item>)}
/>
</div>
</div>
)
}
const mapStateToProps = (state) => {
return {
inputValue : state.inputValue,
list: state.list,
}
}
const mapDispatchToProps = (dispatch) => {
return {
getTodoList() {
const action = getTodoListAction();
dispatch(action);
},
inputChange(e) {
const action = changeInputAction(e.target.value);
dispatch(action);
},
clickButton() {
const action = addItemAction();
dispatch(action);
},
deleteItem(index) {
const action = deleteItemAction(index);
dispatch(action);
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(TodoList);
TodoList案例运行:
如果想要进一步了解react-redux的流程,可以通过Redux DevTools工具来调试