React 入门学习(十七)-- React 扩展

简介: React 入门学习(十七)-- React 扩展

6.gif

大家好,我是小丞同学,一名大二的前端爱好者


这篇文章是学习 React扩展部分的学习笔记


非常感谢你的阅读,不对的地方欢迎指正


愿你忠于自己,热爱生活


引言

学到这里 React 已经学的差不多了,接下来就学习一些 React 扩展内容,可以帮助我们更好的开发和理解,这部分的知识还有很多的东西可以探寻,比如:网红 React-Hook,就是我们需要注意的地方,打了 100 多集的类式组件,出来一个 hooks ,现在用函数式组件偏多了…


所以 Hooks 就需要我们深入的学习一下了,下面我们就一起来看看扩展部分有哪些内容吧


1. setState

对象式 setState

首先在我们以前的认知中,setState 是用来更新状态的,我们一般给它传递一个对象,就像这样

this.setState({
    count: count + 1
})

这样每次更新都会让 count 的值加 1。这也是我们最常做的东西

这里我们做一个案例,点我加 1,一个按钮一个值,我要在控制台输出每次的 count 的值

image.png

那我们需要在控制台输出,要如何实现呢?

我们会考虑在 setState 更新之后 log 一下

add = () => {
    const { count } = this.state
    this.setState({
        count: count + 1
    })
    console.log(this.state.count);
}

因此可能会写出这样的代码,看起来很合理,在调用完 setState 之后,输出 count

image.png

我们发现显示的 count 和我们控制台输出的 count 值是不一样的

这是因为,我们调用的 setState 是同步事件,但是它的作用是让 React 去更新数据,而 React 不会立即的去更新数据,这是一个异步的任务,因此我们输出的 count 值会是状态更新之前的数据。“React 状态更新是异步的”

那我们要如何实现同步呢?

其实在 setState 调用的第二个参数,我们可以接收一个函数,这个函数会在状态更新完毕并且界面更新之后调用,我们可以试试

add = () => {
    const { count } = this.state
    this.setState({
        count: count + 1
    }, () => {
        console.log(this.state.count)
    })
}

我们将 setState 填上第二个参数,输出更新后的 count 值image.png

这样我们就能成功的获取到最新的数据了,如果有这个需求我们可以在第二个参数输出噢~

函数式 setState

这种用法我也是第一次见,函数式的 setState 也是接收两个参数

第一个参数是 updater ,它是一个能够返回 stateChange 对象的函数

第二个参数是一个回调函数,用于在状态更新完毕,界面也更新之后调用

与对象式 setState 不同的是,我们传递的第一个参数 updater 可以接收到2个参数 state 和 props

我们尝试一下

add = () => {
    this.setState((state) => ({ count: state.count + 1 }))
}

image.png

我们也成功的实现了

我们在第一个参数中传入了一个函数,这个函数可以接收到 state ,我们通过更新 state 中的 count 值,来驱动页面的更新

利用函数式 setState 的优势还是很不错的,可以直接获得 state 和 props

可以理解为对象式的 setState 是函数式 setState 的语法糖

2. LazyLoad

懒加载在 React 中用的最多的就是路由组件了,页面刷新时,所有的页面都会重新加载,这并不是我们想要的,我们想要实现点击哪个路由链接再加载即可,这样避免了不必要的加载

image.png

我们可以发现,我们页面一加载时,所有的路由组件都会被加载

如果我们有 100 个路由组件,但是用户只点击了几个,这就会有很大的消耗,因此我们需要做懒加载处理,我们点击哪个时,才去加载哪一个

首先我们需要从 react 库中暴露一个 lazy 函数

import React, { Component ,lazy} from 'react';

然后我们需要更改引入组件的方式

const Home = lazy(() => import('./Home'))
const About = lazy(() => import('./About'))

采用 lazy 函数包裹

image.png

我们会遇到这样的错误,提示我们用一个标签包裹

