react hooks使用总结

useState

function App() {
  const [name,setName] = useState("name");
  return <div>
      <p>{name}</p>
      <button onClick={()=>{
        setName("显示名称");
        console.log(name);
      }}>显示全称</button>
  </div>;
}

useState注意项

-1. useState的set方法是异步方法,需要组件内部更新之后state才是更新后的值
-2. setState方法不具有类组件的setState合并多个state的作用,在更新时,其他值一同更新

function App() {
  const [data,setData] = useState({name: 'test', age: 10});
  return <div>
      <p>{data.name}</p>
      <button onClick={()=>{
        setName({...data, name: "hello"});
      }}>显示全称</button>
  </div>;
}

-3. 同一个组件内可以使用多个useState

useEffect

Effect翻译成专业术语称之为副作用。什么是副作用呢?网络请求、DOM操作都是副作用的一种,useEffect就是专门用来处理副作用的。在类组件中副作用通常在componentDid-Mount和componentDidUpdate中进行处理,而 useEffect就相当于componentDidMount、com-ponentDidUpdate和componentWillUnmount的集合体。useEffect包括两个参数执行时的回调函数和依赖参数,并且回调函数还有一个返回函数

import React, { useState, useEffect } from 'react';
function Course(){
    const [course,setCourse] = useState("English");
    const [num,setNum] = useState(1);
    useEffect(()=>{
      console.log("组件挂在或更新");
      return ()=>{
          console.log("清理更新前的一些全局内容,或检测组件即将卸载");
      }
    },[num]);
    console.log(1);
    return <div>
          <div>
            选择课程:
            <select
              value = {course}
              onChange = {({target})=>{
                  setCourse(target.value);
              }}
            >
                <option value="Math">Math</option>
                <option value="English">English</option>
            </select>
          </div>
          <div>
            购买数量:<input 
              type="number" 
              value={num}
              min={1}
              onChange={({target})=>{
                setNum(target.value);
              }}
            />
          </div>
    </div> 
}
function App() {
  const [show,setShow] = useState(true)
  return <div>
    {show?<Course />:""}    
    <button onClick={()=>{
        setShow(!show);
    }}>{show?"隐藏课程":"显示课程"}</button>
  </div>;
}

依赖参数,其本身是一个数组,在数组中放入要依赖的数据,当这些数据有更新时,就会执行回调函数。整个组件的生命周期过程如下:
组件挂载→执行副作用(回调函数)→组件更新→执行清理函数(返还函数)→执行副作用(回调函数)→组件准备卸载→执行清理函数(返还函数)→组件卸载。
上文讲过 useEffect是componentDidMount、componentDidUpdate 和componentWillUnmount
的集合体,如果单纯只想要在挂载后、更新后、卸载前其中之一的阶段执行,可以参考以下操作。
①componentDidMount。如果只想要在挂载后执行,可以把依赖参数置为空,这样在更新时就不会执行该副作用了。
②componentWilUnmount。如果只想要在卸载前执行,同样把依赖参数置为空,该副作用的返还函数就会在卸载前执行。
③componentDidUpdate。只检测更新相对比较麻烦,需要区分更新还是挂载需要检测依赖数据和初始值是否一致,如果当前的数据和初始数据保持一致就说明是挂载阶段,当然安全起见应和上一次的值进行对比,若当前的依赖数据和上一次的依赖数据完全一样,则说明组件没有更新。这种情况需要借助useRef的原因在于ref如果和数据绑定的话,数据更新时ref并不会自动更新,这样就可以获取到更新前数据的值。在下例中,可以看到useEffect模拟的各个阶段,当然也可以看到一个组件中可以拥有多个 useEffect。

function Course(){
    const [course,setCourse] = useState("English");
    const [num,setNum] = useState(1);
    let prevCourse = useRef(course);
    let prevNum = useRef(num);
    useEffect(()=>{
        console.log("组件挂在阶段");
        return ()=>{
          console.log("组件卸载之前");
        }
    },[]);//一定注意依赖参数传入一个空数组,不传的话组件的任何更新都会调用该副作用
    useEffect(()=>{
        if(course != prevCourse.current
        || num != prevNum.current){
          // 如果当前值和上一次值不一样则代表组件又更新
          console.log("组件更新");
          // 这里注意 ref 不会自动更新,需要我们手动进行更新
          prevCourse.current = course;
          prevNum.current = num;
        }
    },[course,num]); 
    return <div>
          <div>
            选择课程:
            <select
              value = {course}
              onChange = {({target})=>{
                  setCourse(target.value);
              }}
            >
                <option value="English">English</option>
                <option value="Math">Math</option>
            </select>
          </div>
          <div>
            购买数量:<input 
              type="number" 
              value={num}
              min={1}
              onChange={({target})=>{
                setNum(target.value);
              }}
            />
          </div>
    </div> 
}
function App() {
  const [show,setShow] = useState(true)
  return <div>
    {show?<Course />:""}    
    <button onClick={()=>{
        setShow(!show);
    }}>{show?"隐藏课程":"显示课程"}</button>
  </div>;
}

useRef

useRef可以看成是 createRef 的Hook 版。使用时先把 ref存入变量,然后变量和DOM节点绑定,使用时通过ref的current属性来获取DOM节点

function App() {
  let elP = useRef();
  return <div>
      <p ref={elP}>ref的实例值</p>
      <button onClick={()=>{
          console.log(elP.current);
      }}>获取ref</button>
  </div>;
}

useReducer

通常使用 useState和 useEffect基本能满足函数组件状态管理的需求,但也难免会有更加复杂的场景。我们现在虚拟一个计算器组件,需要实现计算器的加减乘除等操作,显然这些方法如果都分散定义,会导致状态管理混乱。这时我们想到了Redux状态管理的思想——单向数据流。
useReducer接受三个参数,第一个是处理状态更新的reducer,第二个参数是状态的初始值,第三个是状态初始函数

const [state, dispatch] = useReducer(reducer, initialArg, init);

状态更新函数

function reducer(state, action) {
  switch (action.type) {
  case 'increment':
  return {count: state.count + 1};
  case 'decrement':
  return {count: state.count - 1};
  default:
  throw new Error();
}

定义初始化状态值

const initialArg = {count: 0};

一般情况下,定义了这两个参数后就可以使用useReducer了

function Calculator() {
  const [state, dispatch] = useReducer (reducer, initialArg);
  return (
  <View>
    <Text>(state.count)</Text>
    <View onClick={() => dispatch({type:'increment'})}>+</View>
    <View onClick={() => dispatch ({type: 'decrement'})}>-</View>
  </View>
  )
}

useCallback

在函数组件中,定义函数很常见,但因为函数组件会随着状态值的更新而重新渲染,函数中定义的函数会频繁定义,这是非常影响性能的。Hooks提供了useCallback方法用于记忆函数。
useCallback接收两个参数,第一个参数是一个函数,第二个参数是一个数组,用于指定被记忆函数更新所依赖的值。使用示例如下:

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

第一个参数为需要记忆的函数,如事件处理回调函数。第二个参数如果指定为空数组,则被记忆的函数在组件初始化创建后永远保持不变直至组件卸载。回调函数使用 useCallback优化后是这样的:

function Demo() {
  const handleClick = useCallback(() =>{console.log('clicked')}, [])
  return (
	  <View onClick={handleClick}>view</View>
  )
}

请注意,如果记忆函数中使用了组件的状态或者props值,则useCallback第二个参数需要指明对应的依赖,例如:

function Demo({id}) {
  const [count ,setCount] = useState (0);
  const handleClick = useCallback(() => {
    console.log('clicked')
    console.log(id, count)
    setCount(count + 1)
    //或者使用回调函数形式
    //setCount(c => c + 1)
  }, [id, count])
  return (
  <View onClick=(handleClick)>setCount</View>
  )
}

useMemo

useCallback 用于记忆函数,useMemo用于记忆值,并且通常这个值是经过比较消
生能的计算得到的。useMemo接收两个参数:第一个参数用于处理耗时计算并返回需要记录的值;第二个参数为数组,用于指定被记忆函数更新所依赖的值

function Demo({list}) {
  const memoList = useMemo(() => {
    //doSomeThing表示性能计算函数
    return doSomeThing (list)
  }, [list]);
  return (
  <View>{memoList}</View>
  )
}

自定义hook

可以自定义Hooks,可将组件中可复用逻辑提取出来,自定义的Hooks是个函数, 名称以“use”开头,函数内部可以调用其他Hooks,下面简单写个返回滚动条位置的hook

function useScrollY(){
  let [scrollY,setScrollY] = useState(0);
  function scroll(){
      setScrollY(window.scrollY);
  }
  useEffect(()=>{
    window.addEventListener("scroll",scroll);
    return ()=>{
      window.removeEventListener("scroll",scroll);
    }
  },[]);
  return scrollY;
}
function App() {
  let scrollY = useScrollY();
  return <div style={{
    border: "1px solid #000",
    height: "1500px"
  }}>
      <p style={{
        position: "fixed",
        left: 0,
        top: 0
      }}>当前滚动条位置是:{scrollY}</p>
  </div>;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值