React Redux
一、Redux
# 下载 redux
npm i redux
1. redux
的简单使用:
const redux = require("redux");
// 初始化 state
const initState = {
count: 0
}
// reducer,纯函数
function reducer(state = initState, action) {
switch (action.type) {
case "incremnet":
return { ...state, count: state.count + 1 };
case "decremnet":
return { ...state, count: state.count - 1 };
case "add_number":
return { ...state, count: state.count + action.data };
case "sub_number":
return { ...state, count: state.count - action.data };
default:
return state
}
}
// store
const store = redux.createStore(reducer);
// 订阅 store 中 state 的改变
store.subscribe(() => {
console.log("state改变了", store.getState());
})
// action
const action1 = { type: "incremnet" };
const action2 = { type: "decremnet" };
const action3 = { type: "add_number", data: 5 };
const action4 = { type: "sub_number", data: 8 };
// dispatch
store.dispatch(action1);
store.dispatch(action2);
store.dispatch(action3);
store.dispatch(action4);
输出结果:
# state改变了 { count: 1 }
# state改变了 { count: 0 }
# state改变了 { count: 5 }
# state改变了 { count: -3 }
2. redux
的文件结构使用
使用redux
的文件结构:
- store
-- actions # 文件夹,存放 actionCreators 函数
-- reducers # 文件夹,存放创建 reducer 函数
--- index.js # 合并 reducer
-- index.js # 整合 store 对象,并export 导出
-- constants.js # 存放 redux 中 action 使用的 type 类型
2.1 redux
代码
store/constants.js
/**
* 用于保存 action中 type 常量值
*/
export const INCREMENT = "increment"
export const DECREMENT = "decrement"
export const ADD_PERSON = "add_person"
store/actions/count.js
import { INCREMENT, DECREMENT } from '../constants'
export function createIncrementAction(data) {
return {
type: INCREMENT,
data
}
}
export const createDecrementAction = (data) => ({type: DECREMENT, data})
store/actions/person.js
import { ADD_PERSON } from '../constants'
// 创建增加一个人的 action
export function createAddPerson(data) {
return {
type: ADD_PERSON,
data
}
}
store/reducers/count.js
import { INCREMENT, DECREMENT } from '../constants'
export default function countReducer(state = 0, action) {
switch (action.type) {
case INCREMENT:
return state + action.data;
case DECREMENT:
return state - action.data;
default:
return state;
}
}
store/reducers/person.js
import { ADD_PERSON } from "../constants"
const initState = [
{ id: "001", name: "小李", age: 18 },
{ id: "002", name: "刘哲", age: 25 },
]
export default function personReducer(prevState = initState, action) {
switch (action.type) {
case ADD_PERSON:
return [...prevState, action.data];
default:
return prevState;
}
}
store/index.js
import { createStore, combineReducers } from 'redux'
// 引入 count 的 reducer
import countReducer from './reducers/count.js'
// 引入 person 的 reducer
import personReducer from "./reducers/person.js"
// 合并 reducer,key:value 形式存在 store 中
const allReducers = combineReducers({
count: countReducer,
person: personReducer
})
// 暴露 store 对象
export default createStore(allReducers)
2.2 使用 redux
和
store
文件夹同一层级 创建index.js
import store from "./store/index.js"
import { createIncrementAction, createDecrementAction } from "./store/actions/count.js"
store.subscribe(() => {
console.log(store.getState().count);
})
store.dispatch(createIncrementAction(2));
store.dispatch(createDecrementAction(4));
store.dispatch(createDecrementAction(3));
store.dispatch(createIncrementAction(6));
/*
2
-2
-5
1
*/
3. 异步 action
一般 action 都是 同步的,即返回 对象格式的。
而异步 action 则是 返回 函数形式。
// 异步 action,返回 函数
export function createAsyncIncrement(data, delay) {
// 异步 action 返回函数 可以有两个参数
return (dispatch, getState) => {
// 模仿异步请求
setTimeout(() => {
dispatch("创建action的函数"(data))
}, delay)
}
}
store
需要配置使用 异步中间件 redux-thunk
import { createStore, applyMiddleware, combineReducers, compose } from 'redux'
// 引入 redux-thunk ,异步 action
import thunk from 'redux-thunk'
export default createStore(allReducers, applyMiddleware(thunk))
4. 使用 redux 的Chrome插件
-
首先下载浏览器扩展
Redux DevTools
,Chrome谷歌商店下载即可 -
配置 store 对象
import { compose } from 'redux' // 使用compose,强化 const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose // 如果使用了异步中间件 export default createStore(allReducers, composeEnhancers(applyMiddleware(thunk)))
5. 合并 reducer
import { combineReducers } from 'redux'
// 合并 reducer,key:value 形式存在 store 中
const allReducers = combineReducers({
count: countReducer,
person: personReducer
})
// 暴露 store 对象
export default createStore(allReducers)
二、react-redux
# 下载 react-redux
npm i react-redux
1. 概念
Provider
提供 store
给子组件。
原理:Provider 利用 context 传递 store 数据。
<Provider store={store}>
<App />
</Provider>,
connect
连接父组件 provider
提供的 store
数据
connect 就是高阶组件,利用 Provider 中 的 context 获得 store 中的数据,然后 返回一个新组件,属性上添加 store 上的数据。
export default connect(mapStateToProps, mapDispatchToProps)("组件名")
// mapStateToProps 是函数
// mapDispatchToProps 是函数
function mapStateToProps(state){
return {
xxxx: state.xxxx
}
}
function mapDispatchToProps(dispatch){
return {
xxx: () => dispatch("创建action的")
}
}
2. 在react
项目中使用
src/index.js
// 引入 Provider,包裹 APP 组件
import { Provider } from "react-redux"
// 引入 store
import store from "./redux/store.js"
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
src/App.js
import React, { Component } from 'react'
import Count from './components/Count'
export default class App extends Component {
render() {
return (
<div>
{/* 通过react-redux 使用 redux */}
<Count />
</div>
)
}
}
src/components/Count.jsx
import React, { Component } from 'react'
// 引入connect
import { connect } from "react-redux"
// 引入创建 action 的函数
import { createIncrementAction, createDecrementAction, createAsyncIncrement } from "../store/actions/count"
class NewCount extends Component {
optionValue = React.createRef();
increament = () => {
this.props.jia(+this.optionValue.current.value);
}
decreament = () => {
this.props.jian(+this.optionValue.current.value);
}
render() {
return (
<div>
<h2>我是Count组件</h2>
<p>当前 count 的值:{this.props.count}</p>
<select name="" id="" ref={this.optionValue}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increament}> + </button>
<button onClick={this.decreament}> - </button>
</div>
)
}
}
// 使用 connect
export default connect(
(state) => ({ count: state.count }),
{
jia: createIncrementAction,
jian: createDecrementAction,
// jia(num){ dispatch(createIncrementAction(num)) }
})(NewCount)