React Hook Series (1): Тщательно изучите использование реагирующих хуков (осторожно длинный текст)

React.js
React Hook Series (1): Тщательно изучите использование реагирующих хуков (осторожно длинный текст)

Внимательно прочитайте его, следуйте демо codeandbox или запуститеисходный код, вы познакомитесь с преимуществами, недостатками и использованием различных компонентов реакции,Быть полностью знаком с использованием реактивных крюков, доход должен быть не маленьким 😀😀😀

Контур:

  • Реагируйте на использование различных компонентов.
  • Что приносят реактивные хуки по сравнению с тем, что было раньше.
  • Использование реагирующих хуков.

Эволюция компонентов React

1. Функциональные компоненты (без сохранения состояния)

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

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

2. Компоненты класса (состояния)

Компонент класса (с отслеживанием состояния), компоненты класса также являются компонентами с отслеживанием состояния, и их также можно назвать компонентами-контейнерами. Как правило, есть логика взаимодействия и бизнес-логика.

class Welcome extends React.Component {
	state = {
		name: ‘tori’,
	}
  componentDidMount() {
		fetch(…);
		…
	}
  render() {
    return (
		<>
			<h1>Hello, {this.state.name}</h1>
			<button onClick={() => this.setState({name: ‘007’})}>改名</button>
		</>
	  );
  }
}

3. Компоненты рендеринга

Презентационный компонент, аналогичный функциональным компонентам (без сохранения состояния).

const Hello = (props) => {
  return (
    <div>
      <h1>Hello! {props.name}</h1>
    </div>
  )
}

**📢 Резюме: **

  • Функциональные компоненты должны быть компонентами без состояния, а компоненты отображения обычно являются компонентами без состояния;
  • Компоненты класса могут быть компонентами с состоянием или без него;
  • Компоненты-контейнеры обычно являются компонентами с отслеживанием состояния.
  • Принципы деления сводятся к следующему:Разделяй и властвуй, высокая сплоченность, низкая связанность;

Большинство требований может быть достигнуто за счет комбинации вышеперечисленных компонентов.

4. Компоненты высшего порядка

Higher order components (HOC)

HOC в основном извлекает состояние, извлекает логику повторяющихся управляемых компонентов в компоненты более высокого порядка и передает их управляемым компонентам с новыми реквизитами. Общие компоненты более высокого порядка в библиотеках с открытым исходным кодом: Redux connect, react-router withRouter и т. д.

Class HocFactory extends React.Component {
    constructor(props) {
      super(props)
    }
	// 操作props
	// …
    render() {
      const newProps = {…};
      return (Component) => <Component {…newProps} />;
    }
} 
Const Authorized = (Component) => (permission) => {
	return Class Authorized extends React.Component {
		…
		render() {
			const isAuth = ‘’;
			return isAuth ? <Component /> : <NoMatch />;
		}
	}
}

// 项目中涉及到的高阶组件
// 主要作用是将所有action通过高阶组件代理到component的Pro上。
import { bindActionCreators } from ‘redux’;
import { connect } from ‘react-redux';
// 所有页面action集合
import * as actions from './actions';
// 缓存actions, 避免render重新加载
let cachedActions;
// action通过bindActionCreators绑定dispatch,
const bindActions = (dispatch, ownProps) => {
  if (!cachedActions) {
    cachedActions = {
      dispatch,
      actions: bindActionCreators(actions, dispatch),
    };
  }
  return cachedActions;
};
const connectWithActions = (
  mapStateToProps,
  mergeProps,
  options
) => (component) => connect(
	mapStateToProps, bindActions, mergeProps, options
)(component);

export default connectWithActions;

// 类似还有log中间件样子的等等。

Недостатки HOC

  • HOC генерирует множество бесполезных компонентов, углубляет иерархию компонентов и влияет на производительность и отладку.
  • Несколько HOC вложены одновременно, захватывая реквизиты, имена могут конфликтовать, и невозможно определить, из какого HOC происходят реквизиты.

5. Render Props

Render Props Вы можете думать об этом как о функции обратного вызова в JavaScript.

// 实现一个控制modal visible的高阶组件
class ToggleVisible extends React.Component {
	state = {
		visible: false
	};
	toggle = () => {
		this.setState({visible: !this.state.visible});
	}
	render() {
		return (
		    <>{this.props.children({visible, toggle})}</>
		);
	}
}
//使用
const EditUser = () => (
	<ToggleVisible>
		{({visible, toggle}) => (<>
		    <Modal visible={visible}/>
		    <Button onClick={toggle}>打开/关闭modal</Button>
		</>)}
	</ToggleVisible>
)

