React Hooks'ta componentWillMount () nasıl kullanılır?


176

React'ın resmi belgelerinde bahsediyor -

React sınıfı yaşam döngüsü yöntemlerini biliyorsanız, useEffect Hook'u componentDidMount, componentDidUpdate ve componentWillUnmount kombine olarak düşünebilirsiniz.

Sorum şu - componentWillMount()lifecyle yöntemini bir kancada nasıl kullanabiliriz ?

Yanıtlar:


341

Sen varolan yaşam döngüsü yöntemlerinden (herhangi kullanamaz componentDidMount, componentDidUpdate, componentWillUnmountkanca vb). Yalnızca sınıf bileşenlerinde kullanılabilirler. Ve Hooks ile sadece fonksiyonel bileşenlerde kullanabilirsiniz. Aşağıdaki satır React belgesinden geliyor:

Sınıf yaşam döngüsü yöntemleri Tepki aşina iseniz, aklınıza gelebilecek useEffectolarak Hook componentDidMount, componentDidUpdateve componentWillUnmountbirleştirdi.

önermek, fonksiyonel bileşenlerde sınıf bileşeninden bu yaşam döngüsü yöntemini taklit edebilirsiniz.

İç componentDidMountkısımdaki kod , bileşen monte edildiğinde bir kez çalışır. useEffectBu davranış için kanca eşdeğeri

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

Burada ikinci parametreye dikkat edin (boş dizi). Bu yalnızca bir kez çalışır.

İkinci parametre olmadanuseEffect kanca tehlikeli olabilir bileşenin kılmak her çağrıda edilecektir.

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

componentWillUnmounttemizleme için kullanılır (olay dinleyicilerini kaldırma, zamanlayıcıyı iptal etme vb.). Diyelim ki bir olay dinleyicisi ekliyor componentDidMountve componentWillUnmountaşağıdaki gibi kaldırıyorsunuz .

componentDidMount() {
  window.addEventListener('mousemove', () => {})
}

componentWillUnmount() {
  window.removeEventListener('mousemove', () => {})
}

Yukarıdaki kodun kanca eşdeğeri aşağıdaki gibi olacaktır

useEffect(() => {
  window.addEventListener('mousemove', () => {});

  // returned function will be called on component unmount 
  return () => {
    window.removeEventListener('mousemove', () => {})
  }
}, [])

184
Diğer Yaşam Döngüsü olayları için güzel bir açıklama, ancak bu özellikle componentWillMount () 'a bir alternatif hakkında soru sormuyor.
Şiraz

3
Gördüğüm PanResponder örneklerinde componentWillMount gerekli görünüyor, aksi takdirde tanımsız panHandlers alıyorsunuz.
Dror Bar

2
Şimdi useEffect()işlevi gerçekten anlıyorum , teşekkürler.
Iharob Al Asimi

68
Bu neden kabul edilmiş bir cevaptır? Bir kanca eşdeğerinden bahsetmedincomponentWillMount
Mykybo

3
@techexpert Soru componentWillMount, buna eşdeğer bir soru sordu , değil componentWillUnmount. Bu cevap gerçekten soruyu hiç cevaplamıyor ve sadece OP'nin zaten bildiğini ima ediyor.
JoshuaCWebDeveloper

62

useComponentDidMount kancası

Çoğu durumda useComponentDidMountkullanılacak bir araçtır. Bileşen monte edildikten sonra yalnızca bir kez çalışır (ilk oluşturma).

 const useComponentDidMount = func => useEffect(func, []);

useComponentWillMount

Sınıftaki bileşenlerin componentWillMountmiras olarak kabul edildiğini belirtmek önemlidir . Bileşen monte edilmeden önce yalnızca bir kez çalıştırmak için koda ihtiyacınız varsa, yapıcıyı kullanabilirsiniz. Burada daha fazlası . İşlevsel bileşenin bir kurucu eşdeğeri olmadığı için, bileşen montajlarından önce yalnızca bir kez kod çalıştırmak için bir kanca kullanmak bazı durumlarda mantıklı olabilir. Özel bir kanca ile elde edebilirsiniz.

const useComponentWillMount = func => {
  const willMount = useRef(true);

  if (willMount.current) {
    func();
  }

  willMount.current = false;
};

