redux中最主要的东西就三个:store,reducer,action
store可以说是redux的躯干,由它撑起一个架子,所有被管理的状态也是由它存储(正如它的名字store)
action是描述所要执行的任务以及传递要进行操作的数据(如果需要的话)
reducer则是一个执行者,根据action中所描述的行为,执行定义好的操作(对数据进行处理),并将新的数据返回,(这个过程不应对原有的状态做出改变)
一、只含同步操作
1、建立reducer.js
import { combineReducers } from "redux" import { hindleAddOrMinusReducer } from "./handleAddOrMinusReducer" import { hindleShowOrHideReducer } from "./handleShowOrHideReducer" //combineReducers用于将不同的reducer进行整个为一个reducer //为什么会有多个reducer? //进行项目开发时,常常时多人合作,每个人负责不同的业务,如果把所有的操作都放到一个reducer里,大家都对这个文件 //进行修改,会显得有些杂乱,所以针对不同的业务,建立不同的reducer文件,不仅结构更加清晰,且编码时也不会有 //不必要的冲突 const reducer = combineReducers({ hindleAddOrMinusReducer, hindleShowOrHideReducer }) export default reducer
const hindleAddOrMinusReducer = function (prevState = { count: 0 }, action) { const { type, payload } = action const newState = { ...prevState } switch (type) { case 'add': newState.count+=payload return newState case 'minus': newState.count-=payload return newState default: return prevState } } export { hindleAddOrMinusReducer }
const hindleShowOrHideReducer = function (prevState = { isShow: true }, action) { const { type, payload } = action const newState = { ...prevState } switch (type) { case 'show': newState.isShow = true return newState case 'hide': newState.isShow = false return newState default: return prevState } } export { hindleShowOrHideReducer }
2,建立action
hideOrShow.js
const show = function () { return { type: 'show' } } const hide = function () { return { type: 'hide' } } export { show, hide }
addOrMinus.js
const add = function (data) { return { type: 'add', payload: data } } const minus = function (data) { return { type: 'minus', payload: data } } export { add, minus }
3.建立store.js
import { createStore } from "redux"; import reducer from "./reducer/reducer"; const store = createStore(reducer) export default store
4.建立App.js
注意:因为redux是第三方的库,因此其保存的状态更新后不会引起组件刷新,所以需要手动的调用react的this.setState({})方法(类式组件)、调用使用useState()创建的函数
或者使用redux的subscribe函数,该函数会在任意redux状态改变后执行,可以将根组件的render函数用store.subscribe(()=>{})包裹,每次redux状态改变后重新渲染所有组件
import React, { Component } from 'react' import { add, minus } from './redux/action/addOrMinus' import { hide, show } from './redux/action/hideOrShow' import store from './redux/store' export default class App extends Component { render() { return ( <div> <p>当前值为:{store.getState().hindleAddOrMinusReducer.count}</p>
<button onClick={() => { store.dispatch(add(2)); this.setState({}) }}>+2</button> <button onClick={() => { store.dispatch(minus(3)); this.setState({}) }}>-3</button> <div> {store.getState().hindleShowOrHideReducer.isShow && <div style={{ width: '100px', height: '100px', background: 'yellow' }}>我出来了</div>} <button onClick={() => { store.dispatch(show()); this.setState({}) }}>显示</button> <button onClick={() => { store.dispatch(hide()); this.setState({}) }}>隐藏</button> </div> </div> ) } }
-------------------------------------------------------------------------------------------分割线
运行时界面如下图所示
---------------------------------------------------------------------------------------------------------------分割线
点击+2按钮后
---------------------------------------------------------------------------------------------------------------分割线
点击-3按钮后
---------------------------------------------------------------------------------------------------------------分割线
点击隐藏按钮后
---------------------------------------------------------------------------------------------------------------分割线
点击显示按钮后
二、redux里的异步操作
要在redux中进行异步操作,需要引入一个中间件来处理,就是redux-thunk,以及引入应用中间件的工具:applyMiddleware
1.建立getFilmsAction.js
里面包含一个axios请求,用来向网络中请求异步数据
import axios from "axios" const getFilms = function () { return (dispatch) => { axios( { url: 'https://m.maizuo.com/gateway?cityId=110100&pageNum=1&pageSize=10&type=1&k=998385', headers: { 'X-Client-Info': '{ "a": "3000", "ch": "1002", "v": "5.2.0", "e": "16447435935369241695944705", "bc": "110100" }', 'X-Host': 'mall.film-ticket.film.list' } } ).then(res => { dispatch({ type: 'getFilms', payload: res.data.data.films }) }).catch() } } export { getFilms }
2.修改store.js
引入thunk和applyMiddleware
import { createStore, applyMiddleware } from "redux"; import reducer from "./reducer/reducer"; import thunk from "redux-thunk"; const store = createStore(reducer, applyMiddleware(thunk)) export default store
3.建立getFilmsReducer.js
import { fromJS } from "immutable" const getFilmsReducer = function (prevState = { films: [] }, action) { //进行深拷贝 const newState = fromJS(prevState).toJS() const { type, payload } = action switch (type) { case 'getFilms': newState.films = payload return newState default: return prevState } } export { getFilmsReducer }
4.App.js
import React, { Component } from 'react' import { add, minus } from './redux/action/addOrMinus' import { getFilms } from './redux/action/getFilmsAction' import { hide, show } from './redux/action/hideOrShow' import store from './redux/store' export default class App extends Component { render() { return ( <div> <p>当前值为:{store.getState().hindleAddOrMinusReducer.count}</p> <button onClick={() => { store.dispatch(add(2)); this.setState({}) }}>+2</button> <button onClick={() => { store.dispatch(minus(3)); this.setState({}) }}>-3</button> <div> {store.getState().hindleShowOrHideReducer.isShow && <div style={{ width: '100px', height: '100px', background: 'yellow' }}>我出来了</div>} <button onClick={() => { store.dispatch(show()); this.setState({}) }}>显示</button> <button onClick={() => { store.dispatch(hide()); this.setState({}) }}>隐藏</button> </div> <div> <button onClick={() => { store.dispatch(getFilms()); this.setState({}) }}>获取电影列表</button> <ul> { store.getState().getFilmsReducer.films.map((item) => { console.log(store.getState().getFilmsReducer.films) return <li key={item.filmId}>{item.name}</li> }) } </ul> </div> </div> ) } }
5.修改入口文件(添加store.subscribe()以达到实时更新)
import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './02-redux-thunk/App'; import reportWebVitals from './reportWebVitals'; import store from './02-redux-thunk/redux/store' ReactDOM.render( <React.StrictMode> <App /> </React.StrictMode>, document.getElementById('root') ); //订阅redux状态的改变来渲染APP组件 store.subscribe(() => { ReactDOM.render( <React.StrictMode> <App /> </React.StrictMode>, document.getElementById('root') ); }) // If you want to start measuring performance in your app, pass a function // to log results (for example: reportWebVitals(console.log)) // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals reportWebVitals();
运行时初始界面
---------------------------------------------------------------------------------------------------------------------------------------分割线
点击‘获取电影列表’按钮