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),里面两个更新的内容蓝牙模拟器和…...
第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...
C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...
