当前位置: 首页 > news >正文

redux全网最详细教程

一.路由懒加载

关键点:
lazy懒加载
Suspense组件(添加加载提示)

utils文件夹
–LazyLoad.js

//lazy懒加载 Suspense 组件(添加加载提示)
import {lazy,Suspense} from 'react'
export default function LazyLoad(url){//导入组件const Elem=lazy(()=>import('../pages'+url))//Suspense 提供一个加载提示return <Suspense fallback={<h2>loading...</h2>}><Elem></Elem></Suspense>
}

router文件夹–
baseRoutes.js
导入lazyLoad
import LazyLoad from "../utils/LazyLoad";

import Home from "../pages/Home";
import About from "../pages/About";
import Produce from "../pages/Produce";
// import OrderList from "../pages/admin/OrderList";
import Admin from "../pages/admin/Admin";
// import Dash from "../pages/admin/Dash"
import LazyLoad from "../utils/LazyLoad";
// 基本路由配置
const baseRoutes = [{path: "",element: <Home></Home>,},{path: "/about",element: <About></About>,},{path: "/produce/:id",element: <Produce></Produce>,},{path:"/admin/*",element:<Admin></Admin>,children:[{path:'',element:LazyLoad('/admin/Dash.js')},{path:'dash',element:LazyLoad('/admin/Dash.js')},{path:'orderlist',element:LazyLoad('/admin/OrderList.js')},]}];export default baseRoutes

index.js

import { useEffect, useState } from "react";
// useRoutes 根据路由配置 创建路由
import { useRoutes } from "react-router-dom";
import baseRoutes from "./baseRoutes";
function RouterView() { // 常见路由const element = useRoutes(baseRoutes);return <>{element}</>;
}
export default RouterView;

lazy Suspense
此时我们发现第一次点击的时候会出现路由懒加载,第二次就不再请求数据

react实现登录

npm i axios

  1. 定义request.js
    utils —request.js
import axios from 'axios'
const request=axios.create({baseURL:"http://dida100.com:8888",timeout:5000})
request.interceptors.request.use(config=>{if(sessionStorage.getItem("token")){config.headers["Authorization"]="Bearer "+sessionStorage.setItem("token")}return config
})
export default request
  1. 定义api
    新建server文件夹
    user.js async 和 await 结合 数据请求完才往下走
import request from '../utils/request'
export async function loginServer(data){//async 和 await 结合const result=await request.post("/api/login",data)//状态码为200 成功if(result.status===200){return result.data}else{//请求失败//throw抛出 新的错误throw new Error("网络请求失败")}
}
  1. 实现登录
    Home.js
    (没有载荷是由于接口里面没写data) 这里面input实现双向绑定是通过onChange事件 onChange={e=>setUser({...user,password:e.target.value})}这里的...是扩展,就是面的name与password,用新的值去替换前面的password
import {loginServer} from '../server/user'
import {useState} from 'react'
import {useNavigate,useLocation} from 'react-router-dom'
import {parse} from '../utils'
function Home() {const [user,setUser]=useState({name:"",password:""})const navigate=useNavigate()const location=useLocation()var search=parse(location.search)function login(){loginServer(user).then(res=>{if(res.code===200){sessionStorage.setItem("token",res.token)sessionStorage.setItem("user",JSON.stringify(res.user))var redirect=search.redirect||'admin'navigate(redirect)}})}return ( <div>用户名:<input value={user.name} onChange={e=>setUser({...user,name:e.target.value})}/><br />密码:<input value={user.password} onChange={e=>setUser({...user,password:e.target.value})}/><br /><button onClick={login}>登录</button></div> );
}export default Home;

权限管理

通过新建一个组件实现的 pages页面新建一个private.js 如果有token就跳转到private的子组件props.children,如果没有就返回首页

import {Navigate,useLocation} from 'react-router-dom'
function Private(props) {const location=useLocation()console.log(location);if(sessionStorage.getItem("token")){return <>{props.children}</>}else{return <Navigate to={{pathname:'/',search:"?redirect="+location.pathname}} />;}}export default Private;

在路由基础配置中的element中,用<Private><Admin></Admin></Private进行包裹子组件Admin

import Private from "../pages/Private";
const baseRoutes = [
path:"/admin/*",
element:<Private><Admin></Admin></Private>,]

Home.js

