react-redux 是一个 react 的插件库,它是专门用来简化 react 应用中使用 redux的
传送门
让所有组件都可以得到 state 数据
<Provider store={store}>
<App />
</Provider>
用于包装 UI 组件生成容器组件
export default connect(mapStateToProps, mapDispatchToProps)(Counter);
将外部的数据(即state对象)转换为UI组件的标签属性
const mapStateToProps = (state) => {
return {
counter: state.counter
}
}
const mapDispatchToProps = (dispatch) => {
return {
increment: (value) => {
dispatch(createIncrementAction(value));
},
decrement: (value) => {
dispatch(createDecrementActio(value));
}
}
}
将分发action的函数转换为UI组件的标签属性
const mapDispatchToProps = (dispatch) => {
return {
increment: (value) => {
dispatch(createIncrementAction(value));
},
decrement: (value) => {
dispatch(createDecrementActio(value));
}
}
}
传送门
处理异步编程的问题
store.js
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import reducer from './reducer';
let store = createStore(reducer, composeWithDevTools(applyMiddleware(thunk)));
export default store;
export const createIncrementAsyncAction = () => {
return (dispatch) => {
axios.get("http://localhost:3000/banner").then(res => {
const data = res.data.data
dispatch(createChangeBannersAction(data.banners));
})
}
}
import {combineReducers} from 'redux';
const reducer = composeEnhancers({
counterInfo: counterReducer,
bannersInfo: bannersReducer
});
默认是不那个用的需要进行简答的处理,两种方法:
1、安装依赖包redux-devtools-extension
,修改 store.js 文件
import { composeWithDevTools } from 'redux-devtools-extension'
const store = createStore(
reducer,
composeWithDevTools(applyMiddleware(thunk))
)
2、引入 composeEnhancers
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import reducer from './reducer';
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
let store = createStore(reducer, composeEnhancers(applyMiddleware(thunk)));
export default store;
传送门
实现一个简答的计数器,功能大致如下
import React, { Component } from 'react';
class App extends Component {
constructor() {
super();
this.state = {
counter: 0
}
}
render() {
return (
<div>
<h2>当前计数:{this.state.counter}</h2>
<select ref="selectRef">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={() => {this.increment()}}>+</button>
<button onClick={() => {this.decrement()}}>-</button>
<button onClick={() => {this.incrementAsync()}}>一秒后再加</button>
</div>
);
}
increment() {
const { value } = this.refs.selectRef;
let { counter } = this.state;
counter += Number(value);
this.setState({
counter
});
}
incrementAsync() {
setTimeout(() => {
this.increment();
}, 1000);
}
decrement() {
const { value } = this.refs.selectRef;
let { counter } = this.state;
counter -= Number(value);
this.setState({
counter
});
}
}
export default App;
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import store from "./store/store";
ReactDOM.render(<App store={store}/>, document.getElementById("root"));
// 监听 state 的变化
store.subscribe(() => {
ReactDOM.render(<App store={store}/>, document.getElementById("root"));
})
App.js
import React, { Component } from 'react';
import { createDecrementActio, createIncrementAction } from './redux/createActions'
class App extends Component {
componentDidMount() {
console.log(this.props.store);
}
render() {
const { counter } = this.props.store.getState();
return (
当前计数:{counter}
);
}
increment() {
const store = this.props.store;
let { value } = this.refs.selectNumberRef;
store.dispatch(createIncrementAction(Number(value)));
}
incrementAsync() {
const store = this.props.store;
let { value } = this.refs.selectNumberRef;
setTimeout(() => {
store.dispatch({
type: 'incrementAsync',
data: Number(value)
})
}, 1000);
}
decrement() {
const store = this.props.store;
let { value } = this.refs.selectNumberRef;
store.dispatch({
type: 'decrement',
data: Number(value)
})
}
}
export default App;
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import store from "./redux/store";
ReactDOM.render(<Redux store={store}/>, document.getElementById("root"));
// 监听 state 的变化
store.subscribe(() => {
ReactDOM.render(<Redux store={store}/>, document.getElementById("root"));
})
store 文件夹
store.js
import { createStore } from 'redux';
import reducer from './reducer';
// 创建 store
const store = createStore(reducer);
export default store;
reducer.js
import { INCREMENT, DECREMENT } from './actionTypes';
const defaultState = {
counter: 1
}
function handleCounter(preState = defaultState, action) {
console.log(action);
let newState;
switch (action.type) {
case INCREMENT:
newState = {
counter: preState.counter + action.data
};
return newState;
case 'incrementIfOdd':
newState = {
counter: preState.counter + action.data
};
return newState;
case 'incrementAsync':
newState = {
counter: preState.counter + action.data
};
return newState;
case DECREMENT:
newState = {
counter: preState.counter - action.data
};
return newState;
default:
return preState;
}
}
export default handleCounter;
createActions.js
import { INCREMENT, DECREMENT, INCREMENTASYNC } from './actionTypes';
export const createIncrementAction = value => ({
type: INCREMENT,
data: value
})
export const createDecrementActio = value => ({
type: DECREMENT,
data: value
})
export const createIncrementAsyncAction = (value, delay) => {
return (dispatch) => {
setTimeout(() => {
dispatch(createIncrementAction(value, delay));
}, delay);
}
}
actionTypes.js
export const INCREMENT = 'increment';
export const DECREMENT = 'decrement';
export const INCREMENTASYNC = 'incrementAsync';
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import store from "./store/store";
import { Provider } from "react-redux";
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
将 App.js 进行拆分
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pA5syu64-1597136908932)(C:\Users\27857\Desktop\QQ截图20200811153735.png)]
counter.jsx
import React, { Component } from 'react';
class Counter extends Component {
componentDidMount() {
console.log(this.props)
}
render() {
return (
<div>
<h2>当前计数:{this.props.counter}</h2>
<select ref="selectNumberRef">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={() => {this.increment()}}>+</button>
<button onClick={() => {this.decrement()}}>-</button>
<button onClick={() => {this.incrementIfOdd()}}>odd</button>
<button onClick={() => {this.incrementAsync()}}>async</button>
</div>
);
}
increment() {
let { value } = this.refs.selectNumberRef;
this.props.increment(Number(value));
}
incrementAsync() {
let { value } = this.refs.selectNumberRef;
this.props.incremenAsync(Number(value), 1000);
}
decrement() {
let { value } = this.refs.selectNumberRef;
this.props.decrement(Number(value));
}
}
export default Counter;
counter_container.js
import { connect } from 'react-redux';
import Counter from '../components/counter';
import { createDecrementActio, createIncrementAction, createIncrementAsyncAction } from '../redux/createActions';
const mapStateToProps = (state) => {
return {
counter: state.counter
}
}
const mapDispatchToProps = (dispatch) => {
return {
increment: (value) => {
dispatch(createIncrementAction(value));
},
decrement: (value) => {
dispatch(createDecrementActio(value));
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Counter);
可以对上面进行简单优化
export default connect(
state =>({
counter: state.counter
}),
{
increment: createIncrementAction,
decrement: createDecrementActio,
incremenAsync: createIncrementAsyncAction
}
)(Counter)
connect 函数的作用
function connect(fn) {
return (value) => {dispatch(fn(value))}
}