Ancak, bir tuzak var. Durumunuzu eşzamansız olarak ayarlamak için kullanmayın (örneğin bir sunucu isteğinin ardından. Beklemeyeceği ilk oluşturmayı etkilemesini beklediğiniz gibi). Bu gibi durumlar ele alınmalıdır useComponentDidMount.

gösteri

const Component = (props) => {
  useComponentWillMount(() => console.log("Runs only once before component mounts"));
  useComponentDidMount(() => console.log("Runs only once after component mounts"));
  ...

  return (
    <div>{...}</div>
  );
}

Tam Demo


18
Soruyu cevaplayan ve mantıklı olan tek cevap budur. Teşekkür ederim!
chumakoff

3
Bununla ilgili tek sorun, durum güncellemesi nedeniyle ekstra bir render elde etmenizdir. Bunun yerine ref kullanarak ekstra davranış olmadan istediğiniz davranışı elde edersiniz: `const useComponentWillMount = func => {const willMount = useRef (true); useEffect (() => {willMount.current = false;}, []); if (willMount.current) {func (); }}; `
remix23

2
Bu fonksiyonel uygulama componentWillMountbazlı tarihinde adlı useEffectiki sorun vardır. Birincisi, fonksiyonel bileşenlerde montaj yaşam döngüsü olmaması, her iki kanca da bileşen işlendikten sonra çalışacaktır, bu yüzden Runs only once before component mountsyanıltıcıdır. İkincisi componentWillMount, sunucu oluşturmada çağrılır ve useEffectdeğildir. Birçok kütüphane hala güvenmektedir, UNSAFE_componentWillMountçünkü şu anda bir yan etki sunucu tarafını tetiklemenin tek yolu budur.
Paolo Moretti

2
@PaoloMoretti, teşekkürler. Bu componentWillMount kancası, bir sınıf bileşenindeki componentWillMount yaşam döngüsünün tam karşılığı değildir. Ancak, kendisine iletilen işlev hemen, sadece ilk çağrıldığında çalışır. Bu pratik olarak, oluşturulmadan önce ve hatta ilk kez bir değer döndürmeden önce çalışacağı anlamına gelir. Bunu kabul edebilir miyiz? ComponentWillMount adını kullanmanın ideal olmadığını kabul ediyorum, çünkü bu ad sınıf yaşam döngüsü sürümünden belirli bir anlam taşıyor. Belki de "useRunPreMount" diyorum.
Ben Carp

1
@PaoloMoretti, tam anlamıyorum. SSR ile çalışmıyorum, ancak benim anlayışım SSR bileşeniWillMount üzerinde iki kez çalışır - bir kez sunucuda ve bir kez istemcide. Ben de useComponentDidMount geçirilen geri arama için aynı olduğunu düşünüyorum. Geri çağrıyı başlatmayı durdurmak için useEffect üzerindeki useComponentDidMount röleleri. UseEffect'in geri çağrısı yürütülene kadar bileşenin işlevi iki kez çalışır - bir kez sunucuda ve bir kez istemcide. Durum böyle değil mi?
Ben Carp

53

Reaktjs.org'a göre, componentWillMount gelecekte desteklenmeyecek. https://reactjs.org/docs/react-component.html#unsafe_componentwillmount

ComponentWillMount kullanmaya gerek yoktur.

Bileşen monte edilmeden önce bir şey yapmak istiyorsanız, bunu yapıcıda () yapın.

Ağ istekleri yapmak istiyorsanız, componentWillMount içinde yapmayın. Çünkü bunu yapmak beklenmedik hatalara yol açacaktır.

Ağ istekleri componentDidMount içinde yapılabilir.

Umarım yardımcı olur.


08/03/2019 tarihinde güncellendi

ComponentWillMount istemenizin nedeni büyük olasılıkla durumu işlemeden önce başlatmak istemenizdir.

Sadece kullanımda yapın.

const helloWorld=()=>{
    const [value,setValue]=useState(0) //initialize your state here
    return <p>{value}</p>
}
export default helloWorld;

ya da örneğin, orijinal kodunuz aşağıdaki gibi görünüyorsa, componentWillMount'ta bir işlev çalıştırmak istersiniz:

componentWillMount(){
  console.log('componentWillMount')
}