import {useNavigate,useLocation} from 'react-router-dom'import {parse} from '../utils'const location=useLocation()
//把location的search转换为对象var search=parse(location.search)
如果search对象有redirext属性就用redirect,没有返回admin
var redirect=search.redirect||'admin'
utils里面 index.js
// 把?name=mumu&age=18
// 转换为{name:"mumu",age:18}
export function parse(url) {var temp = url.slice(1).split("&");var search = {};for (var i = 0; i < temp.length; i++) {var item = temp[i].split("=");search[item[0]] = item[1];}return search;}

redux(老版本)

单向数据流

组成
state状态数据
reducer处理状态的方法
store仓库
actions调用reducer的方法

安装
npm i redux react-redux redux-thunk redux-logger @reduxjs/toolkit -S
redux全局状态管理
react-redux 连接组件与redux
redux-thunk 处理异步actions
redux-logger 日志
redux-persist 本地存储

新建store
—index.js整个仓库

//整个仓库
// createStore 创建仓库,applyMiddleware处理中间件(日志,异步,本地存储)
// combineReducers合并多个处理counterReducer,userReducer,productionReducer
import {createStore,applyMiddleware,combineReducers} from 'redux'
//导入处理计数器
import counterReducer from './counterReducer'
//导入异步处理
import thunk from 'redux-thunk'
//导入日志
import logger from 'redux-logger'
//创建仓库
const store=createStore(combineReducers({counter:counterReducer}),applyMiddleware(thunk,logger)
)
//导出仓库
export default store

store有三个核心方法:
dispatch发起动作 触发reducer 返回新的state
subscribe 监听store中state的变化 执行回调函数
getState 获取stoTe中的数据

counterReducer.js 处理counter数据

import {INCREMENT} from './types'
//处理counter数据 定义初始化state
const initialState={num:1
}
//定义一个处理器function counterReducer(state=initialState,action){//根据动作的类型switch(action.type){case INCREMENT://如果是加,返回原来的数据state,把num值加1return {...state,num:state.num+1}default:return state}
}
export default counterReducer

counterAction.js调用CounterReducer动作
type后面跟的是常量,需要两个页面一致,所以我们
store --type.js 存放reducer动作类型
export const INCREMENT=“INCREMENT”
在其他页面导入,引号就可以去掉了,不容易出错,很规范
import {INCREMENT} from './types'

store有三个核心方法(原生):
dispatch发起动作 触发reducer 返回新的state
subscribe 监听store中state的变化 执行回调函数

getState 获取store中的数据

第一种方法

About.js
原生的三个都得写
这三个方法哪来的?
我们在index.js创建仓库的时候就带了这三个方法,通过createStore方法获取的
counter怎么来的?
const store=createStore( combineReducers({counter:counterReducer}), applyMiddleware(thunk,logger) )

dispatch(itype: “INCREMENT”})中的参数就是counterReducer的action根据type的值

//导入仓库 getState获取state 
//dispatch发送事件执行 reducer改变state subscribe监听state数据的变化
import store from '../store/index.js'
//导入动作
import {add} from '../store/counterAction'
import {useEffect,useState} from 'react'
function About() {             //创建value的状态 响应式更新store中的num 初始赋值const [value,setValue]=useState(store.getState().counter.num)useEffect(()=>{//监听store变化用store的num更新组件的valuestore.subscribe(()=>{setValue(store.getState().counter.num)})},[])return ( <div>about<p>value-store里面的num:{value}</p><button onClick={()=>store.dispatch(add())}>+</button></div>);
}export default About;

第二种方式 react-redux use方法

index.js
导入数据提供器Provider
import {Provider} from 'react-redux'
包装
<Provider store={store}> <App /> </Provider>
使用

const num=useSelector(state=>state.counter.num)const dispatch=useDispatch()
onClick={()=>dispatch({type:"INCREMENT"})}
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';//导入store
import store from './store'
//导入数据提供器
import {Provider} from 'react-redux'const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(// 渲染多次 去掉严格模式// <React.StrictMode><Provider store={store}><App /></Provider>// </React.StrictMode>
);

OrderList使用选择器useSelector
<button onClick={()=>dispatch({type:"INCREMENT"})}>{num}</button> <button onClick={()=>dispatch(add())}>{num}</button>
这俩方式都可以实现

//使用选择器
import {useSelector,useDispatch} from 'react-redux'
//导入动作
import {add} from '../../store/counterAction'
function OrderList() {//选择到state中的counter的numconst num=useSelector(state=>state.counter.num)//创建一个触发器const dispatch=useDispatch()return (  <div>orderlist<p>{/* 单击发送动作给reducer 处理返回新的state数据 */}<button onClick={()=>dispatch({type:"INCREMENT"})}>{num}</button><button onClick={()=>dispatch(add())}>{num}</button></p></div>);
}export default OrderList;

