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
- 定义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
- 定义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("网络请求失败")}
}
- 实现登录
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全网最详细教程
一.路由懒加载 关键点: lazy懒加载 Suspense组件(添加加载提示) utils文件夹 –LazyLoad.js //lazy懒加载 Suspense 组件(添加加载提示) import {lazy,Suspense} from react export default function LazyLoad(url)…...
华为OD机试 - 匿名信(Python)| 真题+思路+考点+代码+岗位
匿名信 题目 电视剧《分界线》里面有一个片段,男主为了向警察透露案件细节,且不暴露自己,于是将报刊上的字减下来,剪拼成匿名信。 现在又一名举报人,希望借鉴这种手段,使用英文报刊完成举报操作。 但为了增加文章的混淆度,只需满足每个单词中字母数量一致即可,不关注…...
【Python】编写代码实现指定下标值顺序进行正序和倒序排序算法编程
🎉🎉 在本次python文章中,主要通过定义一个排序方法,实现一组数列能够按照另一组数列指定的位置进行重新排序输出,默认正序排序,可通过True表示逆序输出 目录1、知识点2、数列和元组1)错误遍历方…...
Sitara™处理器的产品开发路线图
Sitara™处理器的产品开发路线图概述Evaluation Phase(评估阶段)Board Development Phase(硬件发展阶段,硬件设计人员应重点关注这个阶段)Software Development Phase(软件发展阶段)Product Phase/SW Lifecycle概述 一般情况下,会存在四个主要的发展阶段…...
岗位来啦-华为研发OD招聘
研发OD招聘 ★★关于我们★★ 万物互联时代已到来,无线通信技术正在重塑世界。作为行业领导者,华为无线致力于通过移动创新消除数字鸿沟,构建万物互联的智能世界。基于5G的技术,家庭无线宽带接入、车联网、云AR/VR、eMBB高清视频…...
【LeetCode】剑指 Offer 06. 从尾到头打印链表 p58 -- Java Version
题目链接: https://leetcode.cn/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof/ 1. 题目介绍(06. 从尾到头打印链表) 输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。 【测试用例…...
童年回忆--扫雷(包括标记功能和递归展开)--万字讲解让你学会扫雷制作
魔王的介绍:😶🌫️一名双非本科大一小白。魔王的目标:🤯努力赶上周围卷王的脚步。魔王的主页:🔥🔥🔥大魔王.🔥🔥🔥 ❤️…...
【重器】GPS北斗卫星时钟基准与卫星授时服务技术原理
【重器】GPS北斗卫星时钟基准与卫星授时服务技术原理 【重器】GPS北斗卫星时钟基准与卫星授时服务技术原理 1.前言 由计算机网络系统组成的分布式系统,若想协调一致进行:IT行业的“整点开拍”、“秒杀”、“Leader选举”,通信行业的“同步组网…...
软件测试未来发展趋势怎么样
未来,互联网技术是很多企业能够活下去的关键点。互联网技术成为新的基建,互联网“基建”化就决定了软件测试行业的缺口会一直扩大。 并且,软件测试岗位,已不仅局限于互联网企业,现已逐步深入到实体产业,金…...
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 由以下部分组成,用于向后端…...
Leetcode力扣秋招刷题路-0068
从0开始的秋招刷题路,记录下所刷每道题的题解,帮助自己回顾总结 68. 文本左右对齐 给定一个单词数组 words 和一个长度 maxWidth ,重新排版单词,使其成为每行恰好有 maxWidth 个字符,且左右两端对齐的文本。 你应该…...
Nginx介绍及安装(windows版,Linux版)
目录 一、Nginx介绍 1、Nginx优势 2、Nginx作用 3、部署静态资源 4、代理 5、负载均衡 二、Nginx安装步骤(windows版) 三、Nginx安装步骤(Linux版) 1、官网下载安装包,下载完之后上传到Linux系统上 2、在Lin…...
Camera | 4.瑞芯微平台MIPI摄像头应用程序编写
前面3篇我们讲解了camera的基础概念,MIPI协议,CSI2,常用命令等,本文带领大家入门,如何用c语言编写应用程序来操作摄像头。 Linux下摄像头驱动都是基于v4l2架构,要基于该架构编写摄像头的应用程序ÿ…...
【1250. 检查「好数组」】
来源:力扣(LeetCode) 描述: 给你一个正整数数组 nums,你需要从中任选一些子集,然后将子集中每一个数乘以一个 任意整数,并求出他们的和。 假如该和结果为 1,那么原数组就是一个「…...
Spring 如何解决循环依赖?
什么是循环依赖 ? 一个或多个对象之间存在直接或间接的依赖关系,这种依赖关系构成一个环形调用,有下面 3 种方式。 我们看一个简单的 Demo,对标“情况 2”。 Service public class Louzai1 {Autowiredprivate Louzai2 louzai2;…...
CocoaPods使用指南
前言 对于大多数软件开发团队来说,依赖管理工具必不可少,它能针对开源和私有依赖进行安装与管理,从而提升开发效率,降低维护成本。针对不同的语言与平台,其依赖管理工具也各有不同,例如 npm 管理 Javascri…...
Kafka 消息队列
目录主流的消息队列消息队列的应用场景缓存/肖锋解耦异步处理KafkaKafka的定义Kafka的底层基础架构Kafka分区如何保证Leader选举Kafka分区如何保证Leader和Follower数据的一致性Kafka 中消费者的消费方式Kafka 高效读写数据的原因(高性能吞吐的原因)&…...
华为OD机试 - 挑选字符串(Python)| 真题+思路+考点+代码+岗位
挑选字符串 题目 给定a-z,26 个英文字母小写字符串组成的字符串A和B, 其中A可能存在重复字母,B不会存在重复字母, 现从字符串A中按规则挑选一些字母可以组成字符串B 挑选规则如下: 同一个位置的字母只能挑选一次, 被挑选字母的相对先后顺序不能被改变, 求最多可以同时…...
对比Hashtable、HashMap、TreeMap有什么不同?
第9讲 | 对比Hashtable、HashMap、TreeMap有什么不同? Map 是广义 Java 集合框架中的另外一部分,HashMap 作为框架中使用频率最高的类型之一,它本身以及相关类型自然也是面试考察的热点。 今天我要问你的问题是,对比 Hashtable、…...
测试新版Android Studio的手机镜像效果
学更好的别人, 做更好的自己。 ——《微卡智享》 本文长度为669字,预计阅读2分钟 前言 春节刚上班,就开始了疯狂出差的节奏,期间发现Android Studio发布新的版本2022.1.1(Electric Eel),里面两个更新的内容蓝牙模拟器和…...
使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...
Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
服务器--宝塔命令
一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行! sudo su - 1. CentOS 系统: yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...
安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...
WPF八大法则:告别模态窗口卡顿
⚙️ 核心问题:阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程,导致后续逻辑无法执行: var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题:…...
