react hooks学习

172 阅读3分钟

useState + useEffect

语法:

const [state, setState] = useState(initialState);

useEffect(() => {},deps)
function App() {
  const [width, setWidth] = useState(window.innerWidth);
  const [height, setHeight] = useState(window.innerHeight);

  const handleWindowResize = () => {
    setWidth(window.innerWidth);
    setHeight(window.innerHeight);
  };

  useEffect(() => {
    window.addEventListener('resize', handleWindowResize);
    return () => window.removeEventListener('resize', handleWindowResize); //如果你的 effect 返回一个函数,React 将会在执行清除操作时调用它
  },[]);
  
  
 // useCallback(() => {}, []);
 // useMemo(() => {}, []);

  // 三者中都有第二个参数,若第二个参数代表的依赖项发生变化则重新渲染,不执行则不渲染更新。
  // useEffect在dom改变之后触发。
  // useMeno在dom改变之前触发;父传方法给子时,子随着父的改变渲染多次,useMeno会将这些方法缓存起来,当第二个参数改变时才改变;它返回一个值;(不要在这个useMemo函数内部执行与渲染无关的操作,诸如副作用这类的操作属于 useEffect 的适用范畴,而不是 useMemo)。
  // useCallBack类似于useMeno,但如果传入props包含函数时,传递的函数即使内容一样还是会重新渲染,于是引入了useCallBack将props里面的函数也缓存起来;它返回一个函数,子组件一般配合meno使用。

  return (
    <>
    <div className="App">
      <header className="App-header">
        <p>width: { width }</p>
        <p>height: { height }</p>
      </header>
    </div>
    </>
  );
}

useMemo+useCallBack+memo性能优化

import { memo, useCallback, useMemo, useState } from "react"

const Son = memo(({ useInfo, clickChange }) => {
  console.log('Son render')
  return (
    <>
      <div>
      Sonname: {useInfo.name}
      <hr />
      Sonage: {useInfo.age}
      </div>
    </>
  )
})

const Parent = () => {
  const [name, setName] = useState('react hooks');
  const [count, setCount] = useState(0);
  // useMemo缓存数据
  const useInfo = useMemo(() => {
    return {name, age: 18};
  }, [name])

  // useCallBack缓存函数
  const clickChange = useCallback(() => {
    console.log('clickChange')
  }, [])

  console.log('Parent render')
  return (
    <>
      <Son useInfo={useInfo} clickChange={clickChange} />
      <button onClick={() => setCount(count + 1)}>Parentclick</button>
    </>
  )
}

export default Parent;

useContext

语法:

const context = React.createContext(null);
const contextData = useContext(context);

const themes = {
  light: {
    foreground: "#000000",
    background: "#eeeeee"
  },
  dark: {
    foreground: "#ffffff",
    background: "#222222"
  }
};

const ThemesContext = React.createContext(themes.light); //设置light为初始值
function App() {
  return (
    <>
    <div className="App">
      <header className="App-header">
        <ThemesContext.Provider value={themes.dark}>
          <MiddleComp />
        </ThemesContext.Provider>
      </header>
    </div>
    </>
  );
}
function MiddleComp() {
  return (
    <Son />
  )
}

function Son() {
  const theme = useContext(ThemesContext);
  return (
    <button style={{ background: theme.background, color: theme.foreground }}>
      I am styled by theme context!
    </button>
 )
}

useReducer

语法:

const [state, dispatch] = useReducer(reducer, { count: initialCount});
const reducer = (state: { count: number; }, action: { type: string; payload?: any; }) => {
  switch(action.type) {
    case 'increase':
      return {count: state.count + 1};
    case 'decrease':
      return {count: state.count - 1};
    case 'reset':
      return {count: action.payload};
    default:
      throw new Error();
  }
};

const Counter = ({initialCount} : any) => {
  const [state, dispatch] = useReducer(reducer, { count: initialCount});
  return (
    <>
      <p>Counter: {state.count}</p>
      <button onClick={() => dispatch({type: 'reset', payload: initialCount})}>reset</button>
      <button onClick={() => dispatch({type: 'increase'})}>+</button>
      <button onClick={() => dispatch({type: 'decrease'})}>-</button>
    </>
  )
}

function App() {
  return (
    <>
    <div className="App">
      <header className="App-header">
        <Counter initialCount={0} />
      </header>
    </div>
    </>
  );
}

useRef

语法:

const xxref = useRef(null)
const GetInputValue = () => {
  const inputRef:any = useRef(null);
  const [value1, setValue1] = useState('');
  const [value2, setValue2] = useState('');

  const getValue1 = (e:any) => {
    setValue1(e.target.value);
  };
  const getValue2 = () => {
    setValue2(inputRef.current?.value);
  };
  
  return (
    <>
      <input type="text" onChange={(e) => getValue1(e)}/>
      <p>获取input1值: {value1}</p>
      <input type="text" ref={inputRef}/>
      <p>获取input2值: {value2}</p>
      <button onClick={getValue2}>获取input2值</button>
    </>
  )
};

useImperativeHandle + forwardRef(父取子值)

const InputRef = (props:any) => {
  const { label, myRef } = props;
  const [value, setValue] = useState('');
  const inputRef:any = useRef(null);
  
  const handInputChange = (e:any) => {
    setValue(e.target.value)
  };

  const getValue = () => {
    return value
  };

  useImperativeHandle(myRef, () => ({
    getValue,
    focus() {
      inputRef.current.focus()
    },
  }));

  return (
    <>
      {label}:<input type="text" ref={inputRef} value={value} onChange={(e) => handInputChange(e)}/>
    </>
  )
};
const GetInputRef = forwardRef((props:any, ref:any) => 
  <InputRef {...props} myRef={ref} />
);
const GetSon = () => {
  const myRef:any = useRef(null);
  const [value, setValue] = useState('');

  const handleFocus = () => {
    myRef.current.focus()
  };

  const getValue = () => {
    setValue(myRef.current.getValue())
  };

  return (
    <>
      <GetInputRef label="name" ref={myRef}/>
      <button onClick={handleFocus}>focus</button>
      <span>{value}</span>
      <button onClick={getValue}>getValue</button>
    </>
  )
};

function App() {
  return (
    <>
    <div className="App">
      <header className="App-header">
        <GetSon />
      </header>
    </div>
    </>
  );
}
import React, { useEffect, useState, useContext, useReducer, useCallback, useMemo, useRef, useImperativeHandle, forwardRef } from 'react';

一个简单的自定义hooks

import { useState } from "react";

const useCounter = (init:number = 0) => {
  const [count, setCount] = useState(init);
  const decrease = (deCount:number = 1) => {
    setCount(preCount => preCount - deCount)
  };
  const increase = (inCount:number = 1) => {
    setCount(preCount => preCount + inCount)
  };
  return {count, decrease, increase}
};

export default useCounter;
import useCounter from './hooks/useCounter';

function App() {
  const { count, decrease, increase } = useCounter(10);
  const handleDecrease = () => {
    decrease(2);
  };
  const handleIncrease = () => {
    increase()
  };
  return (
    <>
    <div className="App">
      <header className="App-header">
        count:{count}
        <button onClick={handleIncrease}>decrease+1</button>
        <button onClick={handleDecrease}>increase-2</button>
      </header>
    </div>
    </>
  );
}

export default App;

ps: setState 有两种类型的参数。

//直接接收下一个状态作为参数的接口。
setState(newState);
//一个接口,它接受一个参数,从以前的状态计算一个新的状态。
setState((prev) => createNewStateFromPrevState(prev));