Функциональный компонент React повторно инициализирует локальные функции и переменные при рендеринге (React Hooks) - PullRequest
0 голосов
/ 06 ноября 2018

Итак, я начал использовать ловушки React. Я экспериментировал с API уже некоторое время. мне очень нравится идея доведения состояния до функциональных компонентов. но есть одна вещь, которая продолжает беспокоить меня, и это не чувствует себя хорошо в кишечнике, когда я пытаюсь использовать это. Я попытался опубликовать на RFCs, но сейчас там слишком людно. там все кажется потерянным.

Вот фрагмент кода из моего примера.

import React, { useState } from "react";

function Counter() {
  const [counterState,incrementCounterState] =  useCommontState(0); 

  function doSomething (){
   // does something and then calls incrementCounterState
   // with the updated state.
  }

   return (
    <div>
      <p>{counterState}</p>
      <button onClick={incrementCounterState}>increase</button>
      ....
      .... // some jsx calling local scoped functions.
      ....
    </div>
    );
}

function useCommontState(defaultValue){
  var [state, setState] = useState(0);
  function increment(){
    setState(defaultValue+=1);
  }
  return [state, increment]
}

export default Counter;

Я могу легко извлечь state и setState методы и создать пользовательский hook, но моя проблема с локальными функциями, которые используются компонентом. так как состояние теперь является частью компонента, будут случаи, когда некоторая логика решит, что делать дальше с состоянием.

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

Есть ли способы, которыми мы можем обойти это. это новый API. мы даже не уверены, превратится ли это в react 17. но кто-нибудь сталкивался с каким-нибудь лучшим способом сделать это?

Ответы [ 3 ]

0 голосов
/ 06 ноября 2018

У меня были те же проблемы, когда я впервые увидел предложение, но оно было рассмотрено в FAQ по React Docs Hooks Предложение :

Являются ли хуки медленными из-за создания функций в рендере?

Нет. В современных браузерах сырая производительность замыканий по сравнению с классами существенно не отличается, за исключением крайних сценариев.

Мой вывод: теперь у вас есть дополнительные издержки при повторных объявлениях для каждого рендера, но у вас есть дополнительные выигрыши в других местах:

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

  • Идиоматическому коду, использующему Hooks, не требуется глубокое вложение дерева компонентов, распространенное в кодовых базах, в которых используются компоненты более высокого порядка, объекты рендеринга и контекст. С меньшими деревьями компонентов у React меньше работы.

В целом преимущества могут быть больше, чем недостатки, которые делают использование крючков оправданным.

0 голосов
/ 08 ноября 2018

Я использую вспомогательную функцию createOnce для предотвращения повторной инициализации, но я не уверен, правильно это или нет.

Utils / createOnce.js

import { useMemo } from 'react';

export const createOnce = toCreate => useMemo(() => toCreate, []);

SomeComponent.js

...

const someFunction = createOnce((counter) => {
  // whatever
  return counter + 1;
});

...
0 голосов
/ 06 ноября 2018

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

    import React, { useState } from "react";

    function doSomething (counterState, incrementCounterState){
       // does something and then calls incrementCounterState
       // with the updated state.
   }
    function Counter() {
      const [counterState,incrementCounterState] =  useCommontState(0); 

       return (
        <div>
          <p>{counterState}</p>
          <button onClick={incrementCounterState}>increase</button>
          ....
          .... // some jsx calling local scoped functions.
          ....
        </div>
        );
    }

    function increment(defaultValue, setState){
        setState(defaultValue + 1);
    }

    function useCommontState(defaultValue){
      var [state, setState] = useState(0);
      return [state, increment]
    }

    export default Counter;

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

...