这里是因为,当我们网速慢的时候,路由组件就会有可能加载不出来,页面就会白屏,它需要我们来指定一个路由组件加载的东西,相对于 loading

 

<Suspense fallback={<h1>loading</h1>}>
    <Route path="/home" component={Home}></Route>
    <Route path="/about" component={About}></Route>
</Suspense>

在做这个案例的时候,一定不要设置重定向的东西,所有的路由我们要点击再加载

初次登录页面的时候

image.png

在做这个案例的时候,一定不要设置重定向的东西,所有的路由我们要点击再加载

初次登录页面的时候

image.png

注意噢,这些文件都不是路由组件,当我们点击了对应组件之后才会加载7.gif

从上图我们可以看出,每次点击时,才会去请求 chunk 文件

那我们更改写的 fallback 有什么用呢?它会在页面还没有加载出来的时候显示8.gif

注意:因为 loading 是作为一个兜底的存在,因此 loading 是 必须提前引入的,不能懒加载

3. Hooks

useState

hooks 解决了函数式组件和类式组件的差异,让函数式组件拥有了类式组件所拥有的 state ,同时新增了一些 API ,让函数式组件,变得更加的灵活

首先我们需要明确一点,函数式组件没有自己的 this

 
         

这里利用了一个 Hook :useState

它让函数式组件能够维护自己的 state ,它接收一个参数,作为初始化 state 的值,赋值给 count,因此 useState 的初始值只有第一次有效,它所映射出的两个变量 count 和 setCount 我们可以理解为 setState 来使用

useState 能够返回一个数组,第一个元素是 state ,第二个是更新 state 的函数

我们先看看控制台输出的什么

image.png

count 是初始化的值,而 setCount 就像是一个 action 对象驱动状态更新

我们可以通过 setCount 来更新 count 的值

 

setCount(count + 1)

useEffect

在类式组件中,提供了一些声明周期钩子给我们使用,我们可以在组件的特殊时期执行特定的事情,例如 componentDidMount ,能够在组件挂载完成后执行一些东西

在函数式组件中也可以实现,它采用的是 effectHook ,它的语法更加的简单,同时融合了 componentDidUpdata 生命周期,极大的方便了我们的开发

React.useEffect(() => {    console.log('被调用了');})

由于函数的特性,我们可以在函数中随意的编写函数,这里我们调用了 useEffect 函数,这个函数有多个功能


当我们像上面代码那样使用时,它相当于 componentDidUpdata 和 componentDidMount 一同使用,也就是在组件挂载和组件更新的时候都会调用这个函数


9.gif

它还可以接收第二个参数,这个参数表示它要监测的数据,也就是他要监视哪个数据的变化

当我们不需要监听任何状态变化的时候,我们可以就传递一个空数组,这样它就能当作 componentMidMount 来使用

React.useEffect(() => {    console.log('被调用了');}, [])

这样我们只有在组件第一次挂载的时候触发

当然当页面中有多个数据源时,我们也可以选择个别的数据进行监测以达到我们想要的效果

React.useEffect(() => {    console.log('被调用了');}, [count])

这样,我们就只监视 count 数据的变化

当我们想要在卸载一个组件之前进行一些清除定时器的操作,在类式组件中,我们会调用生命周期钩子 componentDidUnmount 来实现,在函数式组件中,我们的写法更为简单,我们直接在 useEffect 的第一个参数的返回值中实现即可

也就是说,第一个参数的函数体相当于 componentDidMount 返回体相当于 componentDidUnmount ,这样我们就能实现在组件即将被卸载时输出一些东西了

实现卸载

function unmount() {    ReactDOM.unmountComponentAtNode(document.getElementById("root"))}

卸载前输出

React.useEffect(() => {    console.log('被调用了');    return () => {        console.log('我要被卸载了');    }}, [count])

image.png

实现了在组件即将被卸载的时候输出

因此 useEffect 相当于三个生命周期钩子,componentDidMount 、componentDidUpdata 、componentDidUnmount

