前端学习--React(3)

一、Redux

集中状态管理工具,不需要react即可使用,每个store的数据都是独立于组件之外的

vue小链接:vuex/pinia

基本使用

Redux将数据修改流程分成三个概念,state、action和reducer

state - 一个对象 存放我们管理的数据状态

action - 一个对象 描述你如何修改数据

reducer - 一个函数 根据action的描述生成新的state

<button id="decrement">-</button>
<span id="count">0</span>
<button id="increment">+</button>

<script src="https://unpkg.com/redux@latest/dist/redux.min.js"></script>

<script>
  // 1. 定义reducer函数 
  // 作用: 根据不同的action对象,返回不同的新的state
  // state: 管理的数据初始状态
  // action: 对象 type 标记当前想要做什么样的修改
  function reducer (state = { count: 0 }, action) {
    // 数据不可变:基于原始状态生成一个新的状态 所以要返回新对象
    if (action.type === 'INCREMENT') {
      return { count: state.count + 1 }
    }
    if (action.type === 'DECREMENT') {
      return { count: state.count - 1 }
    }
    return state
  }

  // 2. 使用reducer函数生成store实例
  const store = Redux.createStore(reducer)

  // 3. 通过store实例的subscribe订阅数据变化
  // 回调函数可以在每次state发生变化的时候自动执行
  store.subscribe(() => {
    console.log('state变化了', store.getState())
    document.getElementById('count').innerText = store.getState().count
  })

  // 4. 通过store实例的dispatch函数提交action更改状态 
  const inBtn = document.getElementById('increment')
  inBtn.addEventListener('click', () => {
    // 增
    store.dispatch({
      type: 'INCREMENT'
    })
  })

  const dBtn = document.getElementById('decrement')
  dBtn.addEventListener('click', () => {
    // 减
    store.dispatch({
      type: 'DECREMENT'
    })
  })

  // 5. 通过store实例的getState方法获取最新状态更新到视图中

</script>

react中使用redux

相关工具

Redux Toolkit 简化redux书写逻辑

react-redux 链接Redux和React的中间件

npm i @reduxjs/toolkit react-redux

 安装成功

目录创建

创建src/store,modules存放子模块

counterStore.js

//1 导入并创建store
import {createSlice} from "@reduxjs/toolkit"

const counterStore = createSlice({
    name:'counter',
    // 初始状态
    initialState:{
        count:0
    },
    // 更新状态的方法
    reducers:{
        inscrement(state){
            state.count++
        },
        descrement(state){
            state.count --
        }
    }
})

const {inscrement, descrement} = counterStore.actions
const reducer = counterStore.reducer

export{
    inscrement,
    descrement
}

export default reducer

store/index.js

集成store/modules中所有子模块

import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "./modules/counterStore"

// 将子模块中的所有store合成一个根store方便访问
const store = configureStore({
    reducer:{
        counter:counterReducer,
    }
})

export default store

src/index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import store from "./store"
import { Provider } from 'react-redux';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  // 通过react-redux提供的Provider 给组件注入store 使得redux定义的store能够被react组件使用
  <Provider store={store}>
    <App />
  </Provider>
);

App.js

useDispatch() 通过这个来派发reducer修改状态

import { useSelector, useDispatch } from "react-redux";
import {inscrement, descrement} from "./store/modules/counterStore"
function App() {
  const { count } = useSelector(state => state.counter)
  const dispatch = useDispatch()
  return (
    <div className="App">
      <button onClick={() => dispatch(inscrement())}>+</button>
      {count}
      <button onClick={() => dispatch(descrement())}>-</button>
    </div>
  );
}

export default App;

然后就完成了:

进阶版-提交action时传参

counterStore.js

增加了一个addToNum函数

//1 导入并创建store
import {createSlice} from "@reduxjs/toolkit"

const counterStore = createSlice({
    name:'counter',
    // 初始状态
    initialState:{
        count:0
    },
    // 更新状态的方法
    reducers:{
        inscrement(state){
            state.count++
        },
        descrement(state){
            state.count --
        },
        addToNum(state, action){
            // dispatch调用该方法时传入的参数就存放在action.payload
            state.count += action.payload
        }
    }
})

const {inscrement, descrement, addToNum} = counterStore.actions
const reducer = counterStore.reducer

export{
    inscrement,
    descrement,
    addToNum
}

export default reducer

 App.js

增加了两个值,传入不同参数

import { useSelector, useDispatch } from "react-redux";
import {inscrement, descrement, addToNum} from "./store/modules/counterStore"
function App() {
  const { count } = useSelector(state => state.counter)
  const dispatch = useDispatch()
  return (
    <div className="App">
      <button onClick={() => dispatch(inscrement())}>+</button>
      {count}
      <button onClick={() => dispatch(descrement())}>-</button>
      <button onClick={() => dispatch(addToNum(10))}>+ 10</button>
      <button onClick={() => dispatch(addToNum(-10))}>- 10</button>
    </div>
  );
}

