react Hooks基础

167 阅读7分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路

一 hooks

1.是什么

  是钩子,是React 16.8的新特性

2.为什么

  可以让函数组件使用state及其他的React特性,如生命周期等

3.怎么用

import React,{useState} from 'react'
const Func = () => {
  const [color,setColor]=useState('red')
  return (
      <div>
        <button onClick={()=>setColor('green')}></button>
         {color}
      </div>
  )

};
export default Func

4.好处

 1 组件的状态逻辑复用 
 
 2 避免了class 组件自身的问题

5.场景

 在使用函数组件时需要状态时或给函数选择执行时机时使用
 

6.原理

 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数

二 useState

1.为什么

 为函数组件提供状态

2.怎么用

  1. 导入 useState 函数

  2. 调用 useState 函数,传入初始值,返回状态修改状态的函数

  3. 使用

    1. 在 JSX 中展示状态

    2. 特定的时机调用修改状态的函数来改状态

import React,{useState} from 'react'
const Func = () => {
  const [color,setColor]=useState('red')
  return (
      <div>
        <button onClick={()=>setColor('green')}></button>
         {color}
      </div>
  )

};
export default Func

3.注意

(1)参数:状态初始值。比如,传入 0 表示该状态的初始值为 0

(2)此处的状态可以是任意值(比如,数值、字符串等),而 class 组件中的 state 必须是对象

(3)返回值:数组,包含两个值:1 状态值(state) 2 修改该状态的函数(setState)

(4)修改该状态的函数中参数

/1/值

const [count, setCount] = useState(0)

/2/回调函数

 需要return,注意箭头函数内部形参的使用,给状态值多次修改会出现覆盖的效果

image.png

4.更新机制

(1)状态更新,整个组件的逻辑重新运行一次;

(2)useState只会在组件第一次渲染时使用状态的初值,随后都会使用状态的最新值

(3)useState 这个 Hook 就是用来管理 state 的,它可以让函数组件具有维持状态的能力。也就是说,在一个函数组件的多次渲染之间,这个 state 是共享的。

三 useEffect

0.什么是副作用

对于react组件来说,除了渲染UI之外的其他操作,都可以称之为副作用

2.为什么

处理函数组件中的副作用

3.执行时机

render工作完成之后,执行Effect;

如果定义了多个,则顺序执行

4.怎么用

(1)参数

参数1,副作用函数

参数2,执行副作用函数的依赖项,他决定了什么时机执行参数1

使用分析

  • 1.若不带第二个参数。执行时机,初次执行以及每次更新之后都会执行,模拟componentDidMount+componentDidUpdate

  • 2.若带第二个参数。参数是空数组,初始执行,模拟componentDidMount

  • 3.若带第二个参数。并指定依赖项。执行时机(1)初始执行(2)依赖项的值发生变化时执行一次,模拟componentDidMount+指定依赖项的监听

  • 4.依赖项为空,没有具体的副作用函数,有副作用函数的清理函数。将要卸载组件前,模拟componentWillUnMount

(2)函数

effect只能是同步函数,不能使用async

(3)案例1:发请求

import React,{ useEffect,useState } from 'react'
import axios from 'axios'
const Func = () => {
  const [count,setCount]=useState(0)
  const [list,setList]=useState([])
  useEffect(()=>{
    console.log('1');
    axios
    .get('****').then((res)=>{
      console.log('88',res);
      setList(res.data.result)
    })
  },[])
  useEffect(()=>{
    console.log('2');
  },[count])
  console.log(list,'x');
  return <div>
    ====={count}==========
    <ul>
      {list.map((item)=>{
        return <li key={item.id}>{item.name}</li>
      })}
    </ul>
    <button onClick={()=>setCount(count+1)}>按钮</button>
</div>
};
export default Func

(3)案例2:全选,单选互相影响,持久化存储

要求:

MyFooter需要传输list列表数据,changeAll全选,flag单个状态 GoodsItem需要传输每一项列表信息item及给每一项绑定change事件changeHandle

思路展示:

image.png

效果展示:

image.png

代码展示:

import React, { useEffect, useState } from 'react'
import MyHeader from './MyHeader'
import MyFooter from './MyFooter'
import GoodsItem from './GoodsItem'

