React Hooks的使用

useState

  • 使用useState可以让函数式组件也能拥有状态(state)
  • 语法: const [xxx, setXxx] = React.useState(initValue) initValue是初始值
  • useState()说明:
    参数: 第一次初始化指定的值在内部作缓存
    返回值: 包含2个元素的数组, 第1个为内部当前状态值, 第2个为更新状态值的函数
  • setXxx()2种写法:
// 1 . setXxx(newValue): 参数为非函数值, 直接指定新的状态值, 内部用其覆盖原来的状态值
const [count,setCount] = React.useState(0)
function add(){
    setCount(count+1)
}
复制代码
// 2 . 参数为函数, 接收原本的状态值, 返回新的状态值, 内部用其覆盖原来的状态值
const [count,setCount] = React.useState(0)
function add(){
    setCount(value=>value+1)
}
复制代码

useEffect

  • 使用useEffect,能让函数式组件完成类似生命周期的功能
语法和说明: 
        useEffect(() => { 
          // 在此可以执行任何带副作用操作
          return () => { // 在组件卸载前执行
            // 相当于componentWillUnmount
          }
        }, [stateValue]) 
        // 如果指定的是[], 回调函数只会在第一次render()后执行
        // 如果没有的话挂载和每次更新都会执行
复制代码
  • useEffect第一个参数的return后面是一个函数,该函数相当于componentWillUnmount
  • useEffect第二个参数不填的话,那么每次渲染都会执行,相当于componentDidUpdate
  • useEffect第二个参数是空数组的话,相当于componentDidMount
  • useEffect第二个参数可以指定某个属性变化了之后再执行
const [count, setcount] =  React.useState(0)
const [name, setname] =  React.useState('zxx')
React.useEffect(()=>{
	console.log('count变化了才执行,name变化不执行')
},[count])
复制代码

useLayoutEffect

  • 用法和useEffect一样,但是效果有略微的差别
  • useLayoutEffect的执行会先于useEffect,所以想要修改组件元素样式建议用useLayoutEffect

useContext

  • useContext可以帮助我们跨越组件层级直接传递变量,实现共享
  • 首先在父组件中
// 想要通过context传递两个数据
import React ,{useContext}from 'react'
const CountContext = React.createContext()  
const NameContext = React.createContext()  
export default function Father() {
  
  return (
    <div>
      <CountContext.Provider value={15}>
        <NameContext.Provider value={'sss'}>
        <Son/>
        </NameContext.Provider>
      </CountContext.Provider>
    </div>
  )
}
复制代码
  • 在后代组件中接受
function Son(){
   //useContext 的参数必须是 context 对象本身,没有的话就自己导入
  const countInfo = useContext(CountContext)
  const nameInfo = useContext(NameContext)
  return (
    <div>
      <h2>Header组件</h2>
      <p>{countInfo}</p>
      <p>{nameInfo}</p>
    </div>
  )
}
复制代码

useReducer

useReducer仅仅是useState的一种替代方案。如果state处理逻辑比较复杂,我们可以用useReducer来拆分

  • const [状态,dispatch] = useReducer(reducer,初始化状态的值)
import React ,{useReducer}from 'react'
// 第一步创建reducer,接受两个参数state和action
function reducer(state,action){
  switch (action.type) {
    case 'increment':
      return {...state,num:state.num+1}
    case 'decrement':
      return {...state,num:state.num-1}
    default:
      throw new Error();
  }
}
function Home(){
  // 使用useReducer
  const [state,dispatch] = useReducer(reducer,{num:0})
  return (
    <div>
      <h2>Header数据:{state.num}</h2>
      {/*派发action*/}
      <button onClick={()=>dispatch({type:'decrement'})}>-1</button>
      <button onClick={()=>dispatch({type:'increment'})}>+1</button>
    </div>
  )
}
function About(){
  const [state,dispatch] = useReducer(reducer,{num:25})
  return(
    <>
      <h2>About数据:{state.num}</h2>
      <button onClick={()=>dispatch({type:'decrement'})}>-1</button>
      <button onClick={()=>dispatch({type:'increment'})}>+1</button>
    </>

  )
}
export default function App() {
  return (
    <div>
      <Home></Home>
      <About></About>
    </div>
  )
}
复制代码