export default App;

再进阶版-异步状态操作

channelStore.js

import {createSlice} from '@reduxjs/toolkit'
import axios from 'axios'

const channelStore = createSlice({
    name:'channel',
    initialState:{
        channelList:[]
    },
    reducers:{
        getChannels(state, action){
            state.channelList = action.payload
        }
    }
})

const {getChannels} = channelStore.actions


//单独写一个异步action的函数 异步操作处理完毕后再调用同步action修改状态
const getChannelList = () => {
    return async(dispatch) => {
        const res = await axios.get('http://geek.itheima.net/v1_0/channels')
        dispatch(getChannels(res.data.data.channels))
    }
}

export {getChannelList}

const reducer = channelStore.reducer
export default reducer

 App.js

import { useSelector, useDispatch } from "react-redux";
import {inscrement, descrement, addToNum} from "./store/modules/counterStore"
import {getChannelList} from "./store/modules/channelStore"
import {useEffect} from 'react'
function App() {
  const { count } = useSelector(state => state.counter)
  const { channelList } = useSelector(state => state.channel)
  const dispatch = useDispatch()

  useEffect(()=> {
    dispatch(getChannelList())
  }, [dispatch])
  
  return (
    <div className="App">
      <button onClick={() => dispatch(inscrement())}>+</button>
      {count}
      <button onClick={() => dispatch(descrement())}>-</button>
      <button onClick={() => dispatch(addToNum(10))}>+ 10</button>
      <button onClick={() => dispatch(addToNum(-10))}>- 10</button>
      <ul>
        {channelList.map(item => <li key={item.id}>{item.name}</li>)}
      </ul>
    </div>
  );
}

export default App;

调试工具redux devtools

直接在chorme商店里下载

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/181821.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OpenStack云计算平台-镜像服务

目录 一、镜像服务概览 二、安装和配置 1、先决条件 2、安全并配置组件 3、完成安装 三、验证操作 一、镜像服务概览 OpenStack镜像服务是IaaS的核心服务&#xff0c;如同 :ref:get_started_conceptual_architecture所示。它接受磁盘镜像或服务器镜像API请求&#xff0c;…

2023服务端测试开发必备技能:Mock测试

什么是mock测试 Mock 测试就是在测试活动中&#xff0c;对于某些不容易构造或者不容易获取的数据/场景&#xff0c;用一个Mock对象来创建以便测试的测试方法。 Mock测试常见场景 无法控制第三方系统接口的返回&#xff0c;返回的数据不满足要求依赖的接口还未开发完成&#…

浅谈电气设备的绝缘在线监测与状态维修探究

贾丽丽 安科瑞电气股份有限公司 上海嘉定 201801 摘要&#xff1a;在线监测是控制好电气设备绝缘的重要方式&#xff0c;为电力系统稳定奠定重要基础。在线监测电气设备时&#xff0c;要利用检测技术促进电力系统运行效率提升&#xff0c;让电气设备在具体工作过程中发挥更大作…

YAML 深入解析:从语法到最佳实践

什么是YAML YAML&#xff08;YAML Ain’t Markup Language&#xff09;是一种人类可读的数据序列化语言。它的设计目标是使数据在不同编程语言之间交换和共享变得简单。YAML采用了一种简洁、直观的语法&#xff0c;以易于阅读和编写的方式表示数据结构。 YAML广泛应用于配置文…

外部 prometheus监控k8s集群资源(pod、CPU、service、namespace、deployment等)

prometheus监控k8s集群资源 一&#xff0c;通过CADvisior 监控pod的资源状态1.1 授权外边用户可以访问prometheus接口。1.2 获取token保存1.3 配置prometheus.yml 启动并查看状态1.4 Grafana 导入仪表盘 二&#xff0c;通过kube-state-metrics 监控k8s资源状态2.1 部署 kube-st…

php生成xml数据

在PHP中&#xff0c;你可以使用以下几种方法生成XML数据&#xff1a; 使用DOM扩展&#xff1a; $xml new DOMDocument(1.0, UTF-8); $root $xml->createElement(root); $xml->appendChild($root); $child $xml->createElement(child); $root->appendChild($ch…

鸿蒙原生应用/元服务开发-AGC分发如何配置签名信息

使用制作的私钥&#xff08;.p12&#xff09;文件、在AGC申请的证书文件和Profile&#xff08;.p7b&#xff09;文件&#xff0c;在DevEco Studio配置工程的签名信息&#xff0c;以构建携带发布签名信息的APP。 1.打开DevEco Studio&#xff0c;菜单选择“File > Project S…

