Redux 与 react-redux 使用总结
Redux = Reducer + Flux
1. redux 基本使用
1.1 安装
安装 redux
npm install redux
安装 redux-thunk
(如需支持异步 action)
npm install redux-thunk
1.2 使用示例代码
工程目录
src
├─ components
│ └─ Count
│ └─ index.jsx
├─ redux
│ ├─ count
│ │ ├─ action.js
│ │ ├─ constant.js
│ │ └─ reducer.js
│ ├─ person
│ └─ store.js
├─ App.jsx
└─ index.jsx
index.js (入口文件)
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import store from './redux/store';
ReactDOM.render(<App />, document.getElementById('root'));
// 监测redux状态的改变,重新渲染App组件(react-redux不用手动监测,包裹 Provider 实现)
store.subscribe(() => {
ReactDOM.render(<App />, document.getElementById('root'));
});
redux/store.js
import { createStore, applyMiddleWare, combineReducers } from "redux";
import thunk from "redux-thunk"; // 用于支持异步 action
import countReducer from "./count/reducer";
import personReducer from "./person/reducer";
// 最简使用
// export default createStore(reducer);
// 支持异步
// export default createStore(reducer, applyMiddleWare(thunk));
// 支持多个 reducer
const reducer = combineReducers({
count: countReducer,
person: personReducer
});
export default createStore(reducer, applyMiddleWare(thunk));
redux/count/constant.js
export const INCREMENT = "increment";
export const DECREMENT = "decrement";
redux/count/reducer.js
import { INCREMENT, DECREMENT } from "./constant";
const initState = 0 // 初始化状态
export default function countReducer(preState = initState, action) {
const { type, data } = action
switch (type) {
case INCREMENT:
return preState + data;
case DECREMENT:
return preState - data;
default:
return preState;
}
}
redux/count/action.js
import { INCREMENT, DECREMENT } from "./constant";
// 同步 action(返回对象)
export const increment = (data) => ({ type: INCREMENT, data });
export const decrement = (data) => ({ type: DECREMENT, data });
// 异步 action(返回函数。一般会在异步任务返回时,调用同步action)
export const incrementAsync = (data, time) => {
return (dispatch) => {
setTimeout(() => {
dispatch(increment(data));
}, time);
};
};
components/Count/index.jsx (应用层)
import store from 'redux/count/store';
import { increment, incrementAsync } from 'redux/count/action'
export default class Count extends Component {
increment = () => {
const {value} = this.selectNumber
store.dispatch(increment(value*1));
};
incrementAsync = () => {
const {value} = this.selectNumber
store.dispatch(incrementAsync(value*1, 500));
};
render() {
return <div>
<h1>当前求和为:{this.props.count}</h1>
<select ref={c => this.selectNumber = c}>
<option value="1">1</option>
<option value="2">2</option>
</select>
<button onClick={this.increment}>+</button>
</div>
}
}
2. react-redux 基本使用
2.1 安装
npm install react-redux
2.2 使用示例代码
工程目录
src
├─ containers
│ └─ Count
│ └─ index.jsx
├─ redux
│ ├─ count
│ │ ├─ action.js
│ │ ├─ constant.js
│ │ └─ reducer.js
│ ├─ person
│ └─ store.js
├─ App.jsx
└─ index.jsx
index.js (入口文件)
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import store from './redux/store';
import { Provider } from 'react-redux';
// 用 Provider 包裹,1. 监测redux状态的改变,重新渲染 App 组件 2. 将 store 传给所有后代组件
ReactDOM.render(<Provider store={store}><App /></Provider>, document.getElementById('root'));
App.jsx
import React, { Component } from 'react';
import Count from './containers/Count';
// import store from './store';
export default class App extends Component {
render() {
return (
<div>
{/* 将 store 传个容器组件(入口文件使用 Provider 后,不用传) */}
{/* <Count store={store} /> */}
<Count />
</div>
);
}
}
containers/Count/index.jsx(应用层)——定义UI组件与container组件
import React, { Component } from 'react';
import { connect } from 'react-redux'
import { increment } from '../../redux/count/action'
// 定义UI组件
class Count extends Component {
increment = () => {
const {value} = this.selectNumber
this.props.increment(value*1);
};
render() {
return <div>
<h1>当前求和为:{this.props.count}</h1>
<select ref={c => this.selectNumber = c}>
<option value="1">1</option>
<option value="2">2</option>
</select>
<button onClick={this.increment}>+</button>
</div>
}
}
// 映射状态(返回一个对象,key作为UI组件的props)
const mapStateToProps = state => ({ count: state.count, person: state.person})
// 映射操作状态的方法(返回一个对象,key作为UI组件的props)
// const mapDispatchToProps = dispatch => ({
// add: val => dispatch(increment(val))
// })
// mapDispatchToProps 简写
const mapDispatchToProps = {
increment: increment
}
export default connect(mapStateToProps, mapDispatchToProps)(Count);
3. Redux DevTools 使用
3.1 安装浏览器插件 Redux DevTools
3.2 项目配置
npm install redux-devtools-extension
// redux/store.js
import { createStore, applyMiddleWare, combineReducers } from "redux";
import thunk from "redux-thunk";
import countReducer from "./count/reducer";
import personReducer from "./person/reducer";
import { composeWithDevTools } from 'redux-devtools-extension'
// 不使用插件调试
// export default createStore(
// reducer,
// import.meta.env.REACT_APP_MODE === "development" &&
// window.__REDUX_DEVTOOLS_EXTENSION__ &&
// window.__REDUX_DEVTOOLS_EXTENSION__()
// );
// 使用插件调试
const reducer = combineReducers({
count: countReducer,
person: personReducer
});
// export default createStore(reducer, composeWithDevTools(); // 无异步
export default createStore(reducer, composeWithDevTools(applyMiddleWare(thunk)); // 有异步