redux&react-redux

安装命令
	yarn add redux 
	yarn add react-redux
	yarn add redux-thunk

1 redux是什么

1、redux是一个专门用于做状态管理的js库(不是react插件库)。
2、它可以用在react,angular,vue等项目中,但基本与react配合使用。
3、作用:集中式管理react应用中多个组件共享的状态。
4、 redux只负责管理状态,至于状态的改变驱动着页面的展示,要靠我们自己写

1.1 什么情况下需要使用redux

1、某个组件的状态,需要让其他组件可以随时拿到(共享)。
2、一个组件需要改变另一个组件的状态(通信)。
3、总体原则:能不用就不用,如果不用比较吃力才考虑使用。

1.2 redux的方法

  • subscribe:监测redux中状态的改变,如redux的状态发生了改变,就执行一次

    语法:store.subscribe( ()=>{} )
    取消订阅:store.subscribe( ()=>{} )()

  • dispatch:传递action

    语法:store.dispatch({type:'',data:''})

  • getState:获取当前store的值

    语法:store.getState()

  • replaceReducer(nextReducer) : 替换 store 当前用来计算 state 的 reducer。

1.3 redux的api

  • createStore :专门用于创建redux中最为核心的store对象

    3个参数
    1、reducer (Function): 接收两个参数,分别是当前的 state 树和要处理的 action,返回新的 state 树。
    2、[preloadedState] (any): 初始时的 state。
    3、enhancer (Function): Store enhancer,可选使用。可以用第三方第能力如中间价、时间旅行、持久化来增强 store

  • applyMiddleware :中间件,用于配合redux-thunk(插件,需要引入)支持异步
  • combineReducers :当有多个状态时需要使用,可以将状态合并为一个对象

2、react-redux

2.1 概念

  • UI组件:不能使用任何redux的api,只负责页面的呈现,交互等.
  • 容器组件:负责和redux通信,将结果交给UI组件.

2.2 react-redux的api

  • Provider :无需自己给容器组件传递store,给根组件包裹一个即可

    语法:<Provider store={store}>

  • connect : 生成一个容器组件,并暴露(类组件使用)

      	两种用法,还有获取dispatch的方式
      		语法①: connect(mapStateToProps,mapDispatchToProps)(UI组件)
      			直接从函数的参数中就可以获取到dispatch
      			mapStateToProps(state)
      	    	mapStateToProps(dispatch,ownProps) 
      	    语法②:connect(mapStateToProps,null)(UI组件)
      	    	需要从UI组件的props中拿到dispath
    
  • useSelector:相当于类组件的mapStateToProps

    语法 :const state = useSelector(state=>state)

  • useDispatch: 相当于类组件的mapDispatchToProps

    语法:
    cosnt dispatch = useDispatch()
    dispatch( action动作对象 )

    【注意】:useDispatch()(action对象) 直接使用会报错

2.3 connect的语法

//未简写
mapStateToProps(state){}
mapDispatchToProps(dispatch,ownProps){}
connect(mapStateToProps,mapDispatchToProps)(UI组件)
//mapStateToprops:映射状态,返回值是一个对象,默认接收state作为参数
//mapDispatchToProps:映射操作状态的方法,返回值是一个对象,默认接收dispatch,ownProps作为参数
//[备注]:容器组件中的store是靠props传进去的,而不是在容器组件中直接介入
//[备注]:mapDispatchToProps,也可以直接是一个对象,会自动注入dispatch(所以对象的方式不用写dispatch)
// 简写
connect(
  state=>({key:value}),//映射状态
  {key:xxxxxAction}//映射操作状态的方法
)(UI组件)

3、模型图

在这里插入图片描述
在这里插入图片描述

4、一个简单的todolist案列(包含数据持久化)

4.0、redux&react-redux 项目结构

	store
		index.js 创建一个store容器
	views
		Lists——>这个名是看文件,语义化就好了
			 redux 
				- Actions.js   返回一个或多个动作对象,一般为`{type:'',data:''}`
				- ActionsTypes.js   返回一个或多个常量,用做Actions和Reducer的type值
				- Reducer.js    返回一个纯函数,用于处理动作对象
			 index.js    将actions和reducer函数集中导出(方便管理)
			 index.jsx    容器组件和UI组件的结合体

数据持久化看src/store/index.jssrc/router.js

4.1 src/store/index.js

此文件主要就是创建一个仓库
将需要用到的reducer文件引入
从本地存储中取值,放进createStore的第二个参数,初始值的作用

import { createStore, combineReducers,applyMiddleware } from 'redux';
import thunk = 'react-thunk' //支持异步
import { reducer as lists } from '../views/Lists/_index.js'

const reducer = combineReducers({
  lists
})
let initList = JSON.parse(localStorage.getItem("LIST")) || [];
export default createStore(reducer,initList,applyMiddleware(thunk));

4.2 src/router.js

此文件主要就是做一个根组件
通过provider向下传递store
通过subscrbe方法订阅store
getState方法获取store的值存入本地