他们之前是同步的,其他页面也会改变

第三种方式

produce.js

import {useParams} from 'react-router-dom'
//导入连接器 把state和actions方法转换props
import {connect} from 'react-redux'
//导入counterAction 里面的所有动作方法
import * as actions from '../store/counterAction'
console.log(actions);
function Produce(props) {//获取产品参数const params=useParams()return ( <div>产品页面-{params.id}{/* <p onClick={()=>props.add()}>{props.counter.num}</p> */}<p onClick={()=>props.add()}>{props.num}</p></div>);
}
//props.counter.num从connect第一个参数 状态
//props.add 从connect的第二个参数  方法
// export default Produce;
export default connect(state=>({num:state.counter.num}),{add:actions.add})(Produce)

相关文章:

redux全网最详细教程

一.路由懒加载 关键点&#xff1a; lazy懒加载 Suspense组件&#xff08;添加加载提示&#xff09; utils文件夹 –LazyLoad.js //lazy懒加载 Suspense 组件&#xff08;添加加载提示&#xff09; import {lazy,Suspense} from react export default function LazyLoad(url)…...

华为OD机试 - 匿名信(Python)| 真题+思路+考点+代码+岗位

匿名信 题目 电视剧《分界线》里面有一个片段,男主为了向警察透露案件细节,且不暴露自己,于是将报刊上的字减下来,剪拼成匿名信。 现在又一名举报人,希望借鉴这种手段,使用英文报刊完成举报操作。 但为了增加文章的混淆度,只需满足每个单词中字母数量一致即可,不关注…...

【Python】编写代码实现指定下标值顺序进行正序和倒序排序算法编程

&#x1f389;&#x1f389; 在本次python文章中&#xff0c;主要通过定义一个排序方法&#xff0c;实现一组数列能够按照另一组数列指定的位置进行重新排序输出&#xff0c;默认正序排序&#xff0c;可通过True表示逆序输出 目录1、知识点2、数列和元组1&#xff09;错误遍历方…...

Sitara™处理器的产品开发路线图