useRef

当我们想要获取组件内的信息时,在类式组件中,我们会采用 ref 的方式来获取。在函数式组件中,我们可以采用也可以采用 ref 但是,我们需要采用 useRef 函数来创建一个 ref 容器,这和 createRef 很类似。

<input type="text" ref={myRef} />

获取 ref 值

function show() {    alert(myRef.current.value)}

即可成功的获取到 input 框中的值

4. Fragment

我们编写组件的时候每次都需要采用一个 div 标签包裹,才能让它正常的编译,但是这样会引发什么问题呢?我们打开控制台看看它的层级

image.png

它包裹了几层无意义的 div 标签,我们可以采用 Fragment 来解决这个问题

首先,我们需要从 react 中暴露出 Fragment ,将我们所写的内容采用 Fragment 标签进行包裹,当它解析到 Fragment 标签的时候,就会把它去掉

image.png

这样我们的内容就直接挂在了 root 标签下

同时采用空标签,也能实现,但是它不能接收任何值,而 Fragment 能够接收 1 个值key

5. Context

仅适用于类式组件

当我们想要给子类的子类传递数据时,前面我们讲过了 redux 的做法,这里介绍的 Context 我觉得也类似于 Redux

首先我们需要引入一个 MyContext 组件,我们需要引用MyContext 下的 Provider

const MyContext = React.createContext();const { Provider } = MyContext;

用 Provider 标签包裹 A组件内的 B 组件,并通过 value 值,将数据传递给子组件,这样以 A 组件为父代组件的所有子组件都能够接受到数据

<Provider vlue={{ username, age }}>    <B /></Provider>

但是我们需要在使用数据的组件中引入 MyContext

static contextType = MyContext;

在使用时,直接从 this.context 上取值即可

const {username,age} = this.context

适用于函数和类式组件

由于函数式组件没有自己 this ,所以我们不能通过 this.context 来获取数据

这里我们需要从 Context 身上暴露出一个 Consumer

const { Provider ,Consumer} = MyContext;

然后通过 value 取值即可

function C() {  return (    <div>      <h3>我是C组件,我从A接收到的数据 </h3>      <Consumer>        {(value) => {          return `${value.username},年龄是${value.age}`;        }}      </Consumer>    </div>  );}

image.png

因此想要在函数式组件中使用,需要引入 Consumer

6. PureComponent

在我们之前一直写的代码中,我们一直使用的Component 是有问题存在的

1.只要执行 setState ,即使不改变状态数据,组件也会调用 render

当前组件状态更新,也会引起子组件 render

而我们想要的是只有组件的 state 或者 props 数据发生改变的时候,再调用 render

我们可以采用重写 shouldComponentUpdate 的方法,但是这个方法不能根治这个问题,当状态很多时,我们没有办法增加判断

我们可以采用 PureComponent

我们可以从 react 身上暴露出 PureComponent 而不使用 Component

import React, { PureComponent } from 'react'

就这~听了半天结果就只一个 PureComponent

PureComponent 会对比当前对象和下一个状态的 prop 和 state ,而这个比较属于浅比较,比较基本数据类型是否相同,而对于引用数据类型,比较的是它的引用地址是否相同,这个比较与内容无关

7. render props

采用 render props 技术,我们可以像组件内部动态传入带有内容的结构

当我们在一个组件标签中填写内容时,这个内容会被定义为 children props,我们可以通过 this.props.children 来获取

例如:

<A>hello</A>

这个 hello 我们就可以通过 children 来获取

而我们所说的 render props 就是在组件标签中传入一个 render 方法,又因为属于 props ,因而被叫做了 render props

<A render={(name) => <C name={name} />} />

你可以把 render 看作是 props,只是它有特殊作用,当然它也可以用其他名字来命名

在上面的代码中,我们需要在 A 组件中预留出 C 组件渲染的位置 在需要的位置上加上{this.props.render(name)}

