React-Hook学习笔记

React-Hook

hook-router-redux

简介

React Hooks就是用函数的形式代替原来的继承类的形式,并且使用预函数的形式管理state,有Hooks可以不再使用类的形式定义组件了。这时候你的认知也要发生变化了,原来把组件分为有状态组件无状态组件,有状态组件用类的形式声明,无状态组件用函数的形式声明。那现在所有的组件都可以用函数来声明了。

react hooks 编写形式对比

原生写法:

import React, { Component } from 'react';

class Example extends Component {
    constructor(props) {
        super(props);
        this.state = { count:0 }
    }
    render() { 
        return (
            <div>
                <p>You clicked {this.state.count} times</p>
                <button onClick={this.addCount.bind(this)}>Chlick me</button>
            </div>
        );
    }
    addCount(){
        this.setState({count:this.state.count+1})
    }
}

export default Example;

hook写法:

import { useState } from "react";

function HookDemo() {  //必须大写
  const [count,setCount] = useState(0);
  return ( 
    <div>
      <p>you clicked {count} times</p>
      <button  onClick = {()=>{setCount(count+1)}}>click me</button>
    </div>

   );
}

export default HookDemo;

hook 就是让你不再写class extent 用函数一统江湖

Hook的使用说明

  • Hook不能在class组件中使用(可以在package中进行修改)
    也就是说组件用了class声明就不能再用useState等函数

  • 只能在函数最外层调用Hook。不要在循环,条件判断或者子函数中调用

    不能在判断中使用useEffect等(因为钩子函数是根据创建顺序对应,执行顺序不能发生变化)

  • 只能在React的组件函数中调用Hook,不要在其他JS函数中调用

useState

useState的介绍

useState是一个自带的hook函数,他的作用是用来声明状态变量

那我们从三个方面来看useState的用法,分别是声明、读取、使用(修改)。这三个方面掌握了,你基本也就会使用useState了.

使用前要引用

import { useState } from "react";
声明
const [count,setCount] = useState(0);

useState接受的参数是状态的初始值,他返回一个数组,这个数组第0位是当前的状态值,第1位是可以改变状态值的函数,所以上面的代码就是声明了一个状态变量count,以及可以改变count的状态值的函数**(解构的思想)**

const [person,setPerson] = useState({
    name:"zjx",
    age:18,
  });
读取
<p>You clicked {count} times</p>

读取很简单,因为是一个变量,在JSX中直接用{}读取

修改

直接调用setCount,传入参数就是对应修改过状态值,剩下的React会重新渲染组件

<button onClick={()=>{setCount(count+1)}}>click me</button>  //count = count+1 

对于复杂的更新逻辑使用函数式更新

const handleClick1= ()=>{
    setCount(()=>{
       if(count<3){
       	return count+1;  //这里不能写count = count+1 
      }
    	else {
        return count+2
    	}
    })
  }
<button  onClick = {()=>{handleClick()}}>click me</button>

必须有返回值而且返回值必须是一个常量

 const handleClick2 = ()=>{
    setPerson(()=>{
      return {
        ...person,
        name:'zs'
      }
    })
 }

多状态声明的注意事项

比如我们现在要声明多个状态

import React,{ useState } from "react";
function Demo2() {
  const [age,setAge] = useState(10);
  const [sex,setSex] = useState('MALE');
  const [work,setWork] =  useState('engineer');
  return ( 
    <div>
      <p>zjx is {age} years old</p>
      <p>zjx's gender is {sex}</p>
      <p>zjx's work is {work}</p>
    </div>
   );
}

export default Demo2;

react是如何把useState中的值绑定到前面的状态值当中呢

答案是按顺序绑定,所以useState不能写在 if else 等判断性语句中

useState惰性初始化

<HookDemo init = {100}/>
//function HookDemo(props) {
  const [count,setCount] = useState(()=>{
    if(props.init<100){
      return props.init+1;
    }
    else {
      return props.init+100;
    }
  });  //通过函数式调用进行props的判断,再返回给count的值,注意返回的是一个常量

如果状态值没有更新,那么react将跳过组件的渲染和effect的执行

useContext

import React,{useContext}  from 'react';
import './App.css';
//创建context
const numberContext = React.createContext();
//它返回一个具有两个值的对象
//{Provider , Consumer}
function App(){
  //使用Provider为所有子孙提供value值
  return (
    <numberContext.Provider value={520}>
        <div>
        <ShowAn />
        </div>
    </numberContext.Provider>
  )
}