import React from 'react';
import App from './App';
import { Provider } from 'react-redux';
import Store from './store'

const StoreToken = Store.subscribe(() => {
  // Store.getState()
  // console.log(Store.getState())
  window.localStorage.setItem("LIST", JSON.stringify(Store.getState()))
})
//StoreToken() 这样可以取消订阅

const Router = () => {

  return (
    <div>
      <Provider store={Store}>
        <App />
      </Provider>

    </div>
  )
}
export default Router

4.3 src/List/redux/actions.js

此文件主要是返回一个action动作对象
action动作对象必须要有一个type属性

import * as actiontypes from './actionTypes';
export const addList = (data) => ({ type: actiontypes.ADDList, data })
export const delList = (data) => ({ type: actiontypes.DELLIST, data })

4.4 src/List/redux/actionTypes.js

此文件主要是返回一个常量,目的是防止出现字母错误(默认是大写)

export const ADDList = "ADDLIST";
export const DELLIST = "DELLIST";

4.5 src/List/redux/reducer.js

此文件返回一个纯函数,用于接收dispatch传来的action,进行处理之后返回store
默认注入两个参数(preState,action)
preState需要设置初始值
reducer被第一次调用时,是store自动触发的,传递的preState是undefined
必须要有默认返回值

import * as actionTypes from './actionTypes';
const reducer = (preState = [], action) => {
  const { type, data } = action;

  switch (type) {
    case actionTypes.ADDList:
      const result = [
        data,
        ...preState
      ]
      console.log(result)
      return result
    case actionTypes.DELLIST:
      preState.splice(data, 1)
      return [...preState]
    default:
      return preState
  }
}
export default reducer

4.6 src/List/_index.js

汇总action和reducer方便管理
actions文件只有一个
reducer文件或许会有多个

import * as actions from './redux/actions';
import reducer from './redux/reducer';

export { actions, reducer }

4.7-1 src/List/_index.js (类组件写法)

类组件中获取cannect中函数映射的值和函数都是通过props拿到的

import React,{Component} from 'react';
import { connect } from 'react-redux';
import * as actions from './redux/actions';

class View extends Component{
  

  // 渲染函数
  rLsits = () => {
    let { lists } = this.props;
    return lists.map((value, index) => (
      <li key={index}>{value} <button onClick={()=>{this.delfn(index)}}>删除</button></li>
    ))
  }
    // 添加数据
  send = () => {
    let val = this.inp.value;
    this.props.addLists(val)
    this.inp.value=""
  }
   // 删除数据
   delfn = (index) => {
     this.props.delLists(index)
  }
  render() {
    return (
      <div>
        <h2>这是一个class类组件操作数组数据的例子</h2>
        <input ref={value=>this.inp=value} type="text" />
        <button onClick={()=>{this.send()}}>发送</button>
        {this.rLsits()}
      </div>
    )
  }
}
// 写法一  mapDispatchToProps是一个对象
export default connect(
  state => ({ lists: state.lists }),
  {
    addLists: actions.addList,
    delLists: actions.delList
  }
)(View)

// 写法二   mapDispatchToProps是一个函数
// export default connect(
//   state => ({ lists: state.lists }),
//   (dispatch, ownProps) => ({
//     addLists: data => { dispatch(actions.addList(data)) },
//     delLists: data => { dispatch(actions.delList(data)) }
//   })
// )(View)


// 写法三   mapDispatchToProps为null
// 需要在UI组件内通过this.props.dispath传递action动作对象
// export default connect(
//   state => ({ lists: state.lists }),
//   null
// )(View)

4.7-2 src/List/_index.js (函数组件写法)

函数组件的值是通过useSelector拿到的
函数组件的dispatch是通过useDispatch 拿到的

import React,{useRef} from 'react';
import { useSelector, useDispatch } from 'react-redux';
import * as actions from './redux/actions'
const View = () => {
  let inp = useRef();
  const state = useSelector(state=>state)
  const dispath = useDispatch()
  
  const rLsits = () => {
    console.log('我执行了')
    return state.lists.map((value, index) => (
      <li key={index}>{value} <button onClick={()=>{delLists(index)}}>删除</button></li>
    ))
  }
  // 添加数据
  const send = () => {
    let val = inp.current.value;
    dispath(actions.addList(val))
    inp.current.value=""
  }
  // 删除数据
  const delLists = (index) => {
     dispath(actions.delList(index))
  }
  return (
    <div>
      <h2>这是一个函数组件操作数组数据的例子</h2>
      <input ref={inp} type="text" />
      <button onClick={send}>发送</button>
      {rLsits()}
    </div>
  )
  
}

export default View;

【补】纯函数

  • 一类特别的函数:只要是同样的输入(实参),必定得到同样的输出(返回)
  • 必须遵守以下一些约束
    • 不得改写数据
    • 不会产生任何副作用,例如网络请求,输入和输出设备
    • 不能调用Date.now()或者Math.random()等不纯的方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值