React学习笔记十一——扩展知识点(setState / lazyLoad / Hook / Fragment / Context)

setState()

简单案例:
在这里插入图片描述

案例代码如下:

import React from "react";

//UI组件
export default class Person extends React.Component{
  state = {count:0}
  increment = () => {
    const {count} = this.state
    this.setState({count:count+1})
    console.log(this.state.count) // 0  此时页面显示1
  }
  render(){
	 return(
	    <div>
	      <h2>当前求和为:{this.state.count}</h2>
	      <button onClick={this.increment}>点我+1</button>
	    </div>
	 )
  }
}

1.setState两种书写形式

  • 第一个是第一个参数为对象类型的形式(经常使用)
 this.setState({count:count+1})
  • 第二个是第一个参数为updater 函数中(有两个参数state和props)
this.setState((state, props) => {
  return {counter: state.counter+1};
});

2.setState做了什么

  • setState(会对一个组件的 state 对象安排一次更新。当 state 改变了,该组件就会重新渲染。

3.setState更新后,随后打印的值未变,但页面值改变了?

  • setState()本身是同步方法,但是react中状态更新完后引起的动作是异步的。所以官网上说:“调用 setState 其实是异步的 —— 不要指望在调用 setState 之后,this.state 会立即映射为新的值。
  • 将 setState() 视为请求而不是立即更新组件的命令。为了更好的感知性能,React 会延迟调用它,然后通过一次传递更新多个组件。React 并不会保证 state 的变更会立即生效。

4.setState更新后如何马上拿到最新值?

  • 对象式setState更新:setState函数可以传入第二个参数(回调函数),此回调函数是在页面重新render后拿到count值,所以在回调函数里可以去到更改完成后的最新值
 increment = () => {
    const {count} = this.state
   
    this.setState({count:count+1},()=>{
      console.log(this.state.count) // 1  和页面显示的值一样
    })  
  }
  • componentDidUpdate生命钩子函数可以拿到更新过的state

lazyLoad

使用之前:

import OtherComponent from './OtherComponent';

使用之后:

import React, {lazy} from 'react';
const OtherComponent = lazy(() => import('./OtherComponent'));

此代码将会在组件首次渲染时,自动导入包含 OtherComponent 组件的包。

lazy函数是什么?

  • React.lazy 函数能让你像渲染常规组件一样处理动态引入(的组件)
  • React.lazy 接受一个函数,这个函数需要动态调用 import()。它必须返回一个 Promise,该 Promise 需要 resolve 一个 default export 的 React 组件。
  • 然后应在 Suspense 组件中渲染 lazy 组件,如此使得我们可以使用在等待加载 lazy 组件时做优雅降级 。
  • Suspense 组件的fallback 属性接受任何在组件加载过程中你想展示的 React 元素(loading页面)。你可以将 Suspense 组件置于懒加载组件之上的任何位置。你甚至可以用一个 Suspense 组件包裹多个懒加载组件。

代码案例

上面的语言描述只读是理解不了的,还是得结合代码一块理解,话不多说,上代码!

用lazy函数结合Suspense组件实现路由懒加载

import React, { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';

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

const App = () => (
  <Router>
    <Suspense fallback={<div>Loading...</div>}>
      <Switch>
        <Route  path="/" component={Home}/>
        <Route path="/about" component={About}/>
      </Switch>
    </Suspense>
  </Router>
);

上面代码通过lazy函数引入的组件,页面一上来并不全部被渲染,当点击进入某个组件时才会去加载组件。点击加载组件时,如果网速较慢,会显示Suspense组件fallback属性引入的加载中组件或者其他React 元素。

为什么这样做?现在只是两个组件,那一百个组件呢,如果不适用懒加载,一上来首次渲染,100个组件需要全部都被渲染,加长了首屏加载时间。而采用lazy懒加载,这样可以更好的提高了用户体验,首屏组件加载速度更快一些,解决白屏问题。

Hook

React Hook 是什么?

  • Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。

三个常用的Hook

  • state Hook:React.useState()
  • Effect Hook:React.useEffect()
  • Ref Hook:react.useRef()

state Hook

  • state Hook让函数组件也可以有state状态,并进行状态数据的读写操作
  • 语法:const {xxx,setXxx} = React.useState(initValue)
  • useState()说明:

参数:第一次初始化指定的值在内部作缓存
返回值:包含2个元素的数据,第一个参数为函数,第2个为内部当前指定新的状态值,内部用其覆盖原来的状态值

  • setXxx()2种写法:

setXxx(newValue):参数为非函数值,直接指定新的状态值。内部用其覆盖原来的状态值
setXxx( value => newValue):参数为函数,接受原来的状态值,返回新的状态值,内部用其覆盖原来的状态值

还是第一个点击+1的案例:

import React from 'react'

function demo(){
  const [count,setCount] = React.useState(0)
  functon increment(){
    setCount(count+1)
  }
  return(
    <div>
       <h2>当前求和为:{count}</h2>
	    <button onClick={increment}>点我+1</button>
    </div>
  )
}

Effect Hook

  • Effect Hook可以让你在函数组件中执行副作用操作(用于模拟类组件中的生命周期钩子)
  • React中的副作用操作:

发ajax请求数据获取
设置订阅/启动定时器
手动更改真实DOM

  • 语法和说明
 useEffect(() => {
   //在此可以执行任何带副作用的操作
   return () => {
     //在此做一些收尾工作,比如清除定时器/取消订阅
   }
 },[stateValue]) 
 {/*第2个参数[stateValue]有检测的意思,如果指定的是[],
 回调函数只会在第一次render()后执行,如果不传第2个参数[]的话,
 相当于检测所欲satte,在state发生变化时也会触发回调函数*/}
  • 可以把useEffect Hook看作如下三个函数的组合

componentDidMount()
componentDidUpdate()
componentWillUnmount()

挂载后自动一直+1的案例:

import React from 'react'

function demo(){
  const [count,setCount] = React.useState(0)
  React.useEffect(() => { 
     const timer = setInterval(() => {
       setCount(count+1)
     },500)
     return () => {
       clearInterval(timer)
     }
  },[])
  function unMount(){
    ReactDOM.unmountComponentAtNode(document.getElementById('root'))
  }
  return(
    <div>
       <h2>当前求和为:{count}</h2>
	    <button onClick={unMount}>点击卸载组件</button>
    </div>
  )
}

Ref Hook

  • Ref Hook可以在函数组件中存储/查找组件内部标签或任意其他数据
  • 语法: const myRef = React.useRef()
  • 作用:保存标签对象,功能与React.createRef()一样
import React from 'react'

function demo(){
  const myRef = React.useRef()
  show(){
    alert(myRef.current.value)
  }
  return(
    <div>
       <input type="text" ref={myRef]>
	   <button onClick = {show}>点击提示input框信息</button
    </div>
  )
}

Fragment

  • 使用:< Fragment > </ Fragment >
  • 作用:可以不用必须有一个真实DOM跟标签了

来个简单案例:

class Count extends React.Component{
 render(){
   return(
     <div> {/*包<div>的原因是下只有一个根元素,其实可以用<Fragment>代替,控制台打印就不会被显示此标签*/}
        <div>...
        <input>...
        ...
     </div>
   )
 }
}

Context

理解

  • 一种组件通信的方式,常用于祖组件与后代组件之间的通信

使用

  • 创建Context容器对象:const XxxContext = React.createContext()
  • 渲染子组件时,外面包裹XxxContext .Provider,通过value属性给后代组件传递数据
<XxxContext .Provider value={数据}>
</XxxContext .Provider>

  • 后代组件读取数据
//第一种方式:仅限于类组件
static contextType = MyContext //声明需要接收context
this.context
//第二种方式:函数组件和类组件都可以使用
<XxxContext .Consumer value={数据}>
  {
     value => { //value 就是context中的value数据
      //显示内容
     }
  }
</XxxContext .Consumer>

案例

const MyContext = React.createContext()
const {Provider,Consumer} = MyContext 

//祖组件
class A extends React.Component{
 state = {
   useName:'A组件'
 }
 render(){ 
  const {useName} = this.state
   return(
     <div> 
       <h2>我是A组件,用户名为:{useName}</h2>
       <Provider value={useName}>
         <B/>
       </Provider>
     </div>
   )
 }
}

//子组件
class B extends React.Component{
 render(){
   return(
     <div> 
        <C />
        <D />
        <h2>我是B组件</h2>
        <h2>我从A组件接收到的用户名是:{}</h2>
     </div>
   )
 }
}

//孙组件(类组件)
class C extends React.Component{
static contextType = MyContext //声明需要接收context
 render(){
   return(
     <div> 
        <h2>我是C组件</h2>
        <h2>我从A组件接收到的用户名是:{this.context}</h2>
     </div>
   )
 }
}

//孙组件(函数组件)
function D(){
 
  return(
    <div>
       <div> 
        <h2>我是D组件</h2>
        <h2>我从A组件接收到的用户名是:
          <Consumer>
            {
              value => {
                retrun `${value.useName}`
              }
            }
          <Consumer/>
        </h2>
     </div>
    </div>
  )
}
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端探险家

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值