function ShowAn(){
  //使用Consumer从上下文获取value
//调用useContext,传入从React.createContext获取的上下文对象。
  const value = useContext(numberContext);
  return(
    // <numberContext.Consumer>
      // {value=><div>the answer is {value}</div>}
    // </numberContext.Consumer>
    <div>
      the answer is {value}
    </div>

  )
}
export default App;

带有参数的createContext声明

context.js

import React from 'react'


export const themes = {
  light:{
    color:"red",
    backgroundColor:"#ffcc33",
  },
  dark:{
    color:"blue",
    backgroundColor:"#222222",
  }
}
export const ThemeContext =  React.createContext(themes);// 这个参数加不加意义不大  

father.js

import React from 'react'
import {ThemeContext,themes} from './context'
import Child from './child'
function Father(){
  // console.log(test);
  return (
    <ThemeContext.Provider value = {themes.light}> //这里一定要引入两个变量一个是createContext创建的变量,还有一个是传入的参数,具体是为什么我也不知道
      <Child/>
  </ThemeContext.Provider>
  )
  

}
export default Father ;

child.js

import React,{useContext} from 'react'
import {ThemeContext} from './context'
function Child() {
  // const value = useContext(ThemeContext);
  // console.log(themes);
  const value = useContext(ThemeContext)//接受的参数是带有provider的标签,接收到的是value值
  console.log(value)
  return ( 
    <button style = {value}>
      点击 
    </button>
  );
}

export default Child;

useEffect

在react完成对DOM的更新后会执行,默认情况下, react会在渲染后调用副作用函数,包括第一次渲染的时候(didmounted didupdated)

使用前进行引入

import { useEffect} from "react";
const [count,setCount] = useState(0);
useEffect(()=>{
    setCount(1);
    console.log(count);
  })
//output is 0 1  0是因为第一次页面渲染count的初始值是0,同时把setcount放到循环队列中,这是一个异步的过程,然后调用setcount改变count值为1,页面重新渲染,再次进入useEffect中,打印出1
import React, { useState, useEffect } from 'react';

function Demo3 () {
  const [ count , setCount ] = useState(0);
  useEffect(() =>{
    console.log(`useEffect you clicked ${count} times`);
  })
  return ( 
    <div>
      <p>You clicked {count} times</p>
            <button onClick={()=>{setCount(count+1)}}>click me</button>
    </div>
  );
}

export default Demo3;

每次函数mount渲染之后都会执行useEffect,而之前我们要componentDidMount和componentDidUpdate两个生命周期函数来实现

useEffect的两个参数

第一个参数是副作用的处理函数,第二个参数是与该副作用关联的状态或属性依赖数组

完整demo代码如下

import { useState ,useEffect} from "react";

function HookDemo(props) {
  const [count,setCount] = useState(0);
  // console.log("update")
  useEffect(()=>{
    console.log('useEffect');
  },[])
  const handleClick1 = ()=>{
    setCount(()=>{
       if(count<3){
       	return  count+1;
      }
    	else {
        return count+2
    	}
    })
  }

  return ( 
    <div>
      <p>you clicked {count} times</p>
      <button  onClick = {()=>{handleClick1();}}>click me</button>
      {/* <button  onClick = {()=>{handleClick2()}}>click me</button> */}
    </div>

   );
}

export default HookDemo;

如果我们要useEffect函数只执行一次,也就是只在第一次渲染的时候进行更新,那么传递进去的参数就是空

useEffect中的return

useEffect(()=>{
	//开始监听代码
    console.log('开始监听');
    return()=>{
    //结束监听代码
      console.log("取消监听")
    }
  })

页面首次渲染 output is 开始监听

当页面Dom改变,the output is 取消监听 开始监听

可得知第一次渲染不执行useEffect函数但是后面页面的更新是先执行return中的函数的

可以用于监听函数,这一次点击事件需要取消上一次遗留下来的信息,就可以用return函数清除上次的信息

使用useEffect函数实现生命周期函数

ccomponentDidUpdate

useEffect(()=>{},[需要监听的变量])

如何绕过 Capture Value

function Demo3 () {
  const [count, setCount] = useState(0);
  const latestCount = useRef(count);

  useEffect(() => {
    // Set the mutable latest value
    latestCount.current = count;
    setTimeout(() => {
      // Read the mutable latest value
      console.log(`You clicked ${count} times`);
    }, 3000);
  });
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );

}

