后端程序员入门react笔记(九)- react 插件使用

setState

  • setState引起的react的状态是异步的。操作完毕setState之后如果直接取值,可能取不到最新的值,我们举个例子console.log(this.state.num)打印的值,总是上一次的值而不是最新的。
import React, {Component} from 'react';  
class App extends Component {  
state = {  
num: 0  
}  
Add = () => {  
this.setState({  
num: this.state.num + 1  
})  
console.log(this.state.num);  
}  
render() {  
return (  
<div>  
<li>num:{this.state.num}</li>  
<button onClick={this.Add}>+ 1</button>  
</div>  
);  
}  
}  
export default App;

那么我怎么得到最新的值呢,其实在setstate接收第二个参数,是一个回调函数,我们可以这样写

Add = () => {this.setState({num: this.state.num + 1},()=>console.log(this.state.num))}
  • 在上面例子中,setstate 接收到的第一个参数是一个对象,其实也可以是一个stateChange对象的函数,这个对象函数呢,我们可以读取到state和props。我们来看一下
Add = () =>{  
this.setState(  
(state,props)=>{  
console.log(this.state);  
console.log(props);  
return {  
num: state.num+1  
}  
},  
() => {  
console.log(this.state);  
}  
)  
}

路由组件的懒加载

我们知道,一个路由对应一个组件,但是如果在一个页面里面有100个路由,难道我页面渲染的时候要渲染100个组件吗?这明显是不合理的,我们需要的是用到哪个组件,显示哪个组件,比如我们来看下面这段代码

import React, {Component,Suspense, lazy} from 'react';  
import {Link,Routes,Route} from "react-router-dom";  
//如果这样写,组件会在第一次请求的时候就全部加载出来  
// import A from "./components/a";  
import Load from "./components/load";  //这样写,组件只有需要用到的时候才加载一次  
const A=lazy(()=> {  
return import("./components/a")  
});  
const B=lazy(()=>{  
return import("./components/b")  
});  class App extends Component {  
render() {  
return (  
<div>  
<ul>  
<li><Link to="/a">我是a</Link></li>  
<li><Link to="/b">我是b</Link></li>  
</ul>  
<div>  {/*Suspense标签包裹路由组件,当路由组件调用超时,则展示Suspense的fallback组件*/}  
<Suspense fallback={<Load />}>  
<Routes>  
<Route path="/a" element={<A />} />  
<Route path="/b" element={<B />} />  
</Routes>  
</Suspense>  
</div>  
</div>  
);  
}  
}  
export default App;

hooks

之前我说过,在function里面,是没有this的,那这也意味着我们用不了this.state this.props,this.ref,但是在react16.8以后,hooks函数的出现实现了在函数内使用这些功能,那么没有this我们怎么操作呢,没有this,但是我们有react啊,react提供api给函数用就可以了

React.useState(state-hooks)

看名字就知道了,这个hooks我们可以用来操作state,我们举个例子

