当前位置: 首页 > 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;里面两个更新的内容蓝牙模拟器和…...

信息安全工程师-病毒、木马、蠕虫技术原理与防御基础

一、引言 核心概念定义 恶意代码是指故意编制或设置的、对信息系统或网络产生危害的程序代码&#xff0c;计算机病毒、特洛伊木马、网络蠕虫是网络安全领域占比超过 80% 的核心恶意代码类型&#xff0c;也是软考信息安全工程师考试中恶意代码模块的核心考察内容。软考考点重要…...

基于LLM与向量数据库构建个人知识管理智能代理:从原理到实践

1. 项目概述&#xff1a;一个面向个人知识管理的智能代理 最近在折腾个人知识管理&#xff08;PKM&#xff09;系统&#xff0c;发现了一个挺有意思的开源项目&#xff1a; lessthanno/engram-agent 。简单来说&#xff0c;这是一个“记忆代理”&#xff0c;它旨在成为你数字…...

企业级AI应用开发,利用Taotoken实现API访问控制与审计日志

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 企业级AI应用开发&#xff0c;利用Taotoken实现API访问控制与审计日志 在将大模型能力集成到企业应用的过程中&#xff0c;开发团队…...

AI平台竞争中的合谋与网络效应:市场博弈的底层逻辑分析

1. 项目概述&#xff1a;当AI平台开始“默契”时&#xff0c;市场会发生什么&#xff1f; 最近和几位做投资和产品战略的朋友聊天&#xff0c;话题总绕不开一个现象&#xff1a;几个头部的AI大模型平台&#xff0c;无论是定价策略、功能迭代节奏&#xff0c;还是对开发者的扶持…...

主动学习加速广义Benders分解求解混合整数经济模型预测控制

1. 项目概述与核心价值最近在做一个挺有意思的项目&#xff0c;核心是把一个听起来很“学术”的算法——广义Benders分解&#xff0c;和工业界里越来越火的经济模型预测控制给揉到了一起&#xff0c;并且用主动学习这个思路去优化整个求解过程。乍一听&#xff0c;这标题里又是…...

3步解锁SD-WebUI-Inpaint-Anything插件:自定义修复模型完全指南

3步解锁SD-WebUI-Inpaint-Anything插件&#xff1a;自定义修复模型完全指南 【免费下载链接】sd-webui-inpaint-anything Inpaint Anything extension performs stable diffusion inpainting on a browser UI using masks from Segment Anything. 项目地址: https://gitcode.…...

美团闪购mtgsig

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包 内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01;侵权通过头像私信或名字简介叫我删除博…...

Claude API用量监控桌面小组件开发实战:Python+SwiftBar实现成本可视化

1. 项目概述&#xff1a;一个提升Claude使用效率的桌面小工具 最近在折腾AI工具链的时候&#xff0c;发现了一个挺有意思的开源项目&#xff0c;叫 claude-usage-widget 。这名字听起来就挺直白的&#xff0c;一个用来监控Claude使用情况的桌面小工具。对于像我这样重度依赖C…...

AI眼底疾病诊断:从图像处理到深度学习的技术融合与实践

1. 项目概述&#xff1a;当AI遇见眼底&#xff0c;一场关于“看见”的革命作为一名在医疗影像和计算机视觉交叉领域摸爬滚打了十多年的从业者&#xff0c;我亲眼见证了技术如何一步步改变诊断的范式。今天想和大家深入聊聊的&#xff0c;是“AI在视网膜疾病诊断中的应用”这个既…...

AI赋能建筑电气工程:从图纸审查到智慧运维的实战指南

1. 项目概述&#xff1a;当AI遇见建筑电气与电子工程如果你在建筑行业&#xff0c;特别是电气与电子工程领域摸爬滚打过几年&#xff0c;一定会对几个场景深有感触&#xff1a;图纸改了又改&#xff0c;现场管线打架&#xff0c;设备清单对不上&#xff0c;调试阶段问题百出&am…...