react-11-redux(2)

113 阅读4分钟

redux

安装

npm install redux

一、单个reducer的使用

src文件夹下面,新建一个store文件夹,里面新建一个store.js

import { legacy_createStore as createStore } from "redux"

const state = {
  name: "zrs"
}

const reducer = (prevState = state, action = {}) => {
  const newState = { ...prevState }

  switch (action.type) {
    case "change-name":
      newState.name = "名字被改变了"
      return newState
    case "reset-name":
      newState.name = "名字被重置了"
      return newState

    default:
      return prevState
  }
}

const store = createStore(reducer)

export default store

订阅

类组件中订阅

import React, { Component } from "react"

import store from "../store/store"
export default class PageA extends Component {
  state = {
    name: store.getState().name // 设置默认值为store里面的数据
  }
  componentDidMount() {
      // 订阅
    this.unsubscribe=store.subscribe(() => {
      this.setState({ name: store.getState().name })
    })
  }
  componentWillUnmount(){
      // 解除订阅
    this.unsubscribe()
  }
  render() {
    return (
      <>
        <h1>{this.state.name}</h1>
      </>
    )
  }
}

函数式组件中订阅

import React, { useState, useEffect } from "react"
import store from "../store/store"

const PageD = () => {
  const [name, setname] = useState(store.getState().name)  // 设置默认值为store里面的数据
  
  useEffect(() => {
      // 订阅
    const unsubscribe = store.subscribe(() => {
      setname(store.getState().name)
    })
    return () => {
      // 取消订阅
      unsubscribe()
    }
  }, [])

  return (
    <div>
      <h2>{name}</h2>
    </div>
  )
}

export default PageD

dispatch

import React from "react"
import store from "../store/store"

const Button = () => {
  return (
    <>
      <button
        onClick={() => {
          store.dispatch({type:"change-name"})
        }}
      >
        change-name
      </button>
      <button
        onClick={() => {
          store.dispatch({type:"reset-name"})
        }}
      >
        reset-name
      </button>
    </>
  )
}

export default Button

dispatch-action

dispatch 只支持对象为参数,但是可以写一个函数返回对象,返回对象的函数可以定义一些逻辑,这个函数就是action

import React from "react"
import { changeName, resetName } from "../store/actionCreator/NameActionCrator"
import store from "../store/store"

const Button = () => {
  return (
    <>
      <button
        onClick={() => {
          store.dispatch(changeName())
        }}
      >
        change-name
      </button>
      <button
        onClick={() => {
          store.dispatch(resetName())
        }}
      >
        reset-name
      </button>
    </>
  )
}

export default Button

actionCreator

这样写的好处就是可以写一些逻辑。

function changeName() {
  return { type: "change-name" }
}

function resetName() {
  return { type: "reset-name" }
}

export { changeName, resetName }

二、多个reducer的使用

cityReducer

const state = {
  city: "成都"
}

const cityReducer = (prevState = state, action) => {
  const newState = { ...prevState }
  switch (action.type) {
    case "change-city":
      newState.city = "北京"
      return newState
    case "reset-city":
      newState.city = "成都"
      return newState
    default:
      return prevState
  }
}

export default cityReducer

nameReducer

const state = {
  name: "zrs"
}

const nameReducer = (prevState = state, action) => {
  const newState = { ...prevState }
  switch (action.type) {
    case "change-name":
      newState.name = "名字已经被改变了"
      return newState
    case "reset-name":
      newState.name = "zrs"
      return newState
    default:
      return prevState
  }
}

export default nameReducer

将多个reducer合并

使用 combineReducers 将多个reducer合并。

import {
  legacy_createStore as createStore,
  combineReducers
} from "redux"

import cityReducer from "./reducer/cityreducer"
import nameReducer from "./reducer/namereducer"

const rootReducer = combineReducers({
  cityReducer,
  nameReducer
})
const store = createStore(rootReducer)

export default store

订阅

订阅的时候需要添加对应reducer的名字

import React, { useState, useEffect } from "react"
import store from "../store/store"

const PageE = () => {
  const [name, setname] = useState(store.getState().nameReducer.name)
  
  useEffect(() => {
    const unsubscribe = store.subscribe(() => {
      setname(store.getState().nameReducer.name)
    })
    return () => {
      unsubscribe()
    }
  }, [])

  return <h2>{name}</h2>
}

export default PageE

三、在redux中使用异步-1

安装插件

 npm install --save redux-thunk

配置 redux-thunk

import {
  legacy_createStore as createStore,
  combineReducers,
  applyMiddleware
} from "redux"
import reduxThunk from "redux-thunk"

import cityReducer from "./reducer/cityreducer"
import nameReducer from "./reducer/namereducer"
import dataListReducer from "./reducer/dataListRdeducer"

const reducer = combineReducers({
  cityReducer,
  nameReducer,
  dataListReducer
})

// 配置 redux-thunk
const store = createStore(reducer, applyMiddleware(reduxThunk))

export default store

在dispatch-action中使用异步

import axios from "axios"

