Reack Hooks

115 阅读4分钟

useState组件内部状态管理

import {useState} from 'react'
const App = () => { 
   const [n, setN] = React.useState(0); 
   return ( 
      <div> <p>n:{n}</p> 
      <button onClick={()=>setN(n+1)}>+1</button> 
      </div> 
   )    
} 

useState hook返回两个值,第一个值是获取当前的状态值,第二个值是修改状态值的方法。useState是一个一集函数,能够记住状态的值。

useEffect

import React, { useState, useEffect } from 'react';
import axios from 'axios';
 
function App() {
  const [data, setData] = useState({ hits: [] });
 
  useEffect(async () => {
    const result = await axios(
      'http://localhost/api/v1/search?query=redux',
    );
 
    setData(result.data);
    
    const timer = setInterval(()=>{
       console.log("111")
    },1000);
    
    return () => {
        timer = null;
    }
    
  },[]);
 
  return (
    <ul>
      {data.hits.map(item => (
        <li key={item.objectID}>
          <a href={item.url}>{item.title}</a>
        </li>
      ))}
    </ul>
  );
}x
  • useEffect第二个参数是一个数组,当是一个空数组时,则只会在dom更新之后执行一次useEffect函数,当不是一个空数组的时候,每次依赖改变时,useEffect里定义的函数会再次被执行。
  • useEffect的返回函数会在组件销毁的时候执行,如一些定时器就可以在这里进行删除。如果useEffect有依赖的情况下,会在每次更新的时候,销毁函数也会被执行。
  • useEffect支持写多个,不同处理逻辑放在多个useEffect里面,结构会更加清晰

useLayoutEffect

useLayoutEffect(async () => {
    const result = await axios(
      'http://localhost/api/v1/search?query=redux',
    );
 
    setData(result.data);
    
    const timer = setInterval(()=>{
       console.log("111")
    },1000);
    
    return () => {
        timer = null;
    }
    
  },[]);
  • useLayoutEffect和useEffect使用方法一致,不同的是,useEffect会在页面渲染完成之后再执行,useLayoutEffect仅在dom完成之后马上调用同步的代码,会阻塞页面渲染。dom完成只是内存中已经存在对应dom结构,但是还没有渲染到页面上

  • 因为useEffect会在页面渲染完成之后再去执行,如果useEffect有操作dom或者动画等操作,引起回流重绘,可能会引起页面抖动的情况,所以为了避免这种情况可以使用useLayoutEffect,但是一般情况下,使用useEffect就可以。

useCallback

const A = ({ onClick }) => {
  // A 父组件的count变化时,A组件仍旧会不断的re-render
  console.log("case2: render_A");
  return <button onClick={onClick}>A组件+count</button>;
};

export default function Case2() {
  const [count, setCount] = useState(0);
  
  const onClick = useCallback(() => {
    setCount((count) => count + 1);
  }, [count]);

  return (
    <>
      <p>count:{count}</p>
      <A onClick={onClick} />
    </>
  );
}

useCallback是记忆函数,当组件中的某些状态被改变的时候,如果没有使用useCallback,那么所有的函数都会被重新创建,但是有时候某些函数并不需要重新被渲染,所以就用到了useCallback,useCallback第二人参数为一个数组依赖,当为空的时候,onClick函数会一直被缓存,不会被重新渲染,只有当依赖改变的时候,才会重新创建。

useMemo

export default () => {
	let [isChild, setChild] = useState(false);
	return (
		<div>
		      <Child isChild={isChild} name="child" />
	              <button onClick={() => setChild(!isChild)}>改变Child</button>
		</div>
	);
}
 
let Child = (props) => {
	let getRichChild = () => {
		console.log('rich child');
		return 'rich child';
	}
 
	let richChild = useMemo(() => {
		//执行相应的函数
		return getRichChild();
	}, [props.name]);
 
	return (
		<div>
			isChild: {props.isChild ? 'true' : 'false'}<br />
			{richChild}
		</div>
	);
}

useMemo也是一个记忆函数,可以完全代替useCallback函数,useCallback不会执行第一个参数函数,而是直接将函数返回给你,但是useMemo会执行它的第一个函数参数,并讲执行结果返回给你。useMemo的主要所用是执行逻辑,只有在某些依赖改变的时候,去计算对应的逻辑,然后将结果进行返回。

useRef

const RenderCounter = () => {
  const counter = useRef(0);
  
  // counter.current的值可能增加不止一次
  counter.current = counter.current + 1;
  
  return (
    <h1>`The component has been re-rendered ${counter.current} times`</h1>
  );
}
  • 函数组件中useRef和createRef使用方法一致。

  • useRef与createRef最大的不同是,createRef每次重新渲染的时候都会创建一个新的ref对象,useRef第一次渲染创建一个对象之后,再重新渲染的时候,如果发现这个对象已经创建过就不会再创建第二次,性能会好一些,所以useRef一个重要的作用就是保存变量。

useContext

useContext在createContext的基础上,只是对子组件的使用方式进行了简化,两种使用方式比较如下:

//context消费者原来的方式
function Content() {
  return (
        <UserContext.Consumer>
          {user => (
            <ProfilePage user={user} theme={theme} />
          )}
        </UserContext.Consumer>
  );
}

//context消费者使用useContext的方式
function Counter(){
	const count = useContext(CountContext) //得到count
	return (<h2>{count}</h2>)
}

useReducer

const initstate = 0;
const reducer = (state,action)=> {
        if(action === 'add'){
            return state + 1;
        }
        return state;
    };
export default function ReducerDemo() {
    const [ç, dispath] = useReducer(reducer, initstate);
    return (
        <div>
            <h1 className="title">{count}</h1>
            <button className="btn is-primary"
                onClick={()=> dispath('add')}
                >Increment</button>
        </div>
    )
}

useReducer最大的作用的将ui和数据状态管理分离开,initstate是初始化状态,reducer对状态进行管理,组件中内部使用直接使用count获取状态,使用dispath调用触发状态的修改。

自定义hook,

自定义hook,就是将某些组件中复杂的逻辑抽离封装成为一个函数,为什么一定要用use开头呢?因为不使用use,函数中有些hook就无法使用。

const useList = () => {
  const [state, setState] = useState(initialState);
  const deleteLi = (index) => {
    setState((state) => {
      const newState = JSON.parse(JSON.stringify(state));
      newState.splice(index, 1);
      return newState;
    });
  };
  return { state, setState, deleteLi };//返回查、改、删
};