📢 Преимущества

  • Повторное использование компонентов не приведет к созданию избыточных узлов, то есть избыточного вложения не произойдет.
  • Не беспокойтесь о проблемах с именами PROPS.

6. Составной компонент

Реквизиты, требуемые дочерним компонентом, будут инкапсулированы в родительском компоненте, поэтому нет необходимости передавать все реквизиты при ссылке на дочерний компонент. В основе компонентов композиции лежат два метода: React.Children.map и React.cloneElement.

Например, событие щелчка, требуемое дочерним компонентом, передается родительскому компоненту и инкапсулируется в дочерний компонент через родительский компонент.Многие групповые компоненты ant-design используют этот метод.

Справочная статья

class GroupButton extends React.PureComponent {
  state = {
    activeIndex: 0
  };
  render() {
    return (
      <>
        {React.Children.map(this.props.children, (child, index) =>
          child.type
            ? React.cloneElement(child, {
                active: this.state.activeIndex === index,
                onClick: () => {
                  this.setState({ activeIndex: index });
                  this.props.onChange(child.props.value);
                }
              })
            : child
        )}
      </>
    );
  }
}
// 用法
<GroupButton
  onChange={e => {
    console.log(“onChange”, e);
  }}
>
  <Button value="red">red</Button>
  <Button value="yellow">yellow</Button>
  <Button value=“blue”>blue</Button>
  <Button value="white">white</Button>
</GroupButton>

🙊 С чушью покончено, переходим к делу. . .

👍 Реагировать на крючки

Крюк появляется до того, как мультиплексирование логического состояния между компонентами становится затруднительным, требуется реструктуризация элементов ткани решения (HOC, Render Props), а код сложен. React React DevTools Приложение, наблюдаемое в приложении, вы обнаружите, что сборка уровня абстракции другими поставщиками, потребителями, компонентами высокого порядка, реквизитами рендеринга и т. д. образует «вложенный ад».

Сопровождение компонентов становится все более и более сложным, например, логика мониторинга событий должна быть привязана и развязана в разных жизненных циклах, сложная страница componentDidMount содержит много логики, а читабельность кода становится очень плохой.

Компонент this в классе трудно понять, и класс нельзя хорошо сжать, и это сделает горячую перезагрузку нестабильной. Дополнительные сведения см.Официальное введение.

Итак, крючки решают эти проблемы:

  • Избегайте адского вложения, улучшайте читаемость.
  • Функциональные компоненты легче понять, чем классы.
  • Жизненный цикл компонента класса слишком сложен, чтобы компонент функции имел состояние.
  • Устраните недостатки HOC и Render Props.
  • Пользовательский интерфейс и логику легче разделить.

Ниже описаны официально предоставленные API-интерфейсы хуков один за другим.

1. useState

📢 Функциональные компоненты имеют состояние

const [state, setState] = useState(initialState);состояние является переменной,setStateМетод изменения значения состояния setState также выполняется асинхронно.

DEMO1

Обновление класса this.setState заключается в том, что состояние объединяется, а setState в useState является заменой.

