Odpowiednik componentDidMount w funkcji React / komponencie hooków?

107

Czy istnieją sposoby na symulowanie componentDidMountkomponentów funkcjonalnych w React za pomocą hooków?

jeyko
źródło

Odpowiedzi:

216

Dla stabilnej wersji hooków (wersja React 16.8.0+)

Dla componentDidMount

useEffect(() => {
  // Your code here
}, []);

Dla componentDidUpdate

useEffect(() => {
  // Your code here
}, [yourDependency]);

Dla componentWillUnmount

useEffect(() => {
  // componentWillUnmount
  return () => {
     // Your code here
  }
}, [yourDependency]);

W tej sytuacji musisz przekazać swoją zależność do tej tablicy. Załóżmy, że masz taki stan

const [count, setCount] = useState(0);

Gdy liczba wzrasta, chcesz ponownie wyrenderować komponent funkcji. Wtedy twój useEffectpowinien wyglądać tak

useEffect(() => {
  // <div>{count}</div>
}, [count]);

W ten sposób za każdym razem, gdy zaktualizujesz licznik, komponent zostanie ponownie renderowany. Mam nadzieję, że to trochę pomoże.

Mertcan Diken
źródło
Dokładne wyjaśnienie! Czy istnieje sposób na symulację componentDidReceiveProps?
jeyko
1
Nie jestem tego świadomy, nawet jeśli istnieje. Możesz sprawdzić ten wątek na github.com/facebook/react/issues/3279
Mertcan Diken
1
Dziękuję za to, ponieważ nie byłem świadomy drugiego argumentu w useState. Dla każdego, kto to czyta, pamiętaj, że pozostawienie drugiego argumentu undefinedspowoduje wywołanie efektu przy każdym renderowaniu (jeśli się nie mylę).
dimiguel
Czy masz na myśli zależności useEffect (przekazywanie tablicy zależności)? Jeśli tak, tak, jeśli zostawisz to pole puste, oznacza to błąd w kodzie. Do dekonstrukcji tablicy potrzebne są oba elementy [count, setCount], ponieważ w tym przykładzie zmienną stanu jest count, a funkcja setCount jest funkcją aktualizującą ten stan.
Mertcan Diken
1
Próbowałem użyć pustej tablicy zależności, aby zasymulować componentDidMount. Problem polega na tym, że zwykle skutkuje ostrzeżeniem: „React Hook useEffect ma brakującą zależność: <some prop>. Albo ją uwzględnij, albo usuń tablicę zależności react-hooks / exhaustive-deps”. Zastosowanie jednej z sugerowanych „poprawek” powoduje, że nie zachowuje się już jak componentDidMount. czy robię coś źle?
Jonas Rosenqvist,
3

Chociaż zaakceptowana odpowiedź działa, nie jest zalecana. Kiedy masz więcej niż jeden stan i używasz go z useEffect, ostrzeże Cię o dodaniu go do tablicy zależności lub w ogóle jej nieużywaniu.

Czasami powoduje to problem, który może dać nieprzewidywalne wyniki. Dlatego sugeruję, abyś trochę się postarał, aby przepisać swoją funkcję na klasę. Jest bardzo mało zmian i możesz mieć niektóre komponenty jako klasę, a niektóre jako funkcje. Nie jesteś zobowiązany do używania tylko jednej konwencji.

Weź to na przykład

function App() {
  const [appointments, setAppointments] = useState([]);
  const [aptId, setAptId] = useState(1);

  useEffect(() => {
    fetch('./data.json')
      .then(response => response.json())
      .then(result => {
        const apts = result.map(item => {
          item.aptId = aptId;
          console.log(aptId);
          setAptId(aptId + 1);
          return item;
        })
        setAppointments(apts);
      });
  }, []);

  return(...);
}

i

class App extends Component {
  constructor() {
    super();
    this.state = {
      appointments: [],
      aptId: 1,
    }
  }

  componentDidMount() {
    fetch('./data.json')
      .then(response => response.json())
      .then(result => {
        const apts = result.map(item => {
          item.aptId = this.state.aptId;
          this.setState({aptId: this.state.aptId + 1});
          console.log(this.state.aptId);
          return item;
        });
        this.setState({appointments: apts});
      });
  }

  render(...);
}

