Mam składnik funkcjonalny, który inicjuje stan za pomocą useState, a następnie ten stan jest zmieniany za pośrednictwem pola wejściowego.

Następnie mam haczyk useEffect symulujący componentWillUnmount, dzięki czemu przed odłączeniem komponentu bieżący, zaktualizowany stan jest rejestrowany w konsoli. Jednak stan początkowy jest rejestrowany zamiast bieżącego.

Oto prosta reprezentacja tego, co próbuję zrobić (to nie jest mój rzeczywisty komponent):

import React, { useEffect, useState } from 'react';

const Input = () => {
    const [text, setText] = useState('aaa');

    useEffect(() => {
        return () => {
            console.log(text);
        }
    }, [])

    const onChange = (e) => {
        setText(e.target.value);
    };

    return (
        <div>
            <input type="text" value={text} onChange={onChange} />
        </div>
    )
}

export default Input;

Inicjalizuję stan jako „początkowy”. Następnie używam pola wprowadzania, aby zmienić stan, powiedzmy, że wpisuję „nowy tekst”. Jednak gdy komponent jest odłączany, w konsoli rejestrowane jest „początkowe” zamiast „nowego tekstu”.

Dlaczego to się dzieje? Jak mogę uzyskać dostęp do aktualnego zaktualizowanego stanu po odmontowaniu?

Wielkie dzięki!

Edytować:

Dodanie tekstu do tablicy zależności useEffect nie rozwiązuje mojego problemu, ponieważ w moim scenariuszu w świecie rzeczywistym chcę uruchomić akcję asynchroniczną w oparciu o bieżący stan i nie byłoby to efektywne za każdym razem, gdy „ tekst ”zmienia się stan.

Szukam sposobu, aby uzyskać bieżący stan tylko tuż przed odłączeniem komponentu.

2
Edmundo Biglia 18 marzec 2020, 09:34

2 odpowiedzi

Najlepsza odpowiedź

Skutecznie zapamiętałeś początkową wartość stanu, więc kiedy komponent odmontuje wartość jest tym, co zwrócona funkcja objęła swoim zasięgiem.

Oczyszczanie efektu

Funkcja czyszczenia jest uruchamiana przed usunięciem składnika z interfejsu użytkownika aby zapobiec wyciekom pamięci. Ponadto, jeśli składnik renderuje wiele plików razy (jak to zwykle robią), poprzedni efekt jest czyszczony wcześniej wykonanie następnego efektu . W naszym przykładzie oznacza to nowy plik subskrypcja jest tworzona przy każdej aktualizacji. Aby uniknąć wypalenia efektu każda aktualizacja, patrz następna sekcja.

Aby uzyskać najnowszy stan, gdy wywoływana jest funkcja czyszczenia, musisz dołączyć text do tablicy zależności, aby funkcja została zaktualizowana.

Dokumentacja dotycząca efektów

Jeśli przekażesz pustą tablicę ([]), właściwości i stan wewnątrz efektu zawsze będą miały swoje początkowe wartości . Podczas mijania [] jako drugi argument jest bliższy znanemu componentDidMount i Model mentalny componentWillUnmount, zwykle są lepsze rozwiązania aby uniknąć zbyt częstego ponownego uruchamiania efektów.

Oznacza to, że zwrócona funkcja „cleanup” nadal ma dostęp tylko do stanu i właściwości poprzedniego cyklu renderowania.

EDYTUJ

useRef

useRef zwraca zmienny obiekt ref, którego właściwością jest .current zainicjowany do przekazanego argumentu (initialValue). Zwrócony obiekt będzie trwać przez cały okres użytkowania komponentu.

...

Przydaje się przy zachowaniu wszelkich zmiennych wartości , podobnie jak w przypadku używania pól instancji w klasach.

Użycie ref pozwoli ci zbuforować bieżące odniesienie text, do którego można uzyskać dostęp w ramach funkcji czyszczenia.

/ EDYTUJ

Składnik

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

const Input = () => {
  const [text, setText] = useState('aaa');

  // #1 ref to cache current text value
  const textRef = useRef(null);
  // #2 cache current text value
  textRef.current = text;

  useEffect(() => {
    console.log("Mounted", text);

    // #3 access ref to get current text value in cleanup
    return () => console.log("Unmounted", text, "textRef", textRef.current);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    console.log("current text", text);
    return () => {
      console.log("previous text", text);
    }
  }, [text])

  const onChange = (e) => {
    setText(e.target.value);
  };

  return (
    <div>
      <input type="text" value={text} onChange={onChange} />
    </div>
  )
}

export default Input;

Dzięki console.log w zwróconej funkcji czyszczenia zauważysz, że po każdej zmianie danych wejściowych poprzedni stan jest rejestrowany w konsoli.

Edit zen-leftpad-twogm

W tym demo zarejestrowałem aktualny stan w efekcie i poprzednim stanie w funkcji czyszczenia. Zwróć uwagę, że funkcja czyszczenia rejestruje najpierw dziennik przed bieżącym dziennikiem następnego cyklu renderowania.

0
Drew Reese 19 marzec 2020, 02:41

Musisz zdać text do useEffect

useEffect(() => {
  return () => {
     console.log(text);
  };
}, [text]);
0
iamhuynq 18 marzec 2020, 06:39