获取的是点击时的值

利用 useRef 就可以绕过 Capture Value 的特性。可以认为 ref 在所有 Render 过程中保持着唯一引用,因此所有对 ref 的赋值或取值,拿到的都只有一个最终状态,而不会在每个 Render 间存在隔离。

function Example() {
  const [count, setCount] = useState(0);
  const latestCount = useRef(count);

  useEffect(() => {
    // Set the mutable latest value
    latestCount.current = count;
    setTimeout(() => {
      // Read the mutable latest value
      console.log(`You clicked ${latestCount.current} times`);
    }, 3000);
  });
  // ...
}

获取点击之后的终值

回收机制

在组件被销毁时,通过 useEffect 注册的监听需要被销毁,这一点可以通过 useEffect 的返回值做到:

useEffect(() => {
  ChatAPI.subscribeToFriendStatus(props.id, handleStatusChange);
  return () => {
    ChatAPI.unsubscribeFromFriendStatus(props.id, handleStatusChange);
  };
});

在组件被销毁时,会执行返回值函数内回调函数。同样,由于 Capture Value 特性,每次 “注册” “回收” 拿到的都是成对的固定值。

useReducer

The useReducer hook is similar to useState, but gives us a more structured approach for updating complex values.

We typically use useReducer when our state has multiple sub-values, e.g. an object containing keys that we want to update independently.

useReducer接受三个参数,第一个参数是处理状态更新的reducer(处理状态更新都要把参数返回),第二个参数是状态初始值,但三个函数是状态初始化函数

import { useState ,useEffect, useReducer} from "react";

function HookDemo(props) {
  function init(initialCount){
    return {count:initialCount};
  }
  function reducer(state,action){
    switch(action.type){
      case 'increment':return {count:state.count+1};
      case 'decrement':return {count:state.count-1};
      case 'reset':return init(action.payload);
      default:throw new Error();
    }
  }
  const [state,dispatch] = useReducer(reducer,1,init);  
  return ( 
    <div>
      <p>you clicked {state.count} times</p>
      <button  onClick = {()=>{dispatch({type:'reset',payload:1})}}>click me to reset</button>
      <button  onClick = {()=>{dispatch({type:'decrement'})}}>click me to decrement one</button>
      <button  onClick = {()=>{dispatch({type:'increment'})}}>click me add one </button>
      {/* <button  onClick = {()=>{handleClick2()}}>click me</button> */}
    </div>

   );
}

export default HookDemo;

dispatch会调用reducer函数,同时传进去的参数就是reducer中的action对象

state是个对象状态值,可以存储很多数据

init是初始化状态对象count为1

useCallback

x更新,y也会随之更新

function Demo3(){
  const [x,setX] = useState(0);
  const y = 2*x+1
  const changeX = ()=>{
    setX(x+1);
  }
  return (
    <ul onClick={changeX}>
      <li>x是{x}</li>
      <li>y是{y}</li>
    </ul>
  )
}
const y = useMemo(()=>2*x+1,[x]);  //定义变量的改变,使用useMemo返回一个表达式,第二个参数是绑定的因变量的值
const changeX = useCallback(()=>setX(x+1),[x]);  //返回体是一个函数,第二个参数是绑定值

这两种方法可以提高性能

基本写法

第一个参数是处理函数,第二个参数是一个数组,用于制定被记忆函数更新所依赖的值,返回的是一个函数

const memoizedCallback = useCallback(()=>{
	doSomething(a,b);
},[a,b])

为什么要使用useCallback

函数式组件中,定义在组件内函数会随着状态值的更新而重新渲染,函数中定义的函数会被频繁定义,在父子组件通信中这是非常消耗性能的,使用useCallback和memo减少子组件更新频率,提高效率

如下,每次点击都会重新渲染子组件,每次都会重新打印

我们使用memo(react的高阶方法),就不会重新打印了

 import React , {useCallback,useState} from 'react';
 //父组件
 function Memoized() {
  const [count,setCount] = useState(1);
  const handleClick = ()=>{
    setCount(count+1);
  }
  // const handleClick = useCallback(()=>{setCount(1);})
  return ( 
    <div>
      <p>{count}</p>
      <button onClick={handleClick}>点击</button>
      <Child></Child>
    </div>
   );
 }
 