IP定位揭秘:如何揪出SEM、百度竞价恶意点击

在当今的数字营销领域&#xff0c;搜索引擎营销&#xff08;SEM&#xff09;和百度竞价成为了企业推广的重要手段。然而&#xff0c;随着这些渠道的普及&#xff0c;恶意点击现象也日益严重。恶意点击主要来自竞争对手&#xff0c;或是竞价服务的提供商&#xff0c;他们通过点击…

听GPT 讲Rust源代码--src/tools(2)

题图来自AI生成 File: rust/src/tools/rust-analyzer/crates/hir-def/src/src.rs rust-analyzer 是一个 Rust 语言的语法分析器和语义分析器&#xff0c;用于提供代码补全、导航、重构等开发工具。而 rust-analyzer 的代码实现存储在 rust/src/tools/rust-analyzer 这个文件夹中…

【数据结构】一题带你出师链表!

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 题目链接 138. 随机链表的复制https://leetcode.cn/problems/copy-list-with-random-pointer/ 题目描述 给你一个长度为 n 的链表&#xff0c;每个节点包含一个额外增加的随机…

(保姆级教程)Mysql中索引、触发器、存储过程、存储函数的概念、作用,以及如何使用索引、存储过程,代码操作演示

讲解 MySQL 中索引、触发器、存储过程、存储函数的使用 文章目录 1. 索引1.1 索引的分类1.2 索引的设计原则1.3 如何使用&#xff08;create index&#xff09; 2. 触发器2.1 触发器的分类2.2 如何使用&#xff08;create trigger&#xff09; 3. 存储过程3.1 如何使用&#xf…

【尚跑】2023泾阳半程马拉松144 PB完赛

1、赛事背景 来到泾阳&#xff0c;就来到了中国大地原点&#xff1b; 来到泾阳&#xff0c;就来到了陕西的“白菜心心”&#xff1b; 来到泾阳&#xff0c;就来到了具有2000多年的历史长河&#xff1b; 泾河水缓缓流&#xff0c;流过郑国渠&#xff1b; 泾河水缓缓流&…

管理类联考——英语二——备考 100 句涵盖所有词汇

全中 在海里的这个地区&#xff0c;熊猫们喜欢就着苏打碗豆喝茶。而大洋州的民兵则喜欢经过半岛&#xff0c;带着编剧本的公式上餐厅去。附件的电影院里有额外的歌剧和香蕉&#xff0c;这一时代的斑马们被外面的天线所吸引。实验室里的蟹想用它的肋骨去戳四肢象灯炮的小羊。但…

经典滑动窗口试题(一)

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、将x减到0的最小操作数1、题目讲解2、讲解算法原理3、代码实现 二、无重复的最长子串1、题…

String 、StringBuffer 和 StringBuilder 的区别?

String 使用 String 声明一个字符串的时候&#xff0c;该字符串会存放在堆中的字符串常量池中。因为在java中所有的String 都是以常量表示&#xff0c;且由 final 修饰&#xff0c;因此在线程池中它的线程是安全的 且 不可变的 。每个 String 在被创建后就不再发生任何变化。 …

【考研】数据结构(更新到循环链表)

声明&#xff1a;所有代码都可以运行&#xff0c;可以直接粘贴运行&#xff08;只有库函数没有声明&#xff09; 线性表的定义和基本操作 基本操作 定义 静态&#xff1a; #include<stdio.h> #include<stdlib.h>#define MaxSize 10//静态 typedef struct{int d…

Modbus RTU协议及modbus库函数使用

一、与Modbus TCP的区别 在一般工业场景使用modbus RTU的场景还是更多一些&#xff0c;modbus RTU基于串行协议进行收发数据&#xff0c;包括RS232/485等工业总线协议。 与modbus TCP不同的是RTU没有报文头MBAP字段&#xff0c;但是在尾部增加了两个CRC检验字节&#xff08;CRC…

关键字const的修饰(指针)

A.const修饰变量 变量是可以修改的&#xff0c;如果把变量的地址交给⼀个指针变量&#xff0c;通过指针变量的也可以修改这个变量。 但是如果我们希望⼀个变量加上⼀些限制&#xff0c;不能被修改&#xff0c;怎么做呢&#xff1f;这就是const的作⽤。 #include <stdio.h&…

Public Key Retrieval is not allowed客户端连接

使用DBeavear或navicat连接mysql服务器时&#xff0c;报错Public Key Retrieval is not allowed 原因&#xff1a; 客户端默认禁用 SSL/TLS 协议&#xff0c;客户端会使用服务器的公钥进行传输&#xff0c;默认情况下客户端不会主动去找服务器拿公钥&#xff0c;进而会出现…
最新文章