Резюме React Hooks после фактического проекта

React.js

Что такое состояние использования?

Первый useState — это хук, который позволяет добавлять состояние React к функциональным компонентам.

useState — это метод, который сам по себе не может хранить состояние

Во-вторых, он запускается в FunctionalComponent, который сам не может сохранять состояние

useState принимает только один параметр, начальное значение, и не видит в нем ничего особенного.

Зачем использовать состояние?

Потому что компоненты класса имеют много болевых точек

  1. Сложно повторно использовать логику (используйте только HOC или реквизиты рендеринга), что приведет к глубокой иерархии дерева компонентов.
  2. Будет генерировать огромные компоненты (это означает, что в классе должно быть написано много кода)
  3. Компоненты класса сложны для понимания, как методы требуютbind,thisПункт не ясен Я, например, часто вижу такой способ письма.
// 可能是这样
class MyComponent extends React.Component {
  constructor() {
    // initiallize
    this.handler1 = this.handler1.bind(this)
    this.handler2 = this.handler2.bind(this)
    this.handler3 = this.handler3.bind(this)
    this.handler4 = this.handler4.bind(this)
    this.handler5 = this.handler5.bind(this)
    // ...more
  }
}

// 可能是这样的
export default withStyle(style)(connect(/*something*/)(withRouter(MyComponent)))

Как использовать useState?

Прежде чем мы начнем, давайте рассмотрим простой пример, который мы написали до хуков.

import React, {Component} from 'react';
class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      Switch: "打开"
    };
  }
  setSwitch = () => {
    this.state.Switch === "打开"
      ? this.setState({ Switch: "关闭" })
      : this.setState({ Switch: "打开" });
  };
  render() {
    return (
      <div>
        <p>现在是: {this.state.Switch}状态</p>
        <button onClick={this.setSwitch}>Change Me!</button>
      </div>
    );
  }
}
export default CommonCollectionPage;

В прошлом, когда функциональному компоненту нужно было придать ему собственное состояние, нам всегда приходилось превращать функциональный компонент в компонент класса.Теперь с React Hooks нам не нужно превращать функциональный компонент в компонент класса из-за небольшое состояние. , приведенный выше пример может быть преобразован в следующий метод, чтобы выразить.

Варианты использования useState

function App() {
  const [Switch, setSwitch] = useState("打开");
  const newName = () =>
    Switch === "打开" ? setSwitch("关闭") : setSwitch("打开");
  return (
    <div>
      <p>现在是: {Switch} 状态</p>
      <button onClick={newName}>Change Me!</button>
    </div>
  );
}

Таким образом, useState должен добавить функцию к функциональным компонентам, которые могут поддерживать свое собственное состояние.

Адрес операцииОтправитьдверь

Заметки об использовании состояния

Динамическая передача параметров в useState вступит в силу только в первый раз.

Что такое useEffect?

Используйте метод useEffect для замены компонентов класса.componentDidMount, componentDidUpdate, componentWillUnmount

Три компонента, как использовать один хук для получения разных эффектов от трех хуков:

Во-первых, давайте сначала запустим его:

useEffect первый параметр

import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function App() {
  const [switch, setSwitch] = useState("打开");
  const handleSwitch = _ =>
    switch === "打开" ? setSwitch("关闭") : setSwitch("打开");
  const [num, setNum] = useState(0);
  const add = () => {
    setNum(num + 1);
  };
  const minus = () => {
    setNum(num - 1);
  };
  useEffect(() => {
    console.log("改变了状态");
  }, [num]);
  return (
    <div>
      <p>现在是: {switch}状态</p>
      <button onClick={handleSwitch}>Change Me!</button>
      <p>数字: {num}</p>
      <button onClick={add}> +1 </button>
      <button onClick={minus}> -1 </button>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

В приведенном выше примере он будет печатать измененное состояние при первом рендеринге и печатать измененное состояние каждый раз, когда состояние изменяется.

Тогда такое использованиеcomponentDidMount, componentDidUpdate,использование

useEffect второй параметр

Добавьте второй параметр в метод useEffect, пустой объект [ ], тогда он будет напечатан только один раз при загрузке первого компонента.

измененное состояние

А что, если нам нужно напечатать, когда num изменяет состояние?

Только что мы использовали пустой объект, тогда нам нужно только добавить к этому объекту состояние, которое нам нужно отслеживать, тогда это эквивалентно использованию ,componentDidUpdate, ловушки, такие как

useEffect(() => {
    console.log("改变了状态");
  }, [num]);

Итак, теперь, когда состояние activeUser изменится, мы обнаружим, что предложение «изменить состояние» будет напечатано снова. Это предложение не печатается при изменении состояния переключателя.

Использование замыкания useEffect

import React, { useState, useEffect } from 'react';
function App() {
  useEffect(() => {
    console.log('装载了')
    return () => {
      console.log('卸载拉');
    };
  });
  return (
    <div>
      xxxx
    </div>
  );
}
export default App;

В useEffect мы можем делать две вещи: когда компонент смонтирован и когда компонент размонтирован, пока мы используем замыкание в useEffect, мы можем делать то, что хотим, когда компонент размонтирован в замыкании.

this.state и useState

Прежде всего, давайте рассмотрим компоненты класса, которые мы часто использовали ранее.Вот фрагмент кода, который реализует счетчик:

import React, { Component, useState, useEffect } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

class App extends Component {
  constructor() {
    super();
    this.state = {
      count: 0
    };
  }
  componentDidMount() {
    setTimeout(() => {
      console.log(`count:${this.state.count}`);
    }, 3000);
  }
  componentDidUpdate() {
    setTimeout(() => {
      console.log(`count:${this.state.count}`);
    }, 3000);
  }
  render() {
    return (
      <div>
        <p>{this.state.count}</p>
        <button
          onClick={() =>
            this.setState({
              count: this.state.count + 1
            })
          }
        >
          点击 3 次
        </button>
      </div>
    );
  }
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Страница немедленно обновляется, и кнопка нажимается 3 раза.Каким будет результат печати приведенного выше примера? ? ? ?

У нас есть четкое представление об this.state и this.setState, и все, что мы будем знать для печати, это:

Через некоторое время выведите 3, 3, 3, 3 соответственно

Однако механизм работы useEffect в хуках работает иначе.

function Counter() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    setTimeout(() => {
      console.log(count);
    }, 3000);
  });
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        点击 3 次
      </button>
    </div>
  );
}