const Child = React.memo(function Child(){
  console.log("子组件被触发")
  return(
    <div>
      <p>hello world </p>
    </div>
  )
}) //传入组件,如果这个组件props的值没有变化,那就被缓存,不会更新


 export default Memoized ;
 

如果我们需要子组件调用父组件的函数,那么父组件每次重新渲染函数都会跟着一起更新,那么子组件的props就会改变,又会触发打印,所以我们使用useCallback 用于子组件调用父组件的方法,同时父组件是频繁改变的状态:

 import React , {useCallback,useState} from 'react';
 //父组件
 function Memoized() {
  const [count,setCount] = useState(1);
  // const handleClick = ()=>{
  //   setCount(count+1);
  // }
  const handleClick = useCallback(()=>{setCount(count+1);},[count])
  const childClick = ()=>{

  }
  const childClick = useCallback(()=>{}.[]);  //不会打印了
  return ( 
    <div>
      <p>{count}</p>
      <button onClick={handleClick}>点击</button>
      <Child childClick={childClick}></Child>
    </div>
   );
 }
 


 const Child = React.memo(function Child(){
  console.log("子组件被触发")
  return(
    <div>
      <p>hello world </p>
    </div>
  )
})


 export default Memoized ;
 

useMemo

第一个参数用于计算并返回需要记录的值,第二个参数为数组,用于记忆,返回一个值

const memoizedValue = useMemo(()=>{computedValue(a,b)},[a,b]);

useMemo和useCallback的区别

  1. useMemo传入的函数内部需要有返回值
  2. useMemo只能声明在函数式组件内部 类比react.memo

点击事件的bug:

(6条消息) 解决“Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.”_蛞蝓不孤寡的博客-CSDN博客

计算属性的监听作用

import React,{useState,useMemo} from 'react'
function MemoizeValue() {
  const [a,setA] = useState(0);
  const [b,setB] = useState(0);
  const [d,setD] = useState(0);
  const c = useMemo(()=>a+b,[a,b]);
  const handleClick = (type)=>{
    switch(type){
      case 'a':
        setA(a+1)
        break;
      case 'b':
        setB(b+1)
        break;
      default:
        return false;
    }
  }
  return ( 
    <div>
      <p>{a}</p>
      <p>{b}</p>
      <p>{c}</p>
      <button onClick={()=>handleClick('a')}>+a</button>
      <button   onClick={()=>handleClick('b')}>+b</button>

    </div>
    
   );
}

export default MemoizeValue;

也可以返回DOM值

import React,{useState,useMemo} from 'react'
function MemoizeValue() {
  const [a,setA] = useState(0);
  const [b,setB] = useState(0);
  const [d,setD] = useState(0);
  const c = useMemo(()=>{
    return (
      <div>
        dom:
        {a+b}
      </div>
    )
  },[a,b]);
  const handleClick = (type)=>{
    switch(type){
      case 'a':
        setA(a+1)
        break;
      case 'b':
        setB(b+1)
        break;
      case 'd':
        setD(d+1)
        break;
      default:
        return false;
    }
  }
  return ( 
    <div>
      <p>{a}</p>
      <p>{b}</p>
      <p>{d}</p>
      <p>{c}</p>
      <button onClick={()=>handleClick('a')}>+a</button>
      <button   onClick={()=>handleClick('b')}>+b</button>
      <button   onClick={()=>handleClick('d')}>+d</button>

    </div>
    
   );
}

export default MemoizeValue;
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React Typewriter Hook是一个使用React Hooks来实现打字机效果的库。它可以帮助我们在React应用中轻松地实现打字机效果。 要使用React Typewriter Hook,我们首先需要通过npm来安装它,命令如下:npm install react-typewriter-hook。 使用React Typewriter Hook的核心代码包括引入React和useTypewriter钩子,并在组件中使用useTypewriter钩子来创建打字效果。例如,在一个名为Note的组件中,我们可以通过useTypewriter钩子传入一个字符串来实现打字效果。 具体使用React Typewriter Hook的例子可以在官方文档中查看。在使用时,我们只需要根据示例的用法将useTypewriter钩子应用在需要实现打字效果的地方即可。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [【分享创造】react-typewriter-hook: 用react hooks来实现打字机的效果](https://blog.csdn.net/weixin_33924312/article/details/88613110)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [React引入react-typewriter-hook实现打字效果](https://blog.csdn.net/AK852369/article/details/119819250)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [react-typewriter-hook:Use使用react钩子轻松输入效果](https://download.csdn.net/download/weixin_42131276/18402977)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值