function Example() {
  // 声明一个叫 "count" 的 state 变量
  const [count, setCount] = useState(0);
	const [obj, setData] = useState();
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

2. useEffect

📢 Забудьте о жизненном цикле, помните о побочных эффектах

useEffect(()  =>  {// Async Action}, ?[dependencies]); // 第二参数非必填

DEMO2

function Hook2() {
  const [data, setData] = useState();
  useEffect(() => {
    console.log("useEffect");
  });
  return (
    <div>
      {(() => {
        console.log("render");
        return null;
      })()}
      <p>data: {JSON.stringify(data)}</p>
    </div>
  );
}

Результаты:

В заключение:

  • useEffect выполняется после рендеринга.

DEMO3

import React, { useState, useEffect, useRef } from “react”;
function Demo3() {
  const [data, setData] = useState();
  useEffect(() => {
    console.log("useEffect—[]”);
    fetch(“https://www.mxnzp.com/api/lottery/common/latest?code=ssq”)
      .then(res => res.json())
      .then(res => {
        setData(res);
      });
  }, []);

  useEffect(() => {
    console.log("useEffect ---> 无依赖");
  });

  useEffect(() => {
    console.log(“useEffect 依赖data: data发生了变化”);
  }, [data]);

  return (
    <div>
      <p>data: {JSON.stringify(data)}</p>
    </div>
  );
}
export default Demo3;

Результаты:

В заключение:

  • Эффекты выполняются последовательно после рендера.
  • При отсутствии каких-либо зависимостей эффекты выполняются по порядку каждый раз после рендеринга.
  • Внутреннее выполнение эффекта асинхронно.
  • полагаться[]можно добиться чего-то вродеcomponentDidMountэффект, но лучше забыть о жизненном цикле и помнить только о побочных эффектах.

DEMO4

import React, { useState, useEffect, useRef } from "react";

function Demo4() {
  useEffect(() => {
    console.log(“useEffect1”);
    const timeId = setTimeout(() => {
      console.log(“useEffect1-setTimeout-2000”);
    }, 2000);
    return () => {
      clearTimeout(timeId);
    };
  }, []);
  useEffect(() => {
    console.log("useEffect2");
    const timeId = setInterval(() => {
      console.log("useEffect2-setInterval-1000");
    }, 1000);
    return () => {
      clearInterval(timeId);
    };
  }, []);
  return (
    <div>
      {(() => {
        console.log(“render”);
        return null;
      })()}
      <p>demo4</p>
    </div>
  );
}
export default Demo4;

Результаты:

В заключение:

  • Функции обратного вызова эффекта выполняются одновременно по порядку.
  • Функция обратного вызова эффекта возвращает анонимную функцию, которая эквивалентнаcomponentUnMountФункции ловушки обычно удаляют eventListener, очищают timeId и т. д., в основном для предотвращения утечек памяти после удаления компонента.

Подводя итог, можно сказать, что useEffect — это функция-ловушка в функциональном компоненте, которая выполняет функцию обратного вызова всякий раз, когда изменяется зависимость.

3. useContext

Хуки-функции для обмена данными между компонентами

const value = useContext(MyContext);
// MyContext 为 context 对象(React.createContext 的返回值) 
// useContext 返回MyContext的返回值。
// 当前的 context 值由上层组件中距离当前组件最近的<MyContext.Provider> 的 value prop 决定。

DEMO5

import React, { useContext, useState } from “react”;
const MyContext = React.createContext();
function Demo5() {
  const [value, setValue] = useState("init”);
  console.log(“Demo5”);
  return (
    <div>
      {(() => {
        console.log("render");
        return null;
      })()}
      <button onClick={() => {
        console.log('click:更新value')
        setValue(`${Date.now()}_newValue`)
      }}>
        改变value
      </button>
      <MyContext.Provider value={value}>
        <Child1 />
        <Child2 />
      </MyContext.Provider>
    </div>
  );
}

function Child1() {
  const value = useContext(MyContext);
  console.log(“Child1-value”, value);
  return <div>Child1-value: {value}</div>;
}

function Child2(props) {
  console.log(‘Child2’)
  return <div>Child2</div>;
}

Результаты:

В заключение:

  • Компоненты с useContext всегда будут перерисовываться при изменении значения контекста, поэтому<MyContext.Provider>Чем больше пакетов и чем глубже слои, тем меньше будет производительность.

  • <MyContext.Provider>Когда значение пакета изменится, все компоненты будут перерисованы независимо от того, подписывается ли обернутый компонент на значение содержимого.

  • В демке child2 не должен рендериться, как избежать лишнего рендеринга? *
    Оптимизировано с помощью React.memo.

const Child2 = React.memo((props) => {
  return <div>Child2</div>;
})

Результаты:

Уведомление:По умолчанию React.memo выполняет поверхностное сравнение только сложных объектов.Если вы хотите контролировать процесс сравнения, передайте пользовательскую функцию сравнения через второй параметр.Ссылка на ссылку

4. useRef

портал

const refContainer = useRef(initialValue);
  • useRef возвращает изменяемый объект ref, и единственная разница между созданием объекта {current: …} заключается в том, что useRef будет возвращать один и тот же объект ref каждый раз при его рендеринге, который уникален на протяжении всего жизненного цикла компонента.
  • useRef может содержать любое изменяемое значение. Это похоже на то, как поля экземпляра используются в классе.Суммировать:
  • useRef может хранить данные, которые не должны вызывать повторную визуализацию страницы..
  • Если вы намеренно хотите прочитать состояние /latest/ из какого-либо асинхронного обратного вызова, вы можете использоватьреферичтобы сохранить его, изменить его и прочитать из него.

5. useReducer

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

reducerэто то, что может пройти толькоactionБудуstateот одного процесса к другомучистая функция; useReducerэто способ прохождения(state,action) => newStateпроцесс, иreduxРаботает так же. Поток данных: диспетчеризация (действие) => редуктор обновляет состояние => возвращает обновленное состояние

const initialState = {count: 0};

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();
  }
}
function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({type: 'decrement'})}>-</button>
      <button onClick={() => dispatch({type: 'increment'})}>+</button>
    </>
  );
}

Официально рекомендуется, чтобы useReducer лучше подходил для следующих сценариев:

  • Логика состояния сложна и содержит несколько подзначений, которые можно обрабатывать централизованно.
  • Следующее состояние зависит от предыдущего состояния.
  • Хотите более стабильно создавать автоматизированные тест-кейсы.
  • Если вы хотите глубоко изменить состояние некоторых подкомпонентов, использование useReducer также может оптимизировать производительность компонентов, которые будут запускать глубокие обновления, потому чтоВы можете передать отправку дочерним компонентам вместо обратных вызовов.
  • Использование редьюсера помогает отделить чтение от записи.DEMO6
const fetchReducer = (state, action) => {
  switch (action.type) {
    case “FETCH_INIT":
      return {
        ...state,
        loading: true,
        error: false
      };
    case “FETCH_SUCCESS”:
      return {
        ...state,
        loading: false,
        error: false,
        data: action.payload
      };
    case "FETCH_FAIL":
      return {
        …state,
        loading: false,
        error: true
      };
    default:
      throw new Error();
  }
};

function Demo6() {
  const [state, dispatch] = useReducer(fetchReducer, {
    loading: false,
    error: false,
    msg: "",
    data: {}
  });

  const getData = useCallback(async () => {
    try {
      dispatch({ type: "FETCH_INIT" });
      const response = await fetch(
        "https://www.mxnzp.com/api/lottery/common/latest?code=ssq"
      );
      const res = await response.json();

      if (res.code) {
        dispatch({ type: "FETCH_SUCCESS", payload: res.data });
      } else {
        dispatch({ type: “FETCH_FAIL”, payload: res.msg });
      }
    } catch (error) {
      dispatch({ type: “FETCH_FAIL”, payload: error });
    }
  }, []);

  useEffect(() => {
    getData();
  }, [getData]);

  return (
    <Loading loading={state.loading}>
      <p>开奖号码: {state.data.openCode}</p>
    </Loading>
  );
}

demo6useReducer обрабатывает ряд логик, которые могут быть реализованы с помощью useState, в том числеloading, error, msg, data.

useContext и useReducer имитируют состояние управления избыточностью

import React, { useReducer, useContext } from “react”;

const ModalContext = React.createContext();

const visibleReducer = (state, action) => {
  switch (action.type) {
    case “CREATE”:
      return { ...state, ...action.payload };
    case "EDIT":
      return { ...state, ...action.payload };
    default:
      return state;
  }
};
function Demo7() {
  const initModalVisible = {
    create: false,
    edit: false
  };
  const [state, dispatch] = useReducer(visibleReducer, initModalVisible);

  return (
    <ModalContext.Provider value={{ visibles: state, dispatch }}>
      <Demo7Child />
    </ModalContext.Provider>
  );
}
function Demo7Child() {
  return (
    <div>
      Demo7Child
      <Detail />
    </div>
  );
}
function Detail() {
  const { visibles, dispatch } = useContext(ModalContext);
  console.log("contextValue", visibles);
  return (
    <div>
      <p>create: {`${visibles.create}`}</p>
      <button
        onClick={() => dispatch({ type: "CREATE", payload: { create: true } })}
      >
        打开创建modal
      </button>
    </div>
  );
}
export default Demo7;

Логика явно извлечена, и значение в значении контекста не нужно прозрачно передавать в компоненте.из коробки.DEMO7

УведомлениеReact гарантирует, что идентификатор функции диспетчеризации стабилен и не изменится при повторном рендеринге компонента. Вот почему dispatch можно безопасно исключить из списка зависимостей useEffect или useCallback.

6. useCallback

грамматика:

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

вернутьmemoizedПерезвоните.

useCallbackВ чем проблема? Первый взглядDEMO8

import React, { useRef, useEffect, useState, useCallback } from “react”;

function Child({ event, data }) {
  console.log("child-render");
  // 第五版
  useEffect(() => {
    console.log(“child-useEffect”);
    event();
  }, [event]);
  return (
    <div>
      <p>child</p>
      {/* <p>props-data: {data.data && data.data.openCode}</p> */}
      <button onClick={event}>调用父级event</button>
    </div>
  );
}

const set = new Set();

function Demo8() {
  const [count, setCount] = useState(0);
  const [data, setData] = useState({});

  // 第一版
  // const handle = async () => {
  //   const response = await fetch(
  //     "https://www.mxnzp.com/api/lottery/common/latest?code=ssq"
  //   );
  //   const res = await response.json();
  //   console.log("handle", data);
  //   setData(res);
  // };

  // 第二版
  // const handle = useCallback(async () => {
  //   const response = await fetch(
  //     “https://www.mxnzp.com/api/lottery/common/latest?code=ssq"
  //   );
  //   const res = await response.json();
  //   console.log(“handle”, data);
  //   setData(res);
  // });

  // 第三版
  // const handle = useCallback(async () => {
  //   const response = await fetch(
  //     “https://www.mxnzp.com/api/lottery/common/latest?code=ssq”
  //   );
  //   const res = await response.json();
  //   setData(res);
  //   console.log(“useCallback”, data);
  //   // eslint-disable-next-line react-hooks/exhaustive-deps
  // }, []);

  // // 第四版
  // const handle = useCallback(async () => {
  //   const response = await fetch(
  //     “https://www.mxnzp.com/api/lottery/common/latest?code=ssq"
  //   );
  //   const res = await response.json();
  //   setData(res);
  //   console.log(“parent-useCallback", data);
  //   // eslint-disable-next-line react-hooks/exhaustive-deps
  // }, []);

  // 第五版
  const handle = useCallback(async () => {
    const response = await fetch(
      "https://www.mxnzp.com/api/lottery/common/latest?code=ssq"
    );
    const res = await response.json();
    setData(res);
    console.log("parent-useCallback", data);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [count]);
  set.add(handle);

  console.log(“parent-render====>”, data);
  return (
    <div>
      <button
        onClick={e => {
          setCount(count + 1);
        }}
      >
        count++
      </button>
      <p>set size: {set.size}</p>
      <p>count:{count}</p>
      <p>data: {data.data && data.data.openCode}</p>
      <p>-------------------------------</p>
      <Child event={handle} />
    </div>
  );
}
export default Demo8;

В заключение:

  • Первая версия: каждый раз, когда вы рендерите, handle — это новая функция, и вы можете каждый раз получать самые свежие данные.
  • Второй вариант: обернуть хендл с помощью useCallback, каждый раз при рендеринге хендл тоже новая функция, и можно каждый раз получать самые свежие данные, эффект такой же, как и в первом варианте, поэтому использовать его не рекомендуется.
  • Третий вариант: useCallback Если второй параметр deps, то дескриптор будет мемоизирован, поэтому каждое данные является данными (замыканием) первой памяти.
  • Четвертая редакция: useCallback зависит от изменения счетчика, всякий раз, когда useCallback изменяется, дескриптор будет повторно запоминаться.
  • Пятая редакция: при каждом изменении счетчика функция, передаваемая дочернему компоненту, является самой последней, поэтому выполняется useEffect дочернего элемента.Суммировать:
  • useCallback вернетВерсия обратного вызова памяти, только если одна из зависимостей изменилась.
  • Этот метод полезен при передаче обратных вызовов оптимизированным дочерним компонентам, которые полагаются на равенство ссылок, чтобы предотвратить ненужную визуализацию.
  • Используйте функцию обратного вызова в качестве параметра для передачи, каждый раз, когда функция рендеринга будет меняться, это также вызовет повторную визуализацию дочернего компонента, useCallback может оптимизировать повторную визуализацию.Вопрос: Как оптимизировать ненужный рендеринг дочерних компонентов?

7. useMemo

грамматика: const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);; вернутьmemoizedзначение иuseCallbackТочно так же мемоизированное значение пересчитывается только при изменении зависимостей. Разница между useMemo и useCallback в том, что они позволяют вамmemoizedПрименяется к любому типу значения (не только к функциям).DEMO9

import React, { useState, useMemo } from “react”;

function Demo9() {
  const [count, setCount] = useState(0);
  const handle = () => {
    console.log(“handle”, count);
    return count;
  };

  const handle1 = useMemo(() => {
    console.log("handle1", count);
    return count;
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const handle2 = useMemo(() => {
    console.log(“handle2”, count);
	  // 大计算量的方法
    return count;
  }, [count]);

  console.log("render-parent");

  return (
    <div>
      <p>
        demo9: {count}
        <button onClick={() => setCount(count + 1)}>++count</button>
      </p>
      <p>-------------------</p>
      <Child handle={handle1} />
    </div>
  );
}

function Child({ handle }) {
  console.log("render-child");
  return (
    <div>
      <p>child</p>
      <p>props-data: {handle}</p>
    </div>
  );
}
export default Demo9;

Суммировать:

  • useMemoБудет вrender перед казнью.
  • Если массив зависимостей не предоставлен, useMemo будет вычислять новые значения при каждом рендеринге.
  • useMemoдля возвратаmemoize, чтобы предотвратить каждый рендербольшой объем вычисленийпонесенные рассходы.
  • использоватьuseMemoОптимизация должна быть осторожной, потому что сама по себе оптимизация также требует вычислений,В большинстве случаев вам не нужно думать об оптимизации ненужных повторных рендеров..

Другие крючки

1. useImperativeHandle

// ref:需要传递的ref
// createHandle: 需要暴露给父级的方法。
// deps: 依赖
useImperativeHandle(ref, createHandle, [deps])

useImperativeHandleдолжно быть сforwardRef использовать вместе. Первый взглядDEMO10

import React, {
  useRef,
  forwardRef,
  useImperativeHandle,
  useEffect,
  useState
} from "react";

const Child = forwardRef((props, ref) => {
  const inputEl = useRef();
  const [value, setVal] = useState("");
  // 第一版
  // useImperativeHandle(ref, () => {
  //   console.log("useImperativeHandle");
  //   return {
  //     value,
  //     focus: () => inputEl.current.focus()
  //   };
  // });

  // 第二版
  useImperativeHandle(
    ref,
    () => {
      console.log(“useImperativeHandle");
      return {
        value,
        focus: () => inputEl.current.focus()
      };
    },
    // eslint-disable-next-line react-hooks/exhaustive-deps
    []
  );

  return (
    <input
      ref={inputEl}
      onChange={e => setVal(e.target.value)}
      value={value}
      {...props}
    />
  );
});
function Demo10() {
  const inputEl = useRef(null);

  useEffect(() => {
    console.log(“parent-useEffect”, inputEl.current);
    inputEl.current.focus();
  }, []);

  function click() {
    console.log("click:", inputEl.current);
    inputEl.current.focus();
  }
  console.log(“Demo10”, inputEl.current);
  return (
    <div>
      <Child ref={inputEl} />
      <button onClick={click}>click focus</button>
    </div>
  );
}
export default Demo10;

В заключение:

  • useImperativeHandleВыполняется после рендеринга текущего компонента.
  • Первая версия: никаких зависимостей, всякий раз, когда ререндерится,useImperativeHandle будет выполнено, и можно будет получить самое последнее значение в состоянии, и метод, переданный родительским компонентом, также будет самым последним.
  • Второе издание: зависимость[], при каждом повторном рендерингеuseImperativeHandle Не выполняется и не обновляется до родительского компонента.
  • 3-е издание: зависит от входящего значения состояния[value], для достижения желаемого эффекта.

2. useDebugValue

Обычно не используется, его можно увидеть только в инструментах разработчика React, см.портал.

DEMO11

function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(false);
  // 在开发者工具中的这个 Hook 旁边显示标签
  // e.g. "FriendStatus: Online"
  useDebugValue(isOnline ? "Online" : "Offline");
  return isOnline;
}
function Demo11() {
  const isOnline = useFriendStatus(567);
  return <div>朋友是否在线:{isOnline ? "在线" : "离线"}</div>;
}
image-20191212232215094

3. useLayoutEffect

используется редко, сuseEffectТо же самое, но эффект будет вызываться синхронно после всех изменений DOM, см. официальныйпортал.


📢 Наконец-то

Добро пожаловать на общение,😀🍻🍻😀

следующее уведомление

«Практика кастомных хуков в проектах»

Связанное чтение:

Теплое напоминание: ** Больше растягивайтесь, это полезно для вашего тела.


【Серия React Hook】

Гость офицер, качество три подряд! 🤡🤡🤡

图片替换文本