Sitara™处理器的产品开发路线图概述Evaluation Phase(评估阶段)Board Development Phase(硬件发展阶段&#xff0c;硬件设计人员应重点关注这个阶段)Software Development Phase(软件发展阶段)Product Phase/SW Lifecycle概述 一般情况下&#xff0c;会存在四个主要的发展阶段…...

岗位来啦-华为研发OD招聘

研发OD招聘 ★★关于我们★★ 万物互联时代已到来&#xff0c;无线通信技术正在重塑世界。作为行业领导者&#xff0c;华为无线致力于通过移动创新消除数字鸿沟&#xff0c;构建万物互联的智能世界。基于5G的技术&#xff0c;家庭无线宽带接入、车联网、云AR/VR、eMBB高清视频…...

【LeetCode】剑指 Offer 06. 从尾到头打印链表 p58 -- Java Version

题目链接&#xff1a; https://leetcode.cn/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof/ 1. 题目介绍&#xff08;06. 从尾到头打印链表&#xff09; 输入一个链表的头节点&#xff0c;从尾到头反过来返回每个节点的值&#xff08;用数组返回&#xff09;。 【测试用例…...

童年回忆--扫雷(包括标记功能和递归展开)--万字讲解让你学会扫雷制作

魔王的介绍&#xff1a;&#x1f636;‍&#x1f32b;️一名双非本科大一小白。魔王的目标&#xff1a;&#x1f92f;努力赶上周围卷王的脚步。魔王的主页&#xff1a;&#x1f525;&#x1f525;&#x1f525;大魔王.&#x1f525;&#x1f525;&#x1f525; ❤️‍&#x1…...

【重器】GPS北斗卫星时钟基准与卫星授时服务技术原理

【重器】GPS北斗卫星时钟基准与卫星授时服务技术原理 【重器】GPS北斗卫星时钟基准与卫星授时服务技术原理 1.前言 由计算机网络系统组成的分布式系统&#xff0c;若想协调一致进行&#xff1a;IT行业的“整点开拍”、“秒杀”、“Leader选举”&#xff0c;通信行业的“同步组网…...

软件测试未来发展趋势怎么样

未来&#xff0c;互联网技术是很多企业能够活下去的关键点。互联网技术成为新的基建&#xff0c;互联网“基建”化就决定了软件测试行业的缺口会一直扩大。 并且&#xff0c;软件测试岗位&#xff0c;已不仅局限于互联网企业&#xff0c;现已逐步深入到实体产业&#xff0c;金…...

aws Distro for OpenTelemetry 可观测性workshop记录

参考资料 https://aws-otel.github.io/docs/introductionhttps://aws-otel.github.io/docs/introduction aws distro for opentelemetry 官方提供了不同语言不同使用场景下完善的使用实例和相关配置。 AWS Distro for OpenTelemetrics 由以下部分组成&#xff0c;用于向后端…...

Leetcode力扣秋招刷题路-0068

从0开始的秋招刷题路&#xff0c;记录下所刷每道题的题解&#xff0c;帮助自己回顾总结 68. 文本左右对齐 给定一个单词数组 words 和一个长度 maxWidth &#xff0c;重新排版单词&#xff0c;使其成为每行恰好有 maxWidth 个字符&#xff0c;且左右两端对齐的文本。 你应该…...

Nginx介绍及安装(windows版,Linux版)

目录 一、Nginx介绍 1、Nginx优势 2、Nginx作用 3、部署静态资源 4、代理 5、负载均衡 二、Nginx安装步骤&#xff08;windows版&#xff09; 三、Nginx安装步骤&#xff08;Linux版&#xff09; 1、官网下载安装包&#xff0c;下载完之后上传到Linux系统上 2、在Lin…...

Camera | 4.瑞芯微平台MIPI摄像头应用程序编写

前面3篇我们讲解了camera的基础概念&#xff0c;MIPI协议&#xff0c;CSI2&#xff0c;常用命令等&#xff0c;本文带领大家入门&#xff0c;如何用c语言编写应用程序来操作摄像头。 Linux下摄像头驱动都是基于v4l2架构&#xff0c;要基于该架构编写摄像头的应用程序&#xff…...

【1250. 检查「好数组」】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 给你一个正整数数组 nums&#xff0c;你需要从中任选一些子集&#xff0c;然后将子集中每一个数乘以一个 任意整数&#xff0c;并求出他们的和。 假如该和结果为 1&#xff0c;那么原数组就是一个「…...

Spring 如何解决循环依赖?

什么是循环依赖 &#xff1f; 一个或多个对象之间存在直接或间接的依赖关系&#xff0c;这种依赖关系构成一个环形调用&#xff0c;有下面 3 种方式。 我们看一个简单的 Demo&#xff0c;对标“情况 2”。 Service public class Louzai1 {Autowiredprivate Louzai2 louzai2;…...

CocoaPods使用指南

前言 对于大多数软件开发团队来说&#xff0c;依赖管理工具必不可少&#xff0c;它能针对开源和私有依赖进行安装与管理&#xff0c;从而提升开发效率&#xff0c;降低维护成本。针对不同的语言与平台&#xff0c;其依赖管理工具也各有不同&#xff0c;例如 npm 管理 Javascri…...

Kafka 消息队列

目录主流的消息队列消息队列的应用场景缓存/肖锋解耦异步处理KafkaKafka的定义Kafka的底层基础架构Kafka分区如何保证Leader选举Kafka分区如何保证Leader和Follower数据的一致性Kafka 中消费者的消费方式Kafka 高效读写数据的原因&#xff08;高性能吞吐的原因&#xff09;&…...

华为OD机试 - 挑选字符串(Python)| 真题+思路+考点+代码+岗位

挑选字符串 题目 给定a-z,26 个英文字母小写字符串组成的字符串A和B, 其中A可能存在重复字母,B不会存在重复字母, 现从字符串A中按规则挑选一些字母可以组成字符串B 挑选规则如下: 同一个位置的字母只能挑选一次, 被挑选字母的相对先后顺序不能被改变, 求最多可以同时…...

对比Hashtable、HashMap、TreeMap有什么不同?

第9讲 | 对比Hashtable、HashMap、TreeMap有什么不同&#xff1f; Map 是广义 Java 集合框架中的另外一部分&#xff0c;HashMap 作为框架中使用频率最高的类型之一&#xff0c;它本身以及相关类型自然也是面试考察的热点。 今天我要问你的问题是&#xff0c;对比 Hashtable、…...

测试新版Android Studio的手机镜像效果

学更好的别人&#xff0c; 做更好的自己。 ——《微卡智享》 本文长度为669字&#xff0c;预计阅读2分钟 前言 春节刚上班&#xff0c;就开始了疯狂出差的节奏&#xff0c;期间发现Android Studio发布新的版本2022.1.1(Electric Eel)&#xff0c;里面两个更新的内容蓝牙模拟器和…...

ComfyUI实战:如何加载基于Flux.1微调的LoRA模型并优化推理流程

最近在项目里用 ComfyUI 部署基于 Flux.1 微调的 LoRA 模型&#xff0c;踩了不少坑。从模型加载失败到推理时显存爆炸&#xff0c;问题层出不穷。经过一番折腾&#xff0c;总算梳理出一套比较稳定的流程&#xff0c;这里把实战经验记录下来&#xff0c;希望能帮到有同样需求的同…...

如何高效优化多语言模型:专业部署的完整策略

如何高效优化多语言模型&#xff1a;专业部署的完整策略 【免费下载链接】paraphrase-multilingual-MiniLM-L12-v2 项目地址: https://ai.gitcode.com/hf_mirrors/ai-gitcode/paraphrase-multilingual-MiniLM-L12-v2 你是否在部署多语言文本嵌入模型时遭遇过"显存…...

破局B站音频提取难题:BilibiliDown革新性解决方案全解析

破局B站音频提取难题&#xff1a;BilibiliDown革新性解决方案全解析 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader &#x1f633; 项目地址: https://gitcode.com/gh_mirrors…...

南京四季旅游攻略:最美时节去最美地方

南京四季旅游攻略&#xff1a;最美时节去最美地方 &#x1f338;&#x1f343;&#x1f342;❄️本文作者&#xff1a;南京码农 发布日期&#xff1a;2026年3月26日 关键词&#xff1a;南京旅游、四季景点、旅游攻略、南京必去、季节推荐前言&#xff1a;南京&#xff0c;一座四…...

生成式AI欺诈来袭,什么样的IP数据接口才能筑起防线?

某电商平台的风控系统发出预警&#xff1a;一个“新用户”正在批量下单高价商品&#xff0c;收货地址遍布全国&#xff0c;支付方式各不相同。但奇怪的是&#xff0c;这些订单的浏览行为、停留时间、点击轨迹几乎完全一致——这不是真人&#xff0c;而是生成式AI模拟的虚假用户…...

告别混乱:我是如何用Hugo + GitHub Actions实现博客自动化构建与发布的

告别混乱&#xff1a;我是如何用Hugo GitHub Actions实现博客自动化构建与发布的 去年我的博客还处于"石器时代"——每次写完文章都要手动执行hugo build&#xff0c;再把public文件夹里的文件拖到服务器。直到某天连续三次忘记更新CNAME文件导致域名解析失败&#…...

HPE DL380 Gen10安装RedHat 7.9全流程:从VROC驱动配置到系统引导避坑指南

HPE DL380 Gen10企业级部署实战&#xff1a;RedHat 7.9与VROC驱动深度适配指南 在企业级IT基础设施中&#xff0c;HPE ProLiant DL380 Gen10服务器以其卓越的可靠性和扩展性成为关键业务负载的首选平台。当这类高性能硬件遇上RedHat Enterprise Linux 7.9这一经典企业级操作系统…...

从收音机到Wi-Fi:手把手复现经典小信号调谐放大器实验(附Multisim仿真文件)

从矿石收音机到5G射频前端&#xff1a;调谐放大器技术演进与Multisim仿真实践 上世纪二十年代&#xff0c;当业余无线电爱好者们用矿石和线圈组装出最简单的接收装置时&#xff0c;他们可能不会想到&#xff0c;这种基于LC谐振原理的选频技术会延续百年&#xff0c;成为现代无线…...

RWKV7-1.5B-g1a镜像优势解析:离线加载兼容+软链修复+日志分级排查设计

RWKV7-1.5B-g1a镜像优势解析&#xff1a;离线加载兼容软链修复日志分级排查设计 1. 平台简介与核心能力 rwkv7-1.5B-g1a是基于新一代RWKV-7架构的多语言文本生成模型&#xff0c;专为轻量级应用场景优化设计。该镜像经过工程化改造&#xff0c;在保持原模型优秀生成能力的同时…...

AD7606模数转换器的FPGA驱动设计与实现(串行/并行双模式解析)

1. AD7606模数转换器核心特性解析 AD7606这颗16位模数转换芯片在工业现场堪称"数据捕手"&#xff0c;我经手过的电力监控、振动分析项目中都能看到它的身影。与普通ADC不同&#xff0c;它最吸引工程师的特性是双模数据输出——就像高速公路的ETC和人工通道可以并行运…...