Через некоторое время выведите 0, 1, 2, 3 соответственно.

На самом деле, у меня нет впечатления от использования this.state раньше.Когда я увижу результат печати этого кода, буду ли я считать это само собой разумеющимся?

Затем мы хотим, чтобы вышеуказанные компоненты класса также достигали вышеуказанных эффектов 0,1,2,3,4. Мы добавляем эти 2 строки кода.

//...

componentDidMount() {
    // 新增此行代码
    const newCount = this.state.count; 
    setTimeout(() => {
      console.log(newCount);
    }, 3000);
  }
  componentDidUpdate() {
    // 新增此行代码
    const newCount = this.state.count; 
    setTimeout(() => {
      console.log(newCount);
    }, 3000);
  }

  // ....

Все, о чем мы можем думать, это тот же эффект при значении функциональной составляющей

function Counter(props) {
  useEffect(() => {
    setTimeout(() => {
      console.log(props.counter);
    }, 3000);
  });
  // ...
}
function Counter(props) {
  const counter = props.counter;
  useEffect(() => {
    setTimeout(() => {
      console.log(counter);
    }, 3000);
  });
  // ...
}

Это показывает, что при рендеринге функционального компонента его обновление не изменит значения реквизита и состояния в области рендеринга. (выражение может быть неправильным)

Конечно, иногда мы хотим прочитать последнее значение вместо предыдущего значения в функции обратного вызова эффекта. Выведите 3.3.3.3 так же, как предыдущий компонент класса. Самый простой способ сделать это — использовать useRef.

Как используется useRef

Сначала реализуем задачу апелляционной печати 3, 3, 3, 3. как показано в коде ниже

function Counter() {
  const [count, setCount] = useState(0);
  const latestCount = useRef(count);
  useEffect(() => {
    latestCount.current = count;
    setTimeout(() => {
      console.log(latestCount.current);
    }, 3000);
  });
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        点击 3 次
      </button>
    </div>
  );
}

Мы передаем useRef(initVal) для возврата изменяемого объекта ссылки, текущее свойство которого инициализируется переданным параметром (initVal).

useRef также может получать узлы DOM.

Тогда функциональные компоненты не имеют жизненного цикла, так как же нам получить настоящие элементы ChartDom? Это также может быть достигнуто с помощью useRef

import React, { useState, useRef, Fragment, useEffect } from 'react';
import { Button } from 'antd';

function Demo({ count: propsCount = 1 }) {
  const [count, setCount] = useState(propsCount);
  const refContainer = useRef(null); // 如同之前的 React.createRef();
  
  useEffect(() => {
    console.log(refContainer.current, '>>>>>>>>>>>');
  });
  
  return (
      <Fragment>
        <Button onClick={() => { setCount(count + 1); }}>Click Me</Button>
        <p ref={refContainer}>You click {count} times</p>
      </Fragment>
  );
}

export default Demo;

использование редьюсера

import React, { useReducer, useEffect } from "react";
import ReactDOM from "react-dom";

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  const { count, step } = state;

  useEffect(() => {
    const id = setInterval(() => {
      dispatch({ type: 'tick' });
    }, 1000);
    return () => clearInterval(id);
  }, [dispatch]);

  return (
    <>
      <h1>{count}</h1>
      <input value={step} onChange={e => {
        dispatch({
          type: 'step',
          step: Number(e.target.value)
        });
      }} />
    </>
  );
}

const initialState = {
  count: 0,
  step: 1,
};

function reducer(state, action) {
  const { count, step } = state;
  if (action.type === 'tick') {
    return { count: count + step, step };
  } else if (action.type === 'step') {
    return { count, step: action.step };
  } else {
    throw new Error();
  }
}

useImperativeОбрабатывать использование

В компонентах класса мы используем ref для получения экземпляра компонента класса, чтобы родительский компонент мог вызвать метод дочернего компонента.

Тогда нет экземпляра функционального типа, как использовать ref?

// 子组件
import React, { useRef, useImperativeHandle,forwardRef } from "react";
function FancyInput(props, ref) {
  const inputRef = useRef();
  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    }
  }));
  return <input ref={inputRef} ... />;
}
export default forwardRef(FancyInput);


// 父组件
import React, { useRef } from "react";
function App(){
  const fancyInputRef = useRef(null)
  // 这样获取子组件方法
  fancyInputRef.current.focus()
  return (
    <div> 
      <FancyInput ref={fancyInputRef} /> 
    </div>
  )

}

наконец

Во всей статье, если есть какие-либо ошибки или неточности, обязательно исправьте их, спасибо!

Личная рекомендация других статей:

  1. Интерпретация исходного кода Axios
  2. Получить объяснение примера

Ссылаться на: