react笔记03-hooks1

83 阅读4分钟

hooks 钩子函数都是以 use 开头命名的,当我们使用自定义hooks时也需要遵循这一点,hooks必须写在组件内部,否则会报错。

useState

useState 接收一个初始值,可以时任意类型的值,返回一个数组,数组的第一项为整个 state 的值,第二项为改变整个 state 的方法。

  import React, { useState } from 'react';

  const [text, setText] = useState('random title');
  const handleClick = () => {
    setText('hello world');
  };

  return (
    // 当我们使用 React.Fragment 时,可以简写为一对尖括号
    <> 
      <h1>{text}</h1>
      <button type='button' className='btn' onClick={handleClick}>
        change title
      </button>
    </>
  );
};

异步处理

当我们在设置 state 的值的时候,如果是采用异步的方式设置的,那么当异步的结果没回来之前,就进行下一次设置,state 的值还是只会在初始值上修改的。为了保证异步的时候设置的值依赖上次修改后的值,我们可以使用 setState 的另一种用法。

  const asyncIncrease = () => {
    setTimeout(() => {
      // setValue(value + 1);   这样设置时获取的value值不是最新的值
      setValue((prevState) => {
        // 必须有返回值
        return prevState + 1;
      });
    }, 2000);
  };

useEffect

useEffect 会在每次组件渲染后重新执行,当我们触发 useStatesetState 修改数据的时候会使组件重新渲染。useEffect 会被用于处理一些副作用,比如发送请求、事件监听、注册订阅等。 useEffect 接收2个参数:

  1. 回调函数,重新渲染时执行的方法。
  2. 依赖数组,当数组中的项改变时才会重新执行回调函数。当依赖数组为一个空数组时,意味着只会在初始渲染时运行一次。

如果你在 useEffect 中修改了 state ,那么请一定记得添加依赖数组,否则会进行无限循环,每次修改了 state 触发重新渲染,重新渲染会执行 useEffect......

清除函数

初次渲染组件时,我们会直接执行useEffect 中的函数,而不执行 useEffect 的清理函数。而且在组件销毁的时候会执行 useEffect 的清理函数。但是在重新渲染时,会先执行 useEffect 的清理函数,再执行 useEffect 中的函数。useEffect 的清理功能就是在 useEffect 中返回一个函数。

  useEffect(() => {
    window.addEventListener('resize', checkSize);
    return () => {
      window.removeEventListener('resize', checkSize);
    };
  });

异步处理

useEffet 中的函数不能使用 async/await,因为 async 返回的是一个 promise,而 useEffet 返回的应该是它的清理函数。但是我们可以单独将异步函数写在外面,然后在useEffet 中调用异步函数。

受控组件 input

受控组件经常绑定 state 值,而不受控组件经常使用 useRef

当我们向 input 上绑定了 value 之后,就一定要绑定 onChange 事件。否则会报错且输入将不产生任何变化。

const ControlledInputs = () => {
  const [email, setEmail] = useState('');
  return (
    <>
      <input type='text' id='email' name='email'
           value={email}
           onChange={(e) => setEmail(e.target.value)} />
    </>
  );
};

useRef

useRefuseState 一样也可以保存数据,但是改变它不会触发重新渲染,最常用的就是使用它来指定 dom 元素。使用 useRef 创建的是一个带有 current 属性的对象,通过 ref 可以将 current 绑定在这个元素上。

const UseRefBasics = () => {
  const refContainer = useRef(null);

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('handleSubmit', refContainer);
  };
  useEffect(() => {
    console.log('useEffect', refContainer);
  });
  console.log('render', refContainer);
  return (
    <>
      <form className='form' onSubmit={handleSubmit}>
        <div>
          <input type='text' ref={refContainer} />
        </div>
        <button type='submit'>submit</button>
      </form>
    </>
  );
};

运行上面的例子,当我们在 render 的时候取到的 refContainercurrent 的值还是 null,但是在执行 useEffet 的时候,我们可以看到已经绑定到 input 元素上了。

我们可以使用 refContainer.current.focus() 进行 input 元素聚焦,也可以通过 refContainer.current.value 获取当前输入框的值。

useReducer

简单情况用 useState,复杂情况可以使用 useReducer。使用 useReducer 可以将多个 state 数据的处理放在一个地方,只需要 dispatch 传递不同参数进行不同处理,使逻辑更加清晰。

参数: 1. reducer: 改变数据时触发的方法。 2. defaultState: 数据默认初始值。

返回值: 1. state: 存储数据的对象。 2. dispatch: 改变数据的方法。

const defaultState = {people: [], isModalOpen: false, modalContent: ''};
const [state, dispatch] = useReducer(reducer, defaultState);

reducer

接收2个参数,第一个参数为当前的数据,第二个是 dispatch 传递参数,可以根据这个类型进行不同的处理。reducer 方法必须要有返回,否则报错。

export const reducer = (state, action) => {
  if (action.type === 'ADD_ITEM') {
    const newPeople = [...state.people, action.payload];
    return { ...state, people: newPeople, isModalOpen: true, modalContent: 'item added'};
  }
  if (action.type === 'NO_VALUE') {
    return { ...state, isModalOpen: true, modalContent: 'please enter value' };
  }
  if (action.type === 'CLOSE_MODAL') {
    return { ...state, isModalOpen: false };
  }
  // ... 更多情况处理
    return { ...state, people: newPeople };
  }
};

dispatch

触发数据的修改,可以传递不同参数。

dispatch({ type: 'NO_VALUE' });

StrictMode

React.StrictMode 会引起组件中的代码被执行两次。