Redux学习记录

为了防止自己忘记redux相关内容时找不到笔记,记录下来

预:Redux原理理解图

 

1. redux安装

npm  i  redux  

1.1   redux不分版本与框架,即VUE和React都可以使用

二. Redux初步案例(非全局)

以React项目为例,在React项目的src目录下建立三个不相关JS文件,store/PartA(class组件)/Order(function组件)(名字无实际含义)。

2.1

前往store.js文件中创建store,即声明全局的数据,整个应用需要管理的数据都在store中,也就是store是唯一的,并且store是不能直接修改的,只能触发action返回一个新的store来改变它,

import  {createStore} from  "redux"
//在redux中引入createStore创建唯一的store


function  numReducer(state={num:10},action){
        console.log(action);
        return  state;
}

let  store  = createStore(numReducer);

export  default  store;
2.2

前往创建的PartA.js(class组件)文件中调用redux方法查看上文代码块中num值

import React, { Component } from 'react'
import  store from  "../store";//store存储在同名文件夹下

export default class PartA extends Component {
  render() {
    return (
      <div>PartA
        <div>使用全局的数据 {store.getState().num}</div>
            //getState()是createStore生成的方法,可直接调用
      </div>
    )
  }
}

输出结果:

 

 2.3

Order.js文件中查看num

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

export default function Order() {
  return (
    <div>Order
        <div>全局数据为{store.getState().num}</div>
            //实际上类组件与函数式组件在仅查看上毫无区别
    </div>
  )
}

输出结果一样

二(1)

修改store与它的值(调用dispath触发action)

import React, { Component } from 'react'
import  store from  "../store";

export default class PartA extends Component {
  render() {
    return (
      <div>PartA
        <div>使用全局的数据 {store.getState().num}</div>
        <button onClick={()=>{
            store.dispatch({
                type:"新增"  // 重要核心
            })
        }}>修改</button>
      </div>
    )
  }
}

返回store.js文件,修改代码

import  {createStore} from  "redux"

function  numReducer(state={num:10},action){
      //action.type的值是由个人决定的,是确定的,所以使用switch判断
    switch(action.type){
        case  "新增":
            return  {num:1000}
        default:
            return  state;     
    }
      
}

let  store  = createStore(numReducer);

export  default  store;

点击按钮就可以触发action.type的变化,使num由10变为1000

但是!视图却没有同步更新!

因为按钮触发的事件改变的只是num的值,而num的值早在初次渲染的时候就已经给PartA了,修改num又与我PartA有什么关系呢?

所以!需要给PartA添加更新视图方法,class组件的更新方法是setState, newProps forceUdpate

所以给PartA的Button的onClick事件添加任一方法即可

三,全局挂载store

3.1分离方法

在src中新建文件夹用来专门存放Reducer,也就是store的方法,避免造成管理混乱等问题

文件目录图示意

src
----|Store
----|----|index.js
----|Pages
----|----|PartA.js
----|----|Order.js
----|Reducers
----|----|NumReducers.js

将之前写在Store中的function方法挪至新建的NumReducers.js文件中

function  numReducer(state={num:10},action){
      
    switch(action.type){
        case  "新增":
            return  {num:1000}
        default:
            return  state;     
    }
      
}
export  default numReducer;

Store中引入合并

import  {createStore,combineReducers} from  "redux"

import numReducer from "../Reducers/NumReducer";

let  store  = combineReducers({
    numInfo:numReducer//此后store.numInfo就是一个方法了
})

export  default  createStore(store);

然后在PartA中调用试试效果

  return (
    <div>PartA
      <div>全局使用store的数据:{store.getState().NumInfo.num}</div>
    </div>
  )
3.1.1分离action.type

方法已经分离完毕了,那么就继续分离,分离action的type

新建文件夹action

文件目录示意图

src
----|Store
----|----|index.js
----|Pages
----|----|PartA.js
----|----|Order.js
----|Reducers
----|----|NumReducers.js
----|action
----|----|index.js

在action中声明一个常量用来存储actiontype值,切记是大写对象

//例:
const  info  = {
    "ADDNUM":"ADDNUM"
}
export  default  info;

返回NumReducers.js,修改代码action.type的代码

并新增方法来管理action

import info  from "../action";
function  numReducer(state={num:10},action){
    switch(action.type){
        case  info.ADDNUM:
            return  {num:1000}
        default:
            return  state;     
    }
}

//新增AddNum方法专项管理 ADDNUM
export const AddNum = (payload)=>{
    return {
        type:info.ADDNUM,
        payload
    }
}
export  default numReducer;

返回PartA页面,使用AddNum方法(使用dispath调用,AddNum也可以传值)

import React, { Component } from 'react'
import  store from  "../store";
import  {AddNum} from  "../reducers/numReducer"

export default class PartA extends Component {
  render() {
    return (
      <div>PartA
        <div>使用全局的数据 {store.getState().numInfo.num}</div>
        <button onClick={()=>{
            store.dispatch(AddNum(1))
            this.forceUpdate();
        }}>修改</button>
      </div>
    )
  }
}

返回NumReducers.js,接收AddNum传来的参数

function  numReducer(state={num:10},action){
      
    switch(action.type){
        case  info.ADDNUM:
            return  {num:state.num+action.payload}
        default:
            return  state;     
    }
      
}