useCallback

useCallback实际的目的是为了进行性能优化

  • useCallback会返回一个函数的memoized值
  • 在依赖不变的情况下,多次定义的时候,返回的值是相同的

搭配memo使用:当不使用memo的时候,父组件重新渲染,子组件必定重新渲染,所以使用memo(子组件),可以避免这个情况发生

import React,{useState,memo,useCallback} from 'react'
// 没使用useCallback的时候,每次增加或者减少,所有的组件都会重新渲染
function Home(props){
  console.log("HOME渲染了");
  return(
    <div>
      <p>Home</p>
      <button onClick={()=>props.handle()}>减小</button>
    </div>
  )
}
function About(props){
  console.log("ABOUT渲染了");
  return(
    <div>
      <p>About</p>
      <button onClick={()=>props.handle()}>增加</button>
    </div>
  )
}
const MemoHome = memo(Home)
const MemoAbout = memo(About)
export default function App() {
  console.log("APP渲染了");
  const [numState,setNum] = useState(12)
  const [ageState,setAge] = useState(2)
   // 只有ageState变化时候,sub这个函数才会变化
  const sub = useCallback(
    () => {
      setAge(ageState-1)
    },[ageState],
  )
  // 只有numState变化时候,add这个函数才会变化
  const add = useCallback(
    () => {
      setNum(numState+2)
    },[numState],
  )
  return (
    <div>
      <p>num:{numState}</p>
      <p>age:{ageState}</p>
      <hr />
      <MemoHome handle={sub}/>
      <MemoAbout handle={add}/>
    </div>
  )
复制代码

使用场景:将一个组件中的函数,传递给子组件进行回调使用时,使用useCallback对函数进行处理

useMemo

useCallback实际的目的也是为了进行性能优化

  • 使用场景一:
// 每次点击按钮Home组件都会重新渲染,因为App组件重新渲染导致person的内存地址变化
import React, { memo,useState } from 'react'
const Home = memo((props)=>{
  console.log('Home渲染');
  return (
    <h2>name:{props.person.name}--age:{props.person.age}</h2>
  )
})
export default function App() {
  const [show, setshow] = useState(false)
  let person = {name:'zx',age:15}
  return (
    <div>
      <Home person={person}/>
      <button onClick={()=>setshow(!show)}>changeShow</button>
    </div>
  )
}
复制代码
  • 场景一解决方法:
import React, { memo,useMemo,useState} from 'react'
const Home = memo((props)=>{
  console.log('Home渲染');
  return (
    <h2>name:{props.person.name}--age:{props.person.age}</h2>
  )
})
export default function App() {
  const [show, setshow] = useState(false)
  let person = useMemo(() => {
    return {name:'zx',age:15}
  }, [])
  return (
    <div>
      <Home person={person}/>
      <button onClick={()=>setshow(!show)}>changeShow</button>
    </div>
  )
}
复制代码
  • 使用场景二
  • 如果没有使用useMemo,返回函数的时候,每次App重新渲染都会让getData这个函数重新调用
import React,{useMemo, useState} from 'react'
function getData(){
  console.log('getData被调用了');
  let data = 0
  for(let i=0;i<1000;i++){
    data+=i
  }
  return data
}
export default function App() {
  console.log('App组件被渲染了');
  const [numState,setNum] = useState(10)
  const [ageState] = useState(55)
  // const data = getData()
  // 通过useMemo可以使得getData不会被重复调用
  const data = useMemo(()=>{
    return getData()
  },[])
  return (
    <div>
      <h2>num:{numState}</h2>
      <h2>age:{ageState}</h2>
      {/* 修改numState的时候,getData会被重新调用 */}
      <button onClick={()=>{setNum(numState+1)}}>修改num</button>
      <h2>data:{data}</h2>
    </div>
  )
}
复制代码

useRef

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享