function getList() {
    // 因为有异步,所以这里需要返回一个函数
  return (dispatch) => {
    axios({
      url: "https://m.maizuo.com/gateway?cityId=110100&ticketFlag=1&k=657515",
      method: "get",
      headers: {
        "X-Client-Info":
          '{"a":"3000","ch":"1002","v":"5.2.1","e":"16653811463674774018457601","bc":"110100"}',
        "X-Host": "mall.film-ticket.cinema.list"
      }
    }).then((res) => {
      console.log(res.data.data.cinemas)
      dispatch({
        type: "get-list",
        payload: res.data.data.cinemas
      })
    })
  }
}

export { getList }

使用含有异步dispatch-action

import React, { Component } from "react"
import { getList } from "../store/actionCreator/dataListActionCreator"
import store from "../store/store"

export default class PageB extends Component {
  state = {
    list: store.getState().dataListReducer.list
  }
  componentDidMount() {
    if (store.getState().dataListReducer.list.length === 0) {
        // 使用action获取数据
      store.dispatch(getList())
    } else {
      console.log("使用缓存的数据")
    }

    this.unsubscribe = store.subscribe(() => {
      this.setState({
        list: store.getState().dataListReducer.list
      })
    })
  }

  componentWillUnmount() {
    this.unsubscribe()
  }
  render() {
    return (
      <div>
        {this.state.list.map((item) => {
          return <div key={item.name}>{item.name}</div>
        })}
      </div>
    )
  }
}

四、在redux中使用异步-2

安装插件

npm install --save redux-promise

使用redux-promise的方式

import {
  legacy_createStore as createStore,
  combineReducers,
  applyMiddleware
} from "redux"

import cityReducer from "./reducer/cityreducer"
import nameReducer from "./reducer/namereducer"
import dataListReducer from "./reducer/dataListRdeducer"

import reduxPromise from "redux-promise"

const reducer = combineReducers({
  cityReducer,
  nameReducer,
  dataListReducer
})

// 配置 redux-promise
// applyMiddleware 里面可以配置很多中间件
const store = createStore(reducer, applyMiddleware(reduxPromise))

export default store

在dispatch-action中使用异步

import axios from "axios"
async function getList() {
  let res = await axios({
    url: "https://m.maizuo.com/gateway?cityId=110100&ticketFlag=1&k=657515",
    method: "get",
    headers: {
      "X-Client-Info":
        '{"a":"3000","ch":"1002","v":"5.2.1","e":"16653811463674774018457601","bc":"110100"}',
      "X-Host": "mall.film-ticket.cinema.list"
    }
  })

  return {
    type: "get-list",
    payload: res.data.data.cinemas
  }
}

export { getList }

使用含有异步的dispatch-action

import React, { Component } from "react"
import { getList } from "../store/actionCreator/dataListActionCreator"
import store from "../store/store"

export default class PageB extends Component {
  state = {
    list: store.getState().dataListReducer.list
  }
  componentDidMount() {
    if (store.getState().dataListReducer.list.length === 0) {
        // 使用action获取数据
      store.dispatch(getList())
    } else {
      console.log("使用缓存的数据")
    }

    this.unsubscribe = store.subscribe(() => {
      this.setState({
        list: store.getState().dataListReducer.list
      })
    })
  }

  componentWillUnmount() {
    this.unsubscribe()
  }
  render() {
    return (
      <div>
        {this.state.list.map((item) => {
          return <div key={item.name}>{item.name}</div>
        })}
      </div>
    )
  }
}

五、redux-devtool

安装该开发工具之后,需要配置这个代码,才能在浏览器中看到具体的state。

import {
  legacy_createStore as createStore,
  combineReducers,
  applyMiddleware,
  compose
} from "redux"


// 以下代码的配置可以实现让 redux-devtool 获取应用中的状态
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose

const store = createStore(
  reducer,
  composeEnhancers(applyMiddleware(reduxPromise))
)

export default store

六、react-redux

这个工具库是来简化redux的操作的,因为使用redux的核心库会使得需要手动取消订阅或者手动订阅,但是这个库将redux中的状态加工为组件的props,就免去了手动订阅和手动取消订阅,因为react的state或者props发生改变,那么界面就会刷新。

安装

npm install --save react-redux

在根组件上配置

import React from "react"
import ReactDOM from "react-dom/client"
import App from "./App"
import { HashRouter as RouterSelf } from "react-router-dom"

import store from "./store/store"
import { Provider } from "react-redux"

const root = ReactDOM.createRoot(document.getElementById("root"))
root.render(
  <RouterSelf>
    <Provider store={store}>
      <App />
    </Provider>
  </RouterSelf>
)

使用connect修改状态

import React, { Component } from "react"
import { getList } from "../store/actionCreator/dataListActionCreator"

import { connect } from "react-redux"

class PageB extends Component {
  componentDidMount() {
    if (this.props.list.length === 0) {
      this.props.getList()
    }
  }
  render() {
    return (
      <>
        {this.props.list.map((item) => {
          return <div key={item.name}>{item.name}</div>
        })}
      </>
    )
  }
}

const mapStateToProps = (state) => {
  return {
    list: state.dataListReducer.list
  }
}
const mapDispatchToProps = {
  getList
}
export default connect(mapStateToProps, mapDispatchToProps)(PageB)

connect()

该方法的作用就是:将statedispatch混入到原组件的props里面。

函数接收两个参数:

第一个参数是一个函数,该函数有一个形参,就是所有的状态值,可以在这个函数中返回需要的状态即可。

第二个参数就是一个对象,对象里面可以书写对应的actionCreator。