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

news2024/12/24 21:55:17

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)
    //定义一个函数调用setCount
    function 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)
    //定义一个函数调用setCount
    function 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(){
    //定义ref
    const 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(){
    //定义ref
    const 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拿到 谁声明contexttype
    static 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之后,由于数据不在变化,也不在重新render
      console.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一次之后,由于后续没有数据变化,故不再render
    render() {
        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一次之后,由于后续没有数据变化,故不再render
    render() {
        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一次之后,由于后续没有数据变化,故不再render
    render() {
        // 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.coloradmin.cn/o/1537998.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Day41:WEB攻防-ASP应用HTTP.SYS短文件文件解析Access注入数据库泄漏

目录 ASP-默认安装-MDB数据库泄漏下载 ASP-中间件-CVE&短文件&解析&写权限 HTTP.SYS&#xff08;CVE-2015-1635&#xff09;主要用作蓝屏破坏&#xff0c;跟权限不挂钩 IIS短文件(iis全版本都可能有这个问题) IIS文件解析 IIS写权限 ASP-SQL注入-SQLMAP使用…

Java安全 反序列化(5) CC6链原理分析

Java安全 反序列化(5) CC6链原理分析 CC6学习的目的在于其可以无视jdk版本&#xff0c;这条链子更像CC1-LazyMap和URLDNS链子的缝合版 文章目录 Java安全 反序列化(5) CC6链原理分析前言一.CC6的原理和实现以及易错点我们如何实现调用LazyMap.get()方法一个易错点 二.完整CC6P…

Kafka 3.x(上)

具体课程请看课程简介_哔哩哔哩_bilibili 概念 分布式流处理平台&#xff0c;它以高吞吐量和可扩展性而闻名。相同类型的消息存在于Topic主题中&#xff0c;主题类似于数据库中的表&#xff0c;不过主题存储的数据大多是半结构化的。主题可以包含多个分区&#xff08;分布式的…

Flink:维表 Join 难点和技术方案汇总

博主历时三年精心创作的《大数据平台架构与原型实现&#xff1a;数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行&#xff0c;点击《重磅推荐&#xff1a;建大数据平台太难了&#xff01;给我发个工程原型吧&#xff01;》了解图书详情&#xff0c;…

Vue模块化开发步骤—遇到的问题—解决办法

目录 1.npm install webpack -g 2.npm install -g vue/cli-init 3.初始化vue项目 4.启动vue项目 Vscode初建Vue时几个需要注意的问题-CSDN博客 1.npm install webpack -g 全局安装webpack 直接命令提示符运行改指令会报错&#xff0c;operation not permitted 注意&#…

软件推荐 篇三十七:开源免费无广告的在线音乐免费播放 | MusicFree纯净无广告体验-小众冷门推荐

引言 自从QQ音乐没了杰伦、某云开始收费&#xff0c;除了各种广告弹窗导致电脑卡的要死&#xff0c;打工人就靠这点音乐背景熬夜了&#xff0c;木有办法&#xff0c;得有个开源免费的听歌软件吧&#xff0c;一搜github&#xff0c;软件一大堆&#xff0c;作为一个打工仔&#…

python--for循环

for循环&#xff1a; python中的for循环是用来迭代容器中的每一个元素的&#xff0c;而不是c,java中理解那个循环&#xff1b; for 零时变量 in 容器&#xff1a; print&#xff08;零时变量&#xff09; #每一个迭代出的元素 range 全局函数&#xff1a; …

10、chrome拓展程序的实现

一、拓展程序的实现 拓展程序项目的构成 和前端项目一样&#xff0c;拓展程序也是有Html、CSS、JS文件实现的&#xff0c;现在看来它就是一个静态的前端页面。但是不同的是&#xff0c;拓展程序中还需要额外的一个清单文件&#xff0c;就是manifest.json&#xff0c;清单文件可…

Saltstack 最大打开文件数问题之奇怪的 8192

哈喽大家好&#xff0c;我是咸鱼。 今天分享一个在压测过程中遇到的问题&#xff0c;当时排查这个问题费了我们好大的劲&#xff0c;所以我觉得有必要写一篇文章来记录一下。 问题出现 周末在进行压测的时候&#xff0c;测试和开发的同事反映压测有问题&#xff0c;请求打到…

在 Linux/Ubuntu/Debian 上安装 SQL Server 2019

Microsoft 为 Linux 发行版&#xff08;包括 Ubuntu&#xff09;提供 SQL Server。 以下是有关如何执行此操作的基本指南&#xff1a; 注册 Microsoft Ubuntu 存储库并添加公共存储库 GPG 密钥&#xff1a; sudo wget -qO- https://packages.microsoft.com/keys/microsoft.as…

活动回顾 | 走进华为向深问路,交流数智办公新体验

3月20日下午&#xff0c;“企业数智办公之走进华为”交流活动在华为上海研究所成功举办。此次活动由上海恒驰信息系统有限公司主办&#xff0c;华为云计算技术有限公司和上海利唐信息科技有限公司协办&#xff0c;旨在通过对企业数字差旅和HR数智化解决方案的交流&#xff0c;探…

企业网络基础设施物理安全面临全新挑战

企业网络基础设施的物理安全是确保业务连续性和数据完整性的关键组成部分。随着技术的发展和环境的变化&#xff0c;这些基础设施面临着新的挑战。以下是一些主要的挑战和的解决方案 一、机房、仓库、档案馆物理安全事件频发的挑战&#xff1a; 1.电力安全事件&#xff1a;市…

Bumblebee双目测量基本原理

一.双目视觉原理 双目立体视觉三维测量是基于视差原理。 图 双目立体成像原理 因此,左相机像面上的任意一点只要能在右相机像面上找到对应的匹配点,就可以确定出该点的三维坐标。这种方法是完全的点对点运算,像面上所有点只要存在相应的匹配点,就可以参与上述运算,从而获…

代码随想录笔记|C++数据结构与算法学习笔记-二叉树(一)|二叉树的递归遍历、二叉树的迭代遍历、二叉树的统一迭代法

全文基于代码随想录及相关讲解视频。 文字链接&#xff1a;《代码随想录》 文章目录 二叉树的递归遍历二叉树的前序遍历C代码如下 二叉树的中序遍历二叉树的后序遍历 二叉树的迭代遍历前序遍历前序遍历C代码 右序遍历右序遍历C代码 中序遍历为什么中序遍历不同中序遍历迭代法的…

【C#】使用C#窗体应用开启/停止Apache、MySQL服务

目录 一、前言 二、效果图 三、配置文件 四、代码 五、一键启动/停止所有服务 一、前言 使用C#窗体应用开启Apache、MySQL服务&#xff0c;不仅仅是Apache、MySQL&#xff0c;其他服务也可以使用同样的方法操作&#xff0c;包括开启自己写的脚本服务。 二、效果图 两种状…

【大数据】五、yarn基础

Yarn Yarn 是用来做分布式系统中的资源协调技术 MapReduce 1.x 对于 MapReduce 1.x 的版本上&#xff1a; 由 Client 发起计算请求&#xff0c;Job Tracker 接收请求之后分发给各个TaskTrack进行执行 在这个阶段&#xff0c;资源的管理与请求的计算是集成在 mapreduce 上的…

TCP重传机制详解——01概述

文章目录 TCP重传机制详解——01概述什么是TCP重传&#xff1f;TCP为什么要重传&#xff1f;TCP如何做到重传&#xff1f;TCP重传方式有哪些超时重传(timeout or timer-based retransmission)快速重传(fast retransmission或者fast retransmit)改进的重传机制&#xff0c;早期重…

单机模拟分布式MINIO(阿里云)

拉取的最新MINIO&#xff1a; minio version RELEASE.2024-03-15T01-07-19Z Runtime: go1.21.8 linux/amd64 分布式 MinIO 至少需要4个节点&#xff0c;也就意味着至少4个硬盘&#xff0c;对于囊中羞涩仅用来开发测试的人来说&#xff0c;这笔花销还是比较高昂。有没有更好的…

手机可以看到电脑在干什么吗

手机与电脑之间的连接与互动已成为我们日常生活和工作中的常态。 那么&#xff0c;一个常被提及的问题是&#xff1a;手机可以看到电脑在干什么吗&#xff1f; 答案是肯定的。 随着技术的不断进步&#xff0c;我们现在已经可以通过多种方式实现手机对电脑操作的实时监控。 首…

hadoop namenode 查看日志里面报错8485无法连接

一、通过日志排查问题&#xff1a; 1、首先我通过jpsall命令查看我的进程&#xff0c;发现namenode都没有开启 2、找到问题后首先进入我的日志目录里查看namenode.log [rootnode01 ~]# /opt/yjx/hadoop-3.3.4/logs/ [rootnode01 ~]# ll [rootnode01 ~]# cat hadoop-root-nam…