kanca ile, yapmanız gereken tek şey yaşam döngüsü yöntemini kaldırmaktır:

const hookComponent=()=>{
    console.log('componentWillMount')
    return <p>you have transfered componeWillMount from class component into hook </p>
}

UseEffect ile ilgili ilk cevaba bir şeyler eklemek istiyorum.

useEffect(()=>{})

useEffect her renderde çalışır, componentDidUpdate, componentDidMount ve ComponentWillUnmount birleşimidir.

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

UseEffect öğesine boş bir dizi eklersek, bileşen monte edildiğinde çalışır. UseEffect'in kendisine ilettiğiniz diziyi karşılaştırmasıdır. Bu yüzden boş bir dizi olmak zorunda değildir. Değişmeyen bir dizi olabilir. Örneğin, [1,2,3] veya ['1,2'] olabilir. useEffect yine de yalnızca bileşen monte edildiğinde çalışır.

Sadece bir kez çalışmasını veya her işlemden sonra çalışmasını isteyip istemediğinize bağlıdır. Ne yaptığınızı bildiğiniz sürece bir dizi eklemeyi unutmanız tehlikeli değildir.

Kanca için bir örnek oluşturdum. Lütfen kontrol et.

https://codesandbox.io/s/kw6xj153wr


21/08/2019 tarihinde güncellendi

Yukarıdaki cevabı yazdığımdan beri beyaz oldu. Dikkat etmeniz gerektiğini düşündüğüm bir şey var. Kullandığınızda

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

Tepki [] dizisine ilettiğiniz değerleri karşılaştırdığında, karşılaştırmak için Object.is () kullanır. Eğer ona bir nesne iletirseniz, örneğin

useEffect(()=>{},[{name:'Tom'}])

Bu tam olarak aynı:

useEffect(()=>{})

Object.is () bir nesneyi karşılaştırdığında, değerin kendisini değil referansını karşılaştırdığı için her seferinde yeniden oluşturulur. {} === {}, neden referansları farklı olduğu için yanlış döndürdüğü ile aynı. Nesnenin kendisini referans değil karşılaştırmak istiyorsanız, bunun gibi bir şey yapabilirsiniz:

useEffect(()=>{},[JSON.stringify({name:'Tom'})])

17
ve soru kancalarla nasıl uygulanacağıydı
Shubham Khatri

3
ancak kancalarla birlikte uygulamanız gerekmez, çünkü desteklenmeyecektir. Bunu kancalarla nasıl yapacağınızı öğrenmeye gerek yok.
MING WU

1
ComponentDidMount'un kullanmak için doğru yaşam döngüsü olduğundan bahsettiğinize göre, cevabınızda bunu nasıl uygulayacağınızı ekleyebilirdiniz ve daha sonra cevabınız kabul edilen cevaptan daha mantıklı olacaktır
Shubham Khatri

8
Şüphesiz bu kabul edilen cevap olmalıdır - ComponentWillMount'un kanca paradigmasında mevcut olmadığını açıklar. Fonksiyonel bileşenlerde başlatma basitleştirilmiştir - sadece fonksiyonun bir parçası olmalıdır
Shiraz

1
Bu componentWillMount ile nasıl aynı? Fonksiyonel bileşene kod atarsanız, yalnızca bileşen takılmak üzereyken değil, her bir oluşturmayı çalıştırır.
Aşırıkoddan

13

useLayoutEffect[]işlevselliği gerçekten benziyorsa, boş bir gözlemci ( ) kümesiyle bunu başarabilir componentWillMount- ilk içerik DOM'a ulaşmadan önce çalışır - aslında iki güncelleme olsa da, ekrana çizim yapmadan önce senkronize olurlar.

Örneğin:


function MyComponent({ ...andItsProps }) {
     useLayoutEffect(()=> {
          console.log('I am about to render!');
     },[]);

     return (<div>some content</div>);
}

useStateBir başlatıcı / ayarlayıcı ile sağlanan fayda veya useEffectbir render geçişini hesaplayabilmesine rağmen, DOM'da bir kullanıcının fark edeceği gerçek yeniden render'lar yoktur ve ilk farkedilen render işleminden önce çalıştırılır ;useEffect . Dezavantajı elbette ilk render işleminizde küçük bir gecikmedir, çünkü ekrana boyamadan önce bir kontrol / güncelleme yapılması gerekir. Yine de, kullanım durumunuza bağlıdır.