import React from 'react';
function App(){//定义count初始值const initCountValue=0//使用useState定义state和function,这个function不能直接调用,而是要在函数内部调用const [count,setCount]=React.useState(initCountValue)const [age,setAge]=React.useState(initCountValue)//定义一个函数调用setCountfunction add(){//写法一 接收一个状态值setCount(count+1)}function addAge(){//写法二 接收原状态的值,返回新状态的值setAge((age)=>age+1)}return (<div><li>count:{count}</li><button onClick={add}>+1</button><li>age:{age}</li><button onClick={addAge}>+1</button></div>)}
export default App;

React.useEffect(effect-hooks)

  • 我们知道,一个类是有生命周期函数的,那么在function中,我们怎么使用这些函数呢?
    React.useEffect就是监听函数声明周期的api,它接收三个参数,第一个参数就是收到监听后可以执行的动作,第二个参数相当于ComponentWillUnmount,第三个参数用来过滤监听哪些事件,默认监听所有,如果是空数组,默认是componentdidMount,如果是监听某个状态改变,我们就把哪个状态放到数组中即可
import React from 'react';
function App(){//定义count初始值const initCountValue=0//使用useState定义state和function,这个function不能直接调用,而是要在函数内部调用const [count,setCount]=React.useState(initCountValue)const [age,setAge]=React.useState(initCountValue)//定义一个函数调用setCountfunction add(){//写法一 接收一个状态值setCount(count+1)}function addAge(){//写法二 接收原状态的值,返回新状态的值setAge((age)=>age+1)}React.useEffect(()=>{const timer=setInterval(()=>{//定义动作   执行+1操作setCount(count+1)},1000);//卸载前执行操作return ()=>{clearInterval(timer)}//监听Age更新才执行 age 增加一次,count执行一次+1动作},[age])return (<div><li>count:{count}</li><button onClick={add}>+1</button><li>age:{age}</li><button onClick={addAge}>+1</button></div>)}
export default App;

React.useRef(ref-hooks)

我们知道,在类里面我们使用ref1 = React.createRef();这种方式来定义ref,那么在function中,我们怎么定义ref呢,我们看一下

import React from 'react';
function App(){//定义refconst ref1=React.createRef();function getRef(){//获取ref的值console.log(ref1.current.value);}return (<div><li><input type="text" ref={ref1}/></li><button onClick={getRef}>getRef</button></div>)
}
export default App;

Fragment

不知道大家有没有发现,当我们使用return的时候,必须返回一个标签,所有的jsx标签必须被一个标签包裹,像这种

    return (<div><li><input type="text" ref={ref1}/></li><button onClick={getRef}>getRef</button></div>)

那么我有一个想法,我如果想让我的jsx标签不被包裹,应该怎么办?我觉得最简单的方法就是把标签去掉,比如这样

    return (<><li><input type="text" ref={ref1}/></li><button onClick={getRef}>getRef</button></>)

但是空标签有一个问题,我们没办法给它赋值key,比如我们map遍历的时候,这个时候Fragment作用就出来了,它是一个可以被赋值key的空标签

import React, {Fragment} from 'react';
function App(){//定义refconst ref1=React.createRef();function getRef(){//获取ref的值console.log(ref1.current.value);}return (<Fragment key="1"><li><input type="text" ref={ref1}/></li><button onClick={getRef}>getRef</button></Fragment>)
}
export default App;

context

一般后端人员对context还是很熟悉的,一个上下文,贯穿整个请求,从进程,到各个子进程,都可能用到context的东西,那么前端,也提出了一个context的概念,用来实现组件和子组件的数据传递,我们举个例子

在组件中使用context

import React from 'react';
//定义全局的context对象
const MyContext=React.createContext();
//定义provider标签  类组件用
const Provider=MyContext.Provider;
//定义consumer标签 函数组件用
const Consumer=MyContext.Consumer;//这是一个父组件
class App extends React.Component {//定义状态state = {name: 'React'}render() {return (<div className="App"  style={{padding: '10px',border: '1px solid red'}}><h1>{this.state.name}</h1>{/*父组件想要把上下文传递给子组件,必须使用context的Provider标签包裹,并把相关的值传递过去*/}<Provider value={this.state}><span><B></B></span></Provider></div>);}
}class B extends React.Component {render() {return (<div className="App"  style={{padding: '10px',border: '1px solid red'}}><h1>我是B</h1><span ><C></C></span></div>)}
}class C extends React.Component {//谁想从全局context拿到 谁声明contexttypestatic contextType=MyContext;render() {return (<div className="App"  style={{padding: '10px',border: '1px solid red'}}><h1>我是C</h1>{/*这里取值渲染*/}<h1>App组件穿过来的值是{this.context.name}</h1><D></D></div>)}
}function D() {return (<div className="App"  style={{padding: '10px',border: '1px solid red'}}><h1>我是Func D</h1><Consumer>{value=>{return <h1>App组件穿过来的值是{value.name}</h1>}}</Consumer></div>);
}
export default App;

在这里插入图片描述

purgecomponent

我们之前使用redux的时候说过,redux只负责存储数据,如果我们想重新render,那么就得执行一个命令this.setstate={},相当于告诉react,说我更新了state,你需要重新render。其实呢,我们啥也没更新。既然我们啥都没更新,为什么还要执行render?我们能不能等到真正的state发生变化的时候再render?答案是可以,因为我们知道有一个生命周期函数,叫getSnapshotBeforeUpdate,我们可以通过对比state和props来判断返回true还是false,我们知道,既然getSnapshotBeforeUpdate是组件的生命周期函数,那么能不能让getSnapshotBeforeUpdate自动判断,而不是每次都是我手写判断呢?答案是可以,它是对component的优化,名字是React.PureComponent,我们来看看使用

import React from 'react';//这是一个父组件
class App extends React.PureComponent {//定义状态state = {name: 'React'}render() {// 初始化render之后,由于数据不在变化,也不在重新renderconsole.log('app.render');return (<div className="App"  style={{padding: '10px',border: '1px solid red'}}><h1>{this.state.name}</h1><button onClick={() => this.setState({name: 'vue'})}>更改状态名字</button><B></B></div>);}
}class B extends React.PureComponent {// 初始化render一次之后,由于后续没有数据变化,故不再renderrender() {console.log('b.render');return (<div ><h1>我是B</h1><span ></span></div>)}
}export default App;

children props

  • 一般我们写父子组件,可以通过嵌套来写
import React from 'react';
import "./App.css"
//这是一个父组件
class App extends React.PureComponent {//定义状态state = {name: 'React'}render() {return (<div className="component"><h1>我是App</h1>{/*标签包裹的内容通过props.children获取*/}<B x={100}>11211<C></C></B></div>)}
}
class B extends React.PureComponent {// 初始化render一次之后,由于后续没有数据变化,故不再renderrender() {console.log(this.props);return (<div className="component"><h1>我是B</h1>{/*获取组件内容*/}<h1>组件内容:{this.props.children}</h1></div>)}
}class C extends React.PureComponent {render() {return (<div className="component"><h1>我是C组件:{this.props.name}</h1></div>)}
}
export default App;

render props

  • 但是在实际开发中,可能多个人写多个组件,我们不可能实现这种链式嵌套,因为也可能会有这样的情况
    render() {return (<div><h1>我是App</h1>{/*app组件内,需要B和C的组合来实现功能*/}<B><C></C></B></div>)}

那么这种情况我们应该怎么传递数据呢?这里,我们就用到了render props

import React from 'react';
import "./App.css"
//这是一个父组件
class App extends React.PureComponent {//定义状态state = {name: 'React'}render() {// name = this.state.name;return (<div className="component"><h1>我是App</h1>{/*在App组件内 使用B组件嵌套c组件 并指定render接收的参数*/}<B render={data=><C name={data} />} /></div>)}
}
class B extends React.PureComponent {// 初始化render一次之后,由于后续没有数据变化,故不再renderrender() {// console.log(this.props);return (<div className="component"><h1>我是B</h1>{/*获取组件内容*/}<h1>组件内容:{this.props.children}</h1>{/*指定给c组件传递的参数*/}{this.props.render("22233")}</div>)}
}class C extends React.PureComponent {render() {console.log(this.props);return (<div className="component">{/*打印b组件传递的参数*/}<h1>我是C组件:{this.props.name}</h1></div>)}
}
export default App;

错误边界

我们知道,一个页面可能是由很多个组件组成的,但是在开发的时候我们也发现了,一旦一个组件出现问题,整个页面都会报错,我们举个例子

import React from 'react';
import "./App.css"
//这是一个父组件
class App extends React.PureComponent {// state=[//     {name:'张三'},//     {name:'李四'},// ]//将state改成字符串state = "aaaa"render() {// name = this.state.name;return (<div className="component"><h1>我是App</h1>{/*在App组件内 使用B组件嵌套c组件 并指定render接收的参数*/}<B>{this.state}</B></div>)}
}
class B extends React.PureComponent {render() {const persons = this.props.children;return (<div><h2>我是b组件</h2>{persons.map((item,index)=>(<li key={index}>{item.name}</li>))}</div>)}
}
export default App;

在这里插入图片描述
那么问题来了,一个组件的错误,导致整个页面崩溃,这明显是不科学的。我们能不能有机制去捕捉组件的错误并做出对应的处理呢?就像try catch 这种模式,答案是有的。有两个方式来捕捉错误,getDerivedStateFromError捕捉错误通知react的组件,根据错误标识做出下一步处理。componentDidCatch可以做错误统计或者通知服务端错误详情

import React from 'react';
import "./App.css"//这是一个父组件
class App extends React.PureComponent {// state=[//     {name:'张三'},//     {name:'李四'},// ]//将state改成字符串state = "aaaa"//捕捉子组件的错误信息 ,给state标识错误static getDerivedStateFromError(error) {return {hasError: true}}//用于通知服务端错误信息或者统计错误componentDidCatch(error, info) {//捕捉错误console.log(error, info)}render() {//获取到state的错误标识,做出对应处理if (this.state.hasError) {return <h1>出错了,稍后再试</h1>} else {return (<div className="component"><h1>我是App</h1><B>{this.state}</B></div>)}}
}class B extends React.PureComponent {render() {const persons = this.props.children;return (<div><h2>我是b组件</h2>{persons.map((item, index) => (<li key={index}>{item.name}</li>))}</div>)}
}
export default App;

组件通讯方式总结

  • props 用于父子组件传递数据
  • 消息订阅-发布 可以用于兄弟组件,祖孙组件
  • redux 用于兄弟组件,祖孙组件
  • context 用于祖孙组件

react route6

推荐使用函数式组件

结尾

至此,react基本就学完了。我们可以跟前端同学要个项目研究研究,自己练一练。祝大家学习愉快!

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SQLiteC/C++接口详细介绍sqlite3_stmt类(十三)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLiteC/C接口详细介绍sqlite3_stmt类&#xff08;十二&#xff09; 下一篇&#xff1a; SQLite数据库文件损坏的可能几种情况 51、sqlite3_stmt_scanstatus_reset sqlite3_stmt_scanstatus_reset 函数用于重置指…

机器学习:探索数据中的模式与智能

文章目录 导言介绍&#xff1a;机器学习的定义和重要性发展历程&#xff1a;从概念到现实应用 基础概念机器学习的基本原理监督学习、无监督学习和强化学习的区别与应用1.监督学习2.无监督学习3.强化学习 常见的机器学习任务和应用领域 结语 导言 当代科技领域中最为引人注目的…

成都欣丰洪泰文化传媒有限公司怎么样正规吗?

随着互联网的飞速发展和电子商务的蓬勃兴起&#xff0c;越来越多的企业开始将目光投向这片广阔的市场。在这个风起云涌的时代&#xff0c;成都欣丰洪泰文化传媒有限公司凭借其深厚的行业积累和前瞻性的市场洞察力&#xff0c;迅速崛起为电商服务领域的领航者&#xff0c;引领着…

百度谷歌301强引蜘蛛池效果怎么样

301强引蜘蛛池效果怎么样 本文 虚良SEO 原创&#xff0c;转载保留链接&#xff01;网址&#xff1a;百度谷歌301强引蜘蛛池效果怎么样 - 虚良SEO 随着搜索引擎优化&#xff08;SEO&#xff09;技术的发展&#xff0c;越来越多的网站开始采用蜘蛛池技术来提高网站的排名和流量。…

谭浩强第五版C语言课后习题(编程题)+答案

谭浩强第五版作为初学C语言必读的一本教材&#xff0c;课后习题具有非常大的参考价值&#xff0c;也是很多高校期末考试或者考研的重要参考。在这里我整理了一部分个人认为比较重要的编程题&#xff0c;供大家作参考 1.输入两个数&#xff0c;求他们的最大公约数和最小公倍数&…

js改变图片曝光度(高亮度)

方法一&#xff1a; 原理&#xff1a; 使用canvas进行滤镜操作&#xff0c;通过改变图片数据每个像素点的RGB值来提高图片亮度。 缺点 当前项目使用的是svg&#xff0c;而不是canvas 调整出来的效果不是很好&#xff0c;图片不是高亮&#xff0c;而是有些发白 效果 代码 …

1320亿参数,性能超LLaMA2、Grok-1!开源大模型DBRX

3月28日&#xff0c;著名数据和AI平台Databricks在官网正式开源大模型——DBRX。 DBRX是一个专家混合模型&#xff08;MoE&#xff09;有1320亿参数&#xff0c;能生成文本/代码、数学推理等&#xff0c;有基础和微调两种模型。 根据DBRX在MMLU、HumanEval和 GSM8K公布的测试…

FME学习之旅---day15

我们付出一些成本&#xff0c;时间的或者其他&#xff0c;最终总能收获一些什么。 【FME-HOW-TO系列】18 从点生成等高线数据 主要学习在FME中使用ContourGenerator和点数据集创建等高线。 读模块读取的是shp数据&#xff0c;有大概140万个点&#xff0c;加载图形很费劲。 …

二叉树|669.修剪二叉搜索树

力扣题目链接 class Solution { public:TreeNode* trimBST(TreeNode* root, int low, int high) {if (root nullptr ) return nullptr;if (root->val < low) {TreeNode* right trimBST(root->right, low, high); // 寻找符合区间[low, high]的节点return right;}if…

酷开科技依托酷开系统用“平台+产品+场景”塑造全屋智能生活!

杰弗里摩尔的“鸿沟理论”中写道&#xff1a;高科技企业推进产品的早期市场和产品被广泛接受的主流市场之间&#xff0c;存在着一条巨大的“鸿沟”。“鸿沟”&#xff0c;指产品吸引早期接纳者后、赢得更多客户前的那段间歇&#xff0c;以及其中可预知和不可预知的阻碍。多数产…

kubernetes(K8S)学习(一):K8S集群搭建(1 master 2 worker)

K8S集群搭建&#xff08;1 master 2 worker&#xff09; 一、环境资源准备1.1、版本统一1.2、k8s环境系统要求1.3、准备三台Centos7虚拟机 二、集群搭建2.1、更新yum&#xff0c;并安装依赖包2.2、安装Docker2.3、设置hostname&#xff0c;修改hosts文件2.4、设置k8s的系统要求…

实验3 中文分词

必做题&#xff1a; 数据准备&#xff1a;academy_titles.txt为“考硕考博”板块的帖子标题&#xff0c;job_titles.txt为“招聘信息”板块的帖子标题&#xff0c;使用jieba工具对academy_titles.txt进行分词&#xff0c;接着去除停用词&#xff0c;然后统计词频&#xff0c;最…

jenkins权限分配

1.安装权限插件 Role-Based Strategy 2.创建用户 3.修改全局安全配置中的授权策略为Role-Based Strategy 4.进入Manage and Assign Roles创建Global roles和Item roles 4.进入Assign Roles给用户分配role

面试题:Java虚拟机JVM的组成

1. 基础概念 JVM是什么 Java Virtual Machine Java程序的运行环境&#xff08;java二进制字节码的运行环境&#xff09; 好处&#xff1a; 一次编写&#xff0c;到处运行 自动内存管理&#xff0c;垃圾回收机制 JVM由哪些部分组成&#xff0c;运行流程是什么&#xff1f; …

Web APIs知识点讲解(阶段四)

DOM- 事件高级 一.回顾(购物车案例) <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><meta http-equiv&qu…

8年经验之谈 —— 我是如何实现接口自动化测试平台?

实现方式 — 后端&#xff1a;java 前端&#xff1a;vueelement-ui mock&#xff1a;mock-server 其它&#xff1a;redis 01—数据构建 我们在测试过程中发现测试数据的构建非常重要。如测试数据需要有真实性、唯一性、A 接口依赖 B 接口的返回值。目前通过提供环境变量…

web CSS笔记1

CSS(Cascading Style Sheets) 美化样式 CSS通常称为CSS样式表或层叠样式表&#xff08;级联样式表&#xff09;&#xff0c;主要用于设置HTML页面中的文本内容&#xff08;字体、大小、对齐方式等&#xff09;、图片的外形&#xff08;宽高、边框样式、边距等&#xff09;以及…

Redis 不再“开源”:中国面临的挑战与策略应对

Redis 不再“开源”&#xff0c;使用双许可证 3 月 20 号&#xff0c;Redis 的 CEO Rowan Trollope 在官网上宣布了《Redis 采用双源许可证》的消息。他表示&#xff0c;今后 Redis 的所有新版本都将使用开源代码可用的许可证&#xff0c;不再使用 BSD 协议&#xff0c;而是采用…

【快捷部署】010_MySQL(5.7.27)

&#x1f4e3;【快捷部署系列】010期信息 编号选型版本操作系统部署形式部署模式复检时间010MySQL5.7.27Ubuntu 20.04Docker单机2024-03-28 一、快捷部署 #!/bin/bash ################################################################################# # 作者&#xff1a…

ES5和ES6的深拷贝问题

深拷贝我们知道是引用值的一个问题&#xff0c;因为在拷贝的时候&#xff0c;拷贝的是在内存中同一个引用。所以当其中的一个应用值发生改变的时候&#xff0c;其他的同一个引用值也会发生变化。那么针对于这种情况&#xff0c;我们需要进行深度拷贝&#xff0c;这样就可以做到…