3.2全局挂载

引入react-redux

npm i react-redux

react的主入口文件中使用react-redux

import  React from  "react";
import  {createRoot} from  "react-dom/client"
import  {Provider} from  "react-redux"
import  "./css/app.css"
import  App from "./App";
import store from  "./store";

let app  = createRoot(document.getElementById("root"));
app.render(
<Provider store={store}> //使用Provider包裹根组件,store就是store文件中的store
    <App></App>
</Provider>
);
3.2.1 类组件使用

PartA.js/Order.js中引入connect

import React, { Component } from 'react'
import { connect } from 'react-redux'

export class PartA extends Component {
  render() {
    return (
      <div>PartA</div>
    )
  }
}

const mapStateToProps = (state) => ({})

const mapDispatchToProps = {}

export default connect(mapStateToProps, mapDispatchToProps)(PartA)

优化一下,添加数据

import React, { Component } from 'react'
import  {connect} from  "react-redux"

class PartA extends Component {
  render() {
    return (
      <div>PartA
        <div>全局的数据 {this.props.num}</div>
      </div>
    )
  }
}
let  mapStateToProps = (store)=>{
    return  {
        num:store.numInfo.num
    }

}

export default connect(mapStateToProps)(PartA)

再优化一下,添加方法

import React, { Component } from "react";
import { connect } from "react-redux";
import  {AddNum} from  "../reducers/numReducer"

class PartA extends Component {
  render() {
    return (
      <div>
        PartA
        <div>全局的数据 {this.props.num}</div>
        <button onClick={()=>{
            this.props.AddNum(100);
        }}>修改</button>
      </div>
    );
  }
}
const mapDispatchToProps = {
    AddNum
}

export default connect(({ numInfo }) => ({
  num: numInfo.num,
}),mapDispatchToProps)(PartA);
3.2.2函数组件使用

修改Order.js

import React from 'react'
import  {useDispatch,useSelector} from  "react-redux"
import { AddNum } from '../reducers/numReducer'

export default function Order() {
    let num  = useSelector(state=>state.numInfo.num);
    let dispatch = useDispatch();

  return (
    <div>Order

        <div>全局数据 {num}</div>
        <button onClick={(()=>{
            dispatch(AddNum(1));
        })}>修改数据</button>
    </div>
  )
}

3.3实践案例

实现顶部Tab导航条的显示与隐藏(类似于手机商城中点击详情页面不显示底部Tab组件的概念)

创建  flagReducer.js

文件目录示意图:

src
----|Store
----|----|index.js //声明全局变量store
----|Pages
----|----|PartA.js //使用的组件A
----|----|Order.js //使用的组件B
----|Reducers
----|----|NumReducers.js //store中控制num的方法
----|----|flagReducer.js //store中控制flag的方法
----|action
----|----|index.js  //声明action.type

flagReducer.js中声明一个方法

function  flagReducer(state={flag:true},action){
    switch(action.type){

        default:
            return state;
    }
}


export  default  flagReducer;

Store文件夹下合并该方法

import  {createStore,combineReducers} from  "redux"

import numReducer from "../reducers/numReducer";
import flagReducer from "../reducers/flagReducer";

let  store  = combineReducers({
    numInfo:numReducer, //修改store中num值的方法
    flagInfo:flagReducer //修改flag是true还是false的方法
})

export  default  createStore(store);

前往App.js(项目主配置文件)文件中配置全局flag控制路由Tab导航选项

import  {useSelector} from  "react-redux" //useSelector接收一个回调函数
//根据需要返回一个store的状态组件需要的数据

 let flag = useSelector(state=>state.flagInfo.flag);
 
 <div style={{display:flag?"block":"none"}}>
//在App.js的视图结构的最上层添加flag

action中添加flag专属状态

const  info  = {
    "ADDNUM":"ADDNUM", //控制num的action.type
    "CHANGEFLAG":"CHANGEFLAG"//控制flag的action.type
}
export  default  info;

修改flagReducer.js,使flag的值根据action.type改变,以此达成控制Tab组件显示与否的效果

import  info from  "../action"

function  flagReducer(state={flag:true},action){
    switch(action.type){
        case  info.CHANGEFLAG:
            return  {flag:action.payload} //flag的状态就是在这里改变的
        default:
            return state;
    }
}

//该函数就是改变flag的函数,不会忘了store只能依靠action.type改变了吧
export  const  changFlag  = (payload)=>{
    return  {
        type:info.CHANGEFLAG, //不要被info.CHANGEFLAG迷惑了哦,这是action.type的
        payload
    }

}


export  default  flagReducer;

在需要的地方调用changeFlag函数

比如在详情(Detail.js)页调用达成点击详情页Tab消失,退出详情页Tab出现的效果

import React, { useEffect } from "react";
import { useDispatch } from "react-redux";
import { changFlag } from "../reducers/flagReducer";

export default function Detail() {
  let dispatch = useDispatch();
  useEffect(() => { //函数式组件中useEffect可以用来模拟生命周期
    //页面加载
    dispatch(changFlag(false));
    return () => {
      //页面销毁
      dispatch(changFlag(true));
    };
  }, []);
  return <div>Detail</div>;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值