Kişisel olarak, useMemoağır bir şey yapmanız gereken bazı niş durumlarda iyi - bence aklınızda bulundurduğunuz sürece norm vs istisnadır.


3
useLayoutEffect gitmek için bir yoldur !!!! Bu kullanıcının oturum olup olmadığını kontrol ile ilgili soruma cevap. (Sorun, bileşenler yüklenir, daha sonra kullanıcının oturum açmış olup olmadığını kontrol eder.) Benim sorum olsa da, bu standart bir uygulama mı? Çok fazla yerde görmüyorum
Jessica

1
evet oldukça yaygın; resmi React belgelerinde de belirtilmiştir - bir kullanıcı fark etmeden önce mantığı çalıştırmak için çift DOM renderinin sonuçları nedeniyle sadece daha küçük metinlerde.
rob2d

Aslında bileşeni oluşturduktan sonra çalışır. Yani componentWillMount'tan tamamen farklı.
Jiri Mihal

7

Bu useRefkanca kullanarak fonksiyonel bileşenleri kurucu simüle nasıl :

function Component(props) {
    const willMount = useRef(true);
    if (willMount.current) {
        console.log('This runs only once before rendering the component.');
        willMount.current = false;        
    }

    return (<h1>Meow world!</h1>);
}

İşte yaşam döngüsü örneği:

function RenderLog(props) {
    console.log('Render log: ' + props.children);
    return (<>{props.children}</>);
}

function Component(props) {

    console.log('Body');
    const [count, setCount] = useState(0);
    const willMount = useRef(true);

    if (willMount.current) {
        console.log('First time load (it runs only once)');
        setCount(2);
        willMount.current = false;
    } else {
        console.log('Repeated load');
    }

    useEffect(() => {
        console.log('Component did mount (it runs only once)');
        return () => console.log('Component will unmount');
    }, []);

    useEffect(() => {
        console.log('Component did update');
    });

    useEffect(() => {
        console.log('Component will receive props');
    }, [count]);


    return (
        <>
        <h1>{count}</h1>
        <RenderLog>{count}</RenderLog>
        </>
    );
}
[Log] Body
[Log] First time load (it runs only once)
[Log] Body
[Log] Repeated load
[Log] Render log: 2
[Log] Component did mount (it runs only once)
[Log] Component did update
[Log] Component will receive props

Tabii ki Sınıf bileşenlerinin Bodyadımları yoktur, farklı işlev ve sınıf kavramları nedeniyle 1: 1 simülasyonu yapmak mümkün değildir.


Örneğinize dalmadım ama ilk kod snippet'iniz benim için çalışıyor, Teşekkürler!
SAndriy

6

İlk render işleminden önce bir işlevi çalıştıracak özel bir kanca yazdım.

useBeforeFirstRender.js

import { useState, useEffect } from 'react'

export default (fun) => {
  const [hasRendered, setHasRendered] = useState(false)

  useEffect(() => setHasRendered(true), [hasRendered])

  if (!hasRendered) {
    fun()
  }
}

Kullanımı:

import React, { useEffect } from 'react'
import useBeforeFirstRender from '../hooks/useBeforeFirstRender'


export default () => { 
  useBeforeFirstRender(() => {
    console.log('Do stuff here')
  })

  return (
    <div>
      My component
    </div>
  )
}

3

Uygulamak için güzel bir çözüm yoktur componentDidMountve componentWillUnmountile useEffect.

Belgelere dayanarak, useEffectbir "temizleme" işlevi döndürebilirsiniz. bu işlev ilk useEffectçağrıda değil, yalnızca sonraki çağrılarda çağrılır .

Bu nedenle, useEffectkancayı hiçbir bağımlılık olmadan kullanırsak, kanca sadece bileşen monte edildiğinde çağrılır ve bileşen söküldüğünde "temizleme" işlevi çağrılır.

useEffect(() => {
    console.log('componentDidMount');

    return () => {
        console.log('componentWillUnmount');
    };
}, []);

Temizleme dönüş işlevi çağrısı yalnızca bileşen bağlantısı kesildiğinde çağrılır.

Bu yardımcı olur umarım.