To tylko przykład . więc nie mówmy o najlepszych praktykach lub potencjalnych problemach z kodem. Oba mają tę samą logikę, ale późniejsza działa tylko zgodnie z oczekiwaniami. Możesz uzyskać funkcjonalność komponentu componentDidMount, gdy useEffect będzie działał przez ten czas, ale wraz z rozwojem Twojej aplikacji mogą wystąpić pewne problemy. Więc zamiast przepisywać na tym etapie, lepiej zrobić to na wczesnym etapie.

Poza tym OOP nie jest takie złe, gdyby wystarczyło programowanie zorientowane na procedury, nigdy nie mielibyśmy programowania obiektowego. Czasami jest to bolesne, ale lepsze (technicznie. Pomijając kwestie osobiste).

Aniket Kariya
źródło
1
Ja to zrobiłem. Napotkałem problem z użyciem haków. Problem zniknął po przekształceniu go w klasę.
Julez
2

Nie ma żadnych componentDidMountfunkcjonalnych komponentów, ale React hooki zapewniają sposób na emulację zachowania za pomocą useEffecthooka.

Przekaż pustą tablicę jako drugi argument, useEffect()aby uruchomić wywołanie zwrotne tylko po zamontowaniu.

Przeczytaj dokumentacjęuseEffect .

function ComponentDidMount() {
  const [count, setCount] = React.useState(0);
  React.useEffect(() => {
    console.log('componentDidMount');
  }, []);

  return (
    <div>
      <p>componentDidMount: {count} times</p>
      <button
        onClick={() => {
          setCount(count + 1);
        }}
      >
        Click Me
      </button>
    </div>
  );
}

ReactDOM.render(
  <div>
    <ComponentDidMount />
  </div>,
  document.querySelector("#app")
);
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

<div id="app"></div>

Yangshun Tay
źródło
1

Nie ma dokładnego odpowiednika dla componentDidMounthaków reakcyjnych.


Z mojego doświadczenia wynika, że ​​reakcja hooków wymaga innego sposobu myślenia podczas jej tworzenia i generalnie nie należy porównywać jej z metodami klasowymi, takimi jak componentDidMount.

Z powiedział, że istnieją sposoby, które można wykorzystać do produkcji haków podobny efekt do componentDidMount.

Rozwiązanie 1:

useEffect(() => {
  console.log("I have been mounted")
}, [])

Rozwiązanie 2:

const num = 5

useEffect(() => {
  console.log("I will only run if my deps change: ", num)
}, [num])

Rozwiązanie 3 (z funkcją):

useEffect(() => {
  const someFunc = () => {
    console.log("Function being run after/on mount")
  }
  someFunc()
}, [])

Rozwiązanie 4 (useCallback):

const msg = "some message"

const myFunc = useCallback(() => {
  console.log(msg)
}, [msg])

useEffect(() => {
  myFunc()
}, [myFunc])

Rozwiązanie 5 (kreatywność):

export default function useDidMountHook(callback) {
  const didMount = useRef(null)

  useEffect(() => {
    if (callback && !didMount.current) {
      didMount.current = true
      callback()
    }
  })
}

Warto zauważyć, że rozwiązanie 5 powinno być naprawdę używane tylko wtedy, gdy żadne z innych rozwiązań nie działa w twoim przypadku użycia . Jeśli zdecydujesz, że potrzebujesz rozwiązania 5, polecam użycie tego gotowego haka do montażu .

Źródło (bardziej szczegółowo): Używanie komponentu componentDidMount w zaczepach reagujących

Atomicts
źródło
0

dokładny odpowiednik hooka dla componentDidMount () to

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

mam nadzieję, że to pomocne :)

Aravinth
źródło
-1

Chcesz użyć useEffect(), który, w zależności od tego, jak używasz funkcji, może działać podobnie jak componentDidMount ().

Na przykład. można użyć niestandardowej loadedwłaściwości stanu, która jest początkowo ustawiona na false, i przełączyć ją na true podczas renderowania i uruchomić efekt tylko wtedy, gdy ta wartość się zmieni.

Dokumentacja

markmoxx
źródło
1
To rozwiązanie nie jest idealne. Używanie wartości stanu tylko do określenia, czy komponent został zamontowany, jest złym pomysłem. Ponadto, gdybyś użył właściwości, ref byłby lepszy, ponieważ nie spowodowałby ponownego renderowania.
Yangshun Tay