import 'bootstrap/dist/css/bootstrap.css'
import './shop.css'
export default function Shop() {
  const arr = [
    {
    {
      id: 10,
      goods_name:
        'Semir森马卫衣女冬装2019新款可爱甜美大撞色小清新连帽薄绒女士套头衫',
      goods_img: 'https://www.escook.cn/vuebase/pics/10.png',
      goods_price: 153,
      goods_count: 1,
      goods_state: false,
    },
    ...
  ]

  const [list, setList] = useState(
    JSON.parse(localStorage.getItem('list')) || arr
  )
  const [flag, setFlag] = useState(false)
  /* 全选的切换显示 */
  const changeAll = (flag) => {
    /* 更改全选状态值 */
    setFlag(flag)
    /* 2-实现全选 */
    // list.forEach((item) => {
    //   item.goods_state = flag
    // })
    setList(() => {
      var newList = list.map((item) => {
        return {
          ...item,
          goods_state: flag,
        }
      })
      //3- 做持久化
      localStorage.setItem('list', JSON.stringify(newList))

      return newList
    })
  }
  /* 4-实现点个状态改变 */
  const changeHandle = (id, state) => {
    console.log(id, state, 8888)
    // 更新当前状态
    // var itemObj = list.find((item) => item.id === id)
    // console.log(itemObj, 87)
    // itemObj.goods_state = state
    setList(() => {
      var newList = list.map((item) => {
        if (item.id === id) {
          return {
            ...item,
            goods_state: state,
          }
        } else {
          return { ...item }
        }
      })

      return newList
    })
  }
  useEffect(() => {
    // 循环 判断每一项的状态是不是都是true或者false===实现反选
    var bool = list.every((item) => item.goods_state)
    /* 更改全选状态值 */
    setFlag(bool)
  }, [list])

  return (
    <div className="app">
      <MyHeader>购物车</MyHeader>
      {list.map((item) => {
        return (
          <GoodsItem
            key={item.id}
            {...item}
            changeHandle={changeHandle}
          ></GoodsItem>
        )
      })}
      <MyFooter list={list} changeAll={changeAll} flag={flag}></MyFooter>
    </div>
  )
}

(4) 副作用函数的返回值-清除副作用

格式1:

useEffect(() => {
  // 副作用函数的内容

  return 副作用函数的返回值
}, [])

格式2:

useEffect(() => {
  // 副作用函数的内容

  return ()=>{ /* 做清理工作*/ } // 清理函数
}, [])

清理函数的执行时机

清理函数会在组件卸载时以及下一次副作用函数调用之前执行

错误实例

import React, { useEffect, useState } from 'react'
import ReactDom from 'react-dom'

function Com1 () {
  useEffect(() => {
    window.addEventListener('mousemove', (e) => {
      console.log(e.pageX, e.pageY)
    })
  }, [])
  return <div>子组件</div>
}
export default function App () {
  const [isShow, setIsShow] = useState(true)
  return (
    <div>
      {isShow && <Com1 />}
      <button onClick={() => setIsShow(!isShow)}>切换</button>
    </div>
  )
}
ReactDom.render(<App />, document.getElementById('root'))

正确实例

import React, { useEffect, useState } from 'react'
import ReactDom from 'react-dom'

function Com1 () {
  useEffect(() => {
    const fn = (e) => {
      console.log(e.pageX, e.pageY)
    }
+    window.addEventListener('mousemove', fn)

+    return () => {
      window.removeEventListener('mousemove', fn)
      console.log('组件删除了')
    }
  }, [])
  return <div>子组件</div>
}
export default function App () {
  const [isShow, setIsShow] = useState(true)
  return (
    <div>
      {isShow && <Com1 />}
      <button onClick={() => setIsShow(!isShow)}>切换</button>
    </div>
  )
}
ReactDom.render(<App />, document.getElementById('root'))

四 自定义hooks

1.是什么

  • 自定义 Hooks 是一个函数,约定函数名称必须以 use 开头,React 就是通过函数名称是否以 use 开头来判断是不是 Hooks
  • Hooks 只能在函数组件中或其他自定义 Hooks 中使用,否则,会报错!
  • 自定义 Hooks 用来提取组件的状态逻辑,根据不同功能可以有不同的参数和返回值(就像使用普通函数一样)

2.为什么

自定义 Hooks 针对不同组件实现不同状态逻辑复用。

3.场景

将组件状态逻辑提取到可重用的函数(自定义 Hooks)中,实现状态逻辑复用。

4.怎么用

Bpp.js

// useMouse.js
import { useEffect, useState } from 'react'
export default function useMouse() {
  // 逻辑处理
  const [position, setPosition] = useState({
    x: 0,
    y: 0,
  })

  useEffect(() => {
    const move = (e) => {
      setPosition({
        x: e.pageX,
        y: e.pageY,
      })
    }
    document.addEventListener('mousemove', move)
    return () => {
      document.removeEventListener('mousemove', move)
    }
  }, [])
  
  // 返回状态
  return position
}

App.js

import React from 'react'
import useMouse from './Bpp'
function Com () {
  const position = useMouse()
  console.log(position);
    return <div>
      {position.x}
      <br/>
      {position.y}
    </div>
}
export default Com

五 useRef

1.是什么

使用场景:在 React 中进行 DOM 操作时,用来获取 DOM

作用:返回一个带有 current 属性的可变对象,通过该对象就可以进行 DOM 操作了。

3.怎么用

  • 参数:在获取 DOM 时,一般都设置为 null
  • 返回值:包含 current 属性的对象。
  • 注意:只要在 React 中进行 DOM 操作,都可以通过 useRef Hook 来获取 DOM(比如,获取 DOM 的宽高等)。
  • 注意:useRef不仅仅可以用于操作DOM,还可以操作组件

简单使用

// 1. 导入 useRef
import React, { useRef } from 'react'

const Func = () => {
    // 2. 调用useRef(初值),得到引用对象
  // 3. 把引用对象设置ref 给任意的组件/元素
  // 4. 通过引用对象.current 获取 组件/元素
  const refTxt = useRef(null)
  console.log(refTxt)
  const click = () => {
    console.log(refTxt.current)
  }
  return <div>
        useRef, <input ref={refTxt} />
      <button onClick={click}>点击,获取input中的值</button> 
</div>
};
export default Func

7.场景,定时器

使用useEffect开启定时器会导致每次变化都开启一个新定时器,过度浪费性能,使用useRef则不同

import React,{useEffect,useState,useRef} from 'react'

const Func = () => {
  const [count,setCount]=useState(5)
  const [flag,setFlag]=useState(false)
  const timeCount=useRef(null)
 const btn=()=>{
  setFlag(true)
      timeCount.current=setInterval(()=>{
          setCount((count)=>{     
            return count-1
    }) 
      },1000)   
  }
  // 清除
  useEffect(()=>{
    if(count===0){
      clearInterval(timeCount.current)
    }      
  },[count])
  return <div>
    <button ref={timeCount} disabled={flag} onClick={btn}>按钮</button>
==={count}
</div>
};
export default Func

使用自定义hooks拆分

import React,{useEffect,useState,useRef} from 'react'

const useTime = () => {
  const [count,setCount]=useState(5)
  const [flag,setFlag]=useState(false)
  const timeCount=useRef(null)
 const btn=()=>{
  setFlag(true)
      timeCount.current=setInterval(()=>{
          setCount((count)=>{     
            return count-1
    }) 
      },1000)   
  }
  // 清除
  useEffect(()=>{
    if(count===0){
      clearInterval(timeCount.current)
      setFlag(false)
    }      
  },[count])
  return { count,btn,flag }
};
export default useTime
import React from 'react'
import useTime from './chaifen';
const Func = () => {
  const { count,btn,flag}=useTime()
  return <div>
    <button disabled={flag} onClick={btn}>按钮</button>=={count}
</div>
};
export default Func

六 useContext

1.是什么

 全局状态,类似于后代传参

3.怎么用

  • 导入并调用createContext方法,得到Context对象,导出
  • 使用 Provider 组件包裹根组件,并通过 value 属性提供要共享的数据
  • 在任意后代组件中,如果希望获取公共数据:导入useContext;调用useContext(第一步中导出的context) 得到value的值

实例

import React,{useState,createContext} from 'react'
import Son from './son'
export const Context = createContext()
const Func = () => {
  const [color,setColor]=useState('red')
  return (
    <Context.Provider value={ color }>
      <div>
        <button onClick={()=>setColor('green')}>按钮</button>
     <Son></Son>
      </div>
    </Context.Provider>
  )

};
export default Func

import React, { useContext } from 'react'
import { Context } from './App'
const CC = () => {
    const colo = useContext(Context)
    return ( <div>=son=={colo} </div>)
}
export default CC