那我们在 C 组件中,如何接收 A 组件传递的 name 值呢?通过 this.props.name 的方式

8. ErrorBoundary

当不可控因素导致数据不正常时,我们不能直接将报错页面呈现在用户的面前,由于我们没有办法给每一个组件、每一个文件添加判断,来确保正常运行,这样很不现实,因此我们要用到错误边界技术

错误边界就是让这块组件报错的影响降到最小,不要影响到其他组件或者全局的正常运行

例如 A 组件报错了,我们可以在 A 组件内添加一小段的提示,并把错误控制在 A 组件内,不影响其他组件

·我们要对容易出错的组件的父组件做手脚,而不是组件本身

我们在父组件中通过 getDerivedStateFromError 来配置子组件出错时的处理函数

static getDerivedStateFromError(error) {    console.log(error);    return { hasError: error }}

我们可以将 hasError 配置到状态当中,当 hasError 状态改变成 error 时,表明有错误

发生,我们需要在组件中通过判断 hasError 值,来指定是否显示子组件

{this.state.hasError ? <h2>出错啦</h2> : <Child />}

在服务器中启动,才能正常看到效果

可以在 componentDidCatch 中统计错误次数,通知编码人员进行 bug 解决

9. 组件通信方式总结

1.props

1.children props

2.render props

2.消息发布订阅

1.利用 pubsub 库来实现

3.集中式状态管理

1.redux

4..conText

1.生成者-消费者

相关文章
|
14天前
|
前端开发 JavaScript
React学习之——条件渲染
【10月更文挑战第16天】React 中没有像Vue中v-if这种指令。React 中的条件渲染和 JavaScript 中的一样,使用 JavaScript 运算符 if 或者条件运算符去创建元素来表现当前的状态,然后让 React 根据它们来更新 UI。
|
2月前
|
前端开发 JavaScript
学习react基础(3)_setState、state、jsx、使用ref的几种形式
本文探讨了React中this.setState和this.state的区别,以及React的核心概念,包括核心库的使用、JSX语法、类与函数组件的区别、事件处理和ref的使用。
60 3
学习react基础(3)_setState、state、jsx、使用ref的几种形式
|
2月前
|
前端开发 JavaScript
react学习(13)props
react学习(13)props
|
2月前
|
前端开发
学习react基础(2)_props、state和style的使用
本文介绍了React中组件间数据传递的方式,包括props和state的使用,以及如何在React组件中使用style样式。
29 0
|
8天前
|
监控 前端开发 JavaScript
React 静态网站生成工具 Next.js 入门指南
【10月更文挑战第20天】Next.js 是一个基于 React 的服务器端渲染框架,由 Vercel 开发。本文从基础概念出发,逐步探讨 Next.js 的常见问题、易错点及解决方法,并通过具体代码示例进行说明,帮助开发者快速构建高性能的 Web 应用。
31 10
|
5天前
|
前端开发 JavaScript 安全
学习如何为 React 组件编写测试:
学习如何为 React 组件编写测试:
16 2
|
20天前
|
资源调度 前端开发 JavaScript
React进阶学习
React进阶学习
10 1
|
22天前
|
前端开发 JavaScript 开发者
探索现代Web前端技术:React框架入门
【10月更文挑战第9天】 探索现代Web前端技术:React框架入门
|
2月前
|
移动开发 前端开发 JavaScript
构建高效跨平台移动应用:React Native入门指南
【8月更文挑战第47天】在移动开发领域,React Native凭借其跨平台特性和高效的开发模式赢得了开发者的青睐。本文将通过一个简易的待办事项应用实例,带领读者快速入门React Native,并展示如何利用JavaScript和React框架构建具有原生性能的应用。我们将探讨环境配置、界面布局、状态管理和数据流,以及如何打包和发布您的应用。准备好,让我们开始React Native之旅!
70 20
|
20天前
|
JSON 前端开发 JavaScript
React 进阶阶段学习计划
React 进阶阶段学习计划