Warum sollten wir useEffect ohne ein Abhängigkeitsarray verwenden?

Lesezeit: 3 Minuten

Benutzeravatar von dagda1
dagda1

Ich habe diesen Code:

const App: React.FC = () => {
  const [isOpen, setIsOpen] = React.useState(true);
  const [maxHeight, setMaxHeight] = React.useState();

  const wrapper = React.useRef<HTMLDivElement>(null);
  const content = React.useRef<HTMLDivElement>(null);

  const setElementMaxHeight = () => {
    if (content && content.current) {
      setMaxHeight(isOpen ? content.current.offsetHeight : 0);
    }
  };

  useEffect(() => {
   setElementMaxHeight();

    window.addEventListener("resize", setElementMaxHeight);

    return () => {
      window.removeEventListener("resize", setElementMaxHeight);
    };
  });

  const toggle = () => {
    setIsOpen(!isOpen);
  };

  return (
    <div>
      <button onClick={toggle}>
        <span className="nominal-result__expander fa" />
      </button>
      <div
        className="nominal-results__list-wrapper"
        ref={wrapper}
        style={!!maxHeight ? { maxHeight: `${maxHeight}px` } : undefined }
      >
        <div className="nominal-results__list" ref={content} />
      </div>
    </div>
  );
};

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

Dadurch wird bei jedem Rendern ein Ereignishandler hinzugefügt und entfernt.

Ist das unbedingt schlecht und bringt es tatsächlich etwas, ein Haken zu sein?

Dies ist bei einer Codeüberprüfung aufgetaucht und ich sage, dass es schlecht ist, weil es den Ereignis-Listener bei jedem Rendern hinzufügt und entfernt.

Benutzeravatar von nem035
nem035

Dafür genau Falls du recht hast, weil undefined wird als Abhängigkeiten von übergeben useEffect.

Das heisst useEffect wird bei jedem Rendern ausgeführt und daher werden die Ereignishandler bei jedem Rendern unnötigerweise getrennt und wieder angehängt.

function listener() {
  console.log('click');
}

function Example() {
  const [count, setCount] = window.React.useState(0);

  window.React.useEffect(() => {

    console.log(`adding listener ${count}`);
    window.addEventListener("click", listener);

    return () => {
      console.log(`removing listener ${count}`);
      window.removeEventListener("click", listener);
    };
  }); // <-- because we're not passing anything here, we have an effect on each render
  
  window.React.useEffect(() => {
    setTimeout(() => {
      setCount(count + 1);
    }, 1000)
  });
  
  return count;
}

window.ReactDOM.render(window.React.createElement(Example), document.getElementById('root'))
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>

Wenn Sie jedoch explizit keine Abhängigkeiten deklarieren, indem Sie ein leeres Array übergeben [], useEffect wird nur einmal ausgeführt, sodass dieses Muster für die Anbringung von Event-Handlern vollkommen legitim ist.

function listener() {
  console.log('click');
}

function Example() {
  const [count, setCount] = window.React.useState(0);

  window.React.useEffect(() => {

    console.log(`adding listener ${count}`);
    window.addEventListener("click", listener);

    return () => {
      console.log(`removing listener ${count}`);
      window.removeEventListener("click", listener);
    };
  }, []); // <-- we can control for this effect to run only once during the lifetime of this component
  
  window.React.useEffect(() => {
    setTimeout(() => {
      setCount(count + 1);
    }, 1000)
  });
  
  return count;
}

window.ReactDOM.render(window.React.createElement(Example), document.getElementById('root'))
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>

  • „..die Event-Handler werden bei jedem Rendern unnötigerweise getrennt und wieder angefügt.“ Ist es dasselbe, als ob wir einen beliebigen Codeabschnitt ohne Hook geschrieben hätten? Angenommen, wir haben eine Zuweisung (const var = „something“). Bei jedem Rendern funktioniert diese Zuweisung so, als ob wir useEffect(() => const var = „something“) hätten. Bitte berücksichtigen Sie nicht den Variablenbereich

    – Ogostos

    14. Juli 2020 um 6:17 Uhr

  • Warum sollten Sie also jemals einen useEffect ohne ein Abhängigkeitsarray verwenden?

    – dwjohnston

    17. September 2020 um 4:25

  • @dwjohnston Nun, Sie würden es für jeden Vorgang verwenden, der bei jedem Rendern ausgeführt werden muss. Welcher Vorgang das ist, hängt von der App ab, die Sie erstellen.

    – nem035

    24. September 2020 um 5:41

  • @nem könnten Sie in diesem Fall diese Funktionalität nicht einfach in der Funktion deklarieren, ohne useEffect zu verwenden?

    – dwjohnston

    24. September 2020 um 7:17 Uhr

  • Es kommt auf den Anwendungsfall an. Ein Synchronisierungsfunktionsaufruf innerhalb des Renderzyklus wird im Rendervorgang ausgeführt und kann sich auf die Leistung auswirken. Ein Effekt wird immer nach dem Rendern ausgeführt, ist also zumindest weniger schädlich für die Benutzeroberfläche, da auf dem Bildschirm bereits das angezeigt wird, was er anzeigen sollte, wenn der Effekt mit der Ausführung beginnt.

    – nem035

    24. September 2020 um 7:20 Uhr

1453490cookie-checkWarum sollten wir useEffect ohne ein Abhängigkeitsarray verwenden?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy