您现在的位置是:网站首页> 编程资料编程资料
React hook超详细教程_React_
2023-05-24
439人已围观
简介 React hook超详细教程_React_
什么是hook
React Hook是React 16.8版本之后添加的新属性,用最简单的话来说,React Hook就是一些React提供的内置函数,这些函数可以让函数组件和类组件一样能够拥有组件状态(state)以及进行副作用(side effect)
但是不要什么业务都使用hook,请在合适的时候使用hook,否则会造成性能问题.(能不用的时候就不能,当遇到性能不好优化的时候,自然会想到使用它)
useState
它允许函数组件将自己的状态持久化到React运行时的某个地方,这样在组件每次重新渲染的时候都可以从这个地方拿到该状态,而且当该状态被更新的时候,组件也会重渲染。
//语法: import {useState} from "react" const [state, setState] = useState(initialState)//数组解构赋值 //useState接收一个initialState变量作为状态的初始值,返回值是一个数组。返回数组的第一个元素代表当前state的最新值,第二个元素是一个用来更新state的函数。state和setState这两个变量的命名是你自己取的 //state用于组件内部使用的数据 //setState函数用于修改state,当修改后会触发所有使用过state的地方重新取值(调用render) //可以用多个useState案例:
import React, { Component,useState } from 'react' export default function Box3() { const [first, setfirst] = useState(0) return ( {first}
) }
可以看到数据修改了并刷新了模板
useEffect
useEffect是用来使函数组件也可以进行副作用操作的。那么什么是副作用呢?
函数的副作用就是函数除了返回值外对外界环境造成的其它影响假如我们每次执行一个函数,该函数都会操作全局的一个变量,那么对全局变量的操作就是这个函数的副作用。而在React的世界里,我们的副作用大体可以分为两类,一类是调用浏览器的API,例如使用addEventListener来添加事件监听函数等,另外一类是发起获取服务器数据的请求,例如当用户组件挂载的时候去异步获取用户的信息等。
import {useEffect} from "react" useEffect(effect?=>clean, dependencies?) //useEffect的第一个参数effect是要执行的副作用函数,它可以是任意的用户自定义函数,用户可以在这个函数里面 操作一些浏览器的API或者和外部环境进行交互,网络请求等,这个函数会在每次组件渲染完成之后被调用 //useEffect可以有一个返回值,返回一个函数,系统在组件重新渲染之前调用它 //第二个参数dependencies来限制该副作用的执行条件 案例:组件销毁时清除计算器
import React,{useEffect,useState} from 'react' export default function Box1(props) { let [i,seti]=useState(0) useEffect(()=>{ console.log(i) let timer=setInterval(() => { seti(i+1) },1000); return ()=>{ clearInterval(timer) } }) return ( {i}
) }//父组件 import React,{useState} from 'react' import Box1 from './Box1' export default function Box2() { let [flag,setflag]=useState(true) return ( {flag&& } ) }useRef
useRef是用来在组件不同渲染之间共用一些数据的,它的作用和我们在类组件里面为this赋值是一样的。
语法
react import {useRef} from "react" const refObject = useRef(initialValue) //useRef接收initialValue作为初始值,它的返回值是一个ref对象,这个对象的.current属性就是该数据的最新值。使用useRef的一个最简单的情况就是在函数组件里面获取DOM对象的引用 案例:
import { useRef, useEffect } from 'react' import ReactDOM from 'react-dom' const AutoFocusInput = () => { const inputRef = useRef(null) useEffect(() => { // 组件挂载后自动聚焦 inputRef.current.focus() }, []) return ( ) } ReactDOM.render( , document.getElementById('root')) //在上面代码中inputRef其实就是一个{current: input节点}对象,只不过它可以保证在组件每次渲染的时候拿到的都是同一个对象。 useCallback
useCallback就是把我们在函数组件内部定义的函数保存起来,当组件重新渲染时还是使用之前的,就不会被重新定义一次
语法:
import {useCallback} from "react" const memoizedCallback = useCallback(callback, dependencies) //useCallback接收两个参数,第一个参数是需要被记住的函数,第二个参数是这个函数的dependencies,只有dependencies数组里面的元素的值发生变化时useCallback才会返回新定义的函数,否则useCallback都会返回之前定义的函数。 案例:
import React,{useCallback,useEffect,useState} from 'react' export default function Box7() { let [arr,setarr]=useState([{id:1,name:'ljy'},{id:2,name:'jack'},{id:3,name:'marry'}]) let fn=useCallback((index)=>{ console.log(index) },[]) useEffect(()=>{ console.log('fn变化了') },[fn]) return ( <>{arr.map(el=>{el.id}---{el.name}
)}> ) } useMemo
useMemo和useCallback的作用十分类似,只不过它允许你记住任何类型的变量(不只是函数)
import {useMemo} from "react" const memoizedValue = useMemo(() => valueNeededToBeMemoized, dependencies) //useMemo接收一个函数,该函数的返回值就是需要被记住的变量,当useMemo的第二个参数dependencies数组里面的元素的值没有发生变化的时候,memoizedValue使用的就是上一次的值。 案例:
import React, { useMemo } from 'react' import ReactDOM from 'react-dom' const RenderPrimes = ({ iterations, multiplier }) => { const primes = React.useMemo(() => calculatePrimes(iterations, multiplier), [ iterations, multiplier ]) return ( Primes! {primes} ) } ReactDOM.render( , document.getElementById('root')) //例子中calculatePrimes是用来计算素数的,因此每次调用它都需要消耗大量的计算资源。 为了提高组件渲染的性能,我们可以使用useMemo来记住计算的结果, 当iterations和multiplier保持不变的时候,我们就不需要重新执行calculatePrimes函数来重新计算了,直接使用上一次的结果即可。useContext
我们知道React中组件之间传递参数的方式是props,假如我们在父级组件中定义了某些状态,而这些状态需要在该组件深层次嵌套的子组件中被使用的话就需要将这些状态以props的形式层层传递,这就造成了props drilling的问题。为了解决这个问题,React允许我们使用Context来在父级组件和底下任意层次的子组件之间传递状态。在函数组件中我们可以使用useContext Hook来使用Context。
语法:
const value = useContext(MyContext) //useContext接收一个context对象为参数,该context对象是由React.createContext函数生成的。 useContext的返回值是当前context的值,这个值是由最邻近的来决定的。 一旦在某个组件里面使用了useContext这就相当于该组件订阅了这个context的变化, 当最近的 的context值发生变化时,使用到该context的子组件就会被触发重渲染,且它们会拿到context的最新值。
案例:
import React, { useContext, useState } from 'react' import ReactDOM from 'react-dom' //定义context const NumberContext = React.createContext() const NumberDisplay = () => { const [currentNumber, setCurrentNumber] = useContext(NumberContext) const handleCurrentNumberChange = () => { setCurrentNumber(Math.floor(Math.random() * 100)) } return ( <>Current number is: {currentNumber}> ) } const ParentComponent = () => { const [currentNumber, setCurrentNumber] = useState(100) return ( //这里填儿子组件,后面孙子组件就可以直接使用爷爷组件传递的值 ) } ReactDOM.render( , document.getElementById('root'))使用时避免无用渲染
如果一个函数组件使用了useContext(SomeContext)的话它就订阅了这个SomeContext的变化,这样当SomeContext.Provider的value发生变化的时候,这个组件就会被重新渲染。
这里有一个问题就是,我们可能会把很多不同的数据放在同一个context里面,而不同的子组件可能只关心这个context的某一部分数据,当context里面的任意值发生变化的时候,无论这些组件用不用到这些数据它们都会被重新渲染,这可能会造成一些性能问题.
解决方法:
1.拆分Context
这个方法是最被推荐的做法,和useState一样,我们可以将不需要同时改变的context拆分成不同的context,让它们的职责更加分明,这样子组件只会订阅那些它们需要订阅的context从而避免无用的重渲染。
import React, { useContext, useState } from 'react' import ExpensiveTree from 'somewhere/ExpensiveTree' import ReactDOM from 'react-dom' const ThemeContext = React.createContext() const ConfigurationContext = React.createContext() const ChildrenComponent = () => { const [themeContext] = useContext(ThemeContext) return ( ) } const App = () => { const [themeContext, setThemeContext] = useState({ color: 'red' }) const [configurationContext, setConfigurationContext] = useState({ showTips: false }) return ( ) } ReactDOM.render( , document.getElementById('root'))2.拆分组件,使用memo来优化消耗性能的组件
如果出于某些原因你不能拆分context,仍然可以通过将消耗性能的组件和父组件的其他部分分离开来,并且使用memo函数来优化消耗性能的组件
import React, { useContext, useState } from 'react' import ExpensiveTree from 'somewhere/ExpensiveTree' import ReactDOM from 'react-dom' const AppContext = React.createContext() const ExpensiveComponentWrapper = React.memo(({ theme }) => { return ( ) }) const ChildrenComponent = () => { const [appContext] = useContext(AppContext) const theme = appContext.theme return { ) } const App = () => { const [appContext, setAppContext] = useState({ theme: { color: 'red' }, configuration: { showTips: false }}) return ( ) } ReactDOM.render( , document.getElementById('root')) 3.不拆分组件,也可以使用useMemo来优化
import React, { useContext, useState, useMemo } from 'react' import ExpensiveTree from 'somewhere/ExpensiveTree' import ReactDOM from 'react-dom' const AppContext = React.createContext() const ChildrenComponent = () => { const [appContext] = useContext(AppContext) const theme = appContext.theme return useMemo(() => ( ), [theme] ) } const App = () => { const [appContext, setAppContext] = useState({ theme: { color: 'red' }, configuration: { showTips: false }}) return ( ) } Reac
相关内容
- 使用vant-uploader上传照片无法删除的解决_vue.js_
- Varlet组件实现一个丝滑的点击水波效果详解_javascript技巧_
- vant的Uploader 文件上传,图片数据回显问题_vue.js_
- 关于Vite不能使用require问题的解决方法_vue.js_
- Vue electron零基础使用教程_vue.js_
- vue el-switch初始值(默认值)不能正确显示状态问题及解决_vue.js_
- vue项目如何实现ip和localhost同时访问_vue.js_
- Vue自定义Form组件实现方法介绍_vue.js_
- vue项目的访问端口及其设置方式_vue.js_
- Vue项目设置可以局域网访问_vue.js_
点击排行
本栏推荐