2
ComponentWillMount ile ilgisi yoksa bu nasıl yardımcı olur ? Bir şey mi kaçırıyorum?
ZenVentzi

Evet, aynı yer olduğu gerçeğini eksik useEffectçağrı Eğer aynı işlevselliği almak componentWillMountve componentWillUnmountgüzel ve temiz bir şekilde
AfikDeri

Bu doğru değil, useEffectyalnızca oluşturma işleminden sonra componentWillMountbileşen oluşturulmadan önce çalışır.
Aşırıkoddan

@Overcode bahsettiğim componentDidMountdeğil componentWillMount. Soruda kaçırdım, kötüyüm.
AfikDeri

1

Bir componentWillMount yaşam döngüsü olayını taklit etmek için useMemo kancasını hackleyebilirsiniz. Sadece yap:

const Component = () => {
   useMemo(() => {
     // componentWillMount events
   },[]);
   useEffect(() => {
     // componentWillMount events
     return () => {
       // componentWillUnmount events
     }
   }, []);
};

Durumunuzla etkileşime giren herhangi bir şeyden önce useMemo kancasını tutmanız gerekir. Amaçlanan bu değil ama tüm componentWillMount sorunları için benim için çalıştı.

UseMemo aslında bir değer döndürmek gerekmez ve aslında bir şey olarak kullanmak zorunda değilsiniz çünkü çalışır, ama sadece bir kez ("[]") ve onun bileşeninin üstünde çalışacak bağımlılıklara dayalı bir değeri ezberlemek bileşen her şeyden önce monte edildiğinde bir kez çalışır.


0

https://reactjs.org/docs/hooks-reference.html#usememo

UseMemo öğesine iletilen işlevin oluşturma sırasında çalıştığını unutmayın. Orada render işlemi yaparken normalde yapmayacağınız hiçbir şey yapmayın. Örneğin, yan etkiler kullanımdadır.Mükemmel değil kullanım.


usememo performans optimizasyonu içindir. Bir pervane değişmesi durumunda, yazarın amacını yenen bir kanca zaten monte edildikten sonra bir kanca oluşturulacaktır.
max54

0

Ben Carp'ın yanıtı benim için sadece geçerli gibi görünüyor.

Ancak fonksiyonel yolları kullandığımız için, kapatma ve HoC'den sadece başka bir yaklaşım faydalanabilir:

const InjectWillmount = function(Node, willMountCallback) {
  let isCalled = true;
  return function() {
    if (isCalled) {
      willMountCallback();
      isCalled = false;
    }
    return Node;
  };
};

Sonra kullanın:

const YourNewComponent = InjectWillmount(<YourComponent />, () => {
  console.log("your pre-mount logic here");
});

0

Orijinal sorunuzun kısa cevabı componentWillMount, React Hooks ile nasıl kullanılabilir:

componentWillMountkullanımdan kaldırılıyor ve miras olarak kabul ediliyor . Reaksiyon önerisi :

Genel olarak, durumu başlatmak için yapıcı () kullanmanızı öneririz.

Şimdi Hook SSS bölümünde, işlev bileşenleri için bir sınıf yapıcısının eşdeğerinin ne olduğunu öğreneceksiniz:

constructor: İşlev bileşenlerinin bir kurucuya ihtiyacı yoktur. UseState çağrısında durumu başlatabilirsiniz. Başlangıç ​​durumunu hesaplamak pahalıysa ,State işlevini kullanmak için bir işlev iletebilirsiniz.

Yani bir kullanım örneği componentWillMountşöyle:

const MyComp = () => {
  const [state, setState] = useState(42) // set initial value directly in useState 
  const [state2, setState2] = useState(createInitVal) // call complex computation

  return <div>{state},{state2}</div>
};

const createInitVal = () => { /* ... complex computation or other logic */ return 42; };

0

Kullanımda boş bir bağımlılık dizisi eklemeniz yeterlidir componentDidMount.

useEffect(() => {
  // Your code here
  console.log("componentDidMount")
}, []);

0

componentDidMountVe componentWillUnmountkullanarak simüle etmek için basit bir hile var useEffect:

useEffect(() => {
  console.log("componentDidMount");

  return () => {
    console.log("componentWillUnmount");
  };
}, []);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.