Как отменить обратный вызов в функциональном компоненте с помощью хуков - PullRequest
1 голос
/ 24 мая 2019

Как я могу получить действительные значения реквизита в опровергнутых обратных вызовах React Functional Component, Это работало в React Class Component, но я понятия не имею, как достичь этого поведения в функциональном компоненте с помощью хуков.

import React from "react";
import ReactDOM from "react-dom";
import debounce from "lodash.debounce";

const TestFunc = ({ count, onClick }) => {
  const handleClick = debounce(() => {
    onClick();
    console.log(count);
  }, 500);

  return (
    <div>
      <button type="button" onClick={handleClick}>
        Func: {count}
      </button>
    </div>
  );
};

class TestClass extends React.Component {
  handleClick = debounce(() => {
    this.props.onClick();
    console.log(this.props.count);
  }, 500);

  render() {
    return (
      <div>
        <button type="button" onClick={this.handleClick}>
          Class: {this.props.count}
        </button>
      </div>
    );
  }
}

const App = () => {
  const [countClass, setCountClass] = React.useState(0);
  const [countFunc, setCountFunc] = React.useState(0);

  return (
    <div>
      <TestFunc count={countFunc} onClick={() => setCountFunc(countFunc + 1)} />
      <TestClass
        count={countClass}
        onClick={() => setCountClass(countClass + 1)}
      />
    </div>
  );
};

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

КогдаВы нажимаете кнопку функционального компонента, она записывает предыдущее значение count prop в консоль, но это уже изменилось с помощью обработчика onClick, в то же время кнопка компонента класса записывает фактическое значение count prop после того, как оно былоувеличивается на onClick обработчик.Итак, как я могу получить фактические значения пропеллера в функциональном компоненте?

1 Ответ

1 голос
/ 24 мая 2019

Вам нужно внести несколько изменений, чтобы использовать debounced method с крючком

  1. Вам нужно использовать хук useCallback, чтобы деблокированная функция создавалась только один раз при начальном рендеринге.
  2. Теперь, если вам нужно убедиться, что debounce получает правильное значение счетчика при его выполнении, вам нужно передать его как параметр, иначе он будет использовать значение из закрывающего замыкания во время его создания, которое является начальным счетчиком. значение.
  3. Необходимо обновить значение счетчика при вызове метода onClick, используя шаблон обратного вызова в родительском элементе, например setCountFunc(count => count + 1), чтобы дочерние компоненты повторно визуализировали с обновленным значением

Рабочая демоверсия ниже

const TestFunc = ({ count, onClick }) => {
  const handleClick = React.useCallback((count) =>{
     const click = _.debounce((count) => {
          onClick();
          console.log(count);
     }, 500)
     click(count);
 }, []);

  console.log(count, 'render');
  return (
    <div>
      <button type="button" onClick={() => handleClick(count)}>
        Func: {count}
      </button>
    </div>
  );
};

class TestClass extends React.Component {
  handleClick = _.debounce(() => {
    this.props.onClick();
    console.log(this.props.count);
  }, 500);

  render() {
    return (
      <div>
        <button type="button" onClick={this.handleClick}>
          Class: {this.props.count}
        </button>
      </div>
    );
  }
}

const App = () => {
  const [countClass, setCountClass] = React.useState(0);
  const [countFunc, setCountFunc] = React.useState(0);

  return (
    <div>
      <TestFunc count={countFunc} onClick={() => setCountFunc(count => count + 1)} />
      <TestClass
        count={countClass}
        onClick={() => setCountClass(countClass + 1)}
      />
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root" />
...