Yaşam döngüsü yöntemlerini kancalara tepki verin

Dec 16 2020

Makaleler içeren basit bir blogum var. Ve sınıfları işlevsel bileşenlere ve kancalara yeniden yazmak istiyorum. Şimdi bu mantığı düzenle / ekle formuyla sayfam için yaşam döngüsü yöntemlerinde aldım: iyi çalışıyor.

componentDidUpdate(prevProps, prevState) {
 if (this.props.match.params.id !== prevProps.match.params.id) {
    if (prevProps.match.params.id) {
        this.props.onUnload();
      }

      this.id = this.props.match.params.id;
        if (this.id) {
            return this.props.onLoad(userService.articles.get(this.id));
        }
        this.props.onLoad(null);
   }
   this.isLoading = false;
}

componentDidMount() {
  if (this.id) {
    this.isLoading = true;
    return this.props.onLoad(userService.articles.get(this.id));
  }
  this.isLoading = false;
  this.props.onLoad(null);
}
   
componentWillUnmount() {
   this.props.onUnload();
}
   
shouldComponentUpdate(newProps, newState) {
   if (this.props.match.params.id !== newProps.match.params.id) {
      this.isLoading = true;
   }
   return true;
}

Hepsini böyle kancalara yeniden yazdım:

//componentDidMount
  useEffect(() => {
    if (id) {
      setIsloading(true);
      return props.onLoad(userService.articles.get(id));
    }
    setIsloading(false);
    props.onLoad(null);
  }, []);

  useEffect(()=> {
      prevId.current = id;
      }, [id]
  );

  //componentDidUpdate
  useEffect(() => {
    //const id = props.match.params.id;
    if (id !== prevId.current) {
      if (prevId.current) {
        props.onUnload();
      }
      if (id) {
        return props.onLoad(userService.articles.get(id));
      }
      props.onLoad(null);
    }
    setIsloading(false);
  });

  //componentWillUnmount
  useEffect(() => {
     return props.onUnload();
  }, []);

  1. Hata aldım - "Çok fazla yeniden işleme var." codeandbox tam kodunda: codesandbox

Tuhaf, ancak localhost'ta "Çok fazla yeniden işleme" hatası yok.

  1. Sınıfımın "shouldComponentUpdate" metodunu kancalara nasıl yeniden yazacağımı bilmiyorum. "Not" u denedim, ancak bu durumda nasıl yazılacağı hakkında hiçbir fikrim yok.

  2. Ve yine de bir şeyi kaçırıyorum çünkü hepsi işe yaramayacak - form alanlarını düzgün bir şekilde güncellemiyor.

React kancaları hakkında iyi bir bilginiz varsa lütfen yardım edin veya biraz tavsiye verin - nasıl düzeltilir?

Yanıtlar

3 Mhmdrz_A Dec 18 2020 at 21:24

Bağımlılık içermeyen etki neden oluyor "Too many re-renders.": her işlemeden sonra çalışıyor, ardından setIsLoadingstate ( loading) ' yi güncellemeye çağırıyor , bu da bileşenin yeniden oluşturulmasına neden olacak, bu da effecttekrar çalıştıracak ve tekrar setStateçağrılacak effectve böyle devam edecek ...

//componentDidUpdate
  useEffect(() => {
    //const id = props.match.params.id;
    if (id !== prevId.current) {
      if (prevId.current) {
        props.onUnload();
      }
      if (id) {
        return props.onLoad(userService.articles.get(id));
      }
      props.onLoad(null);
    }
    setIsloading(false);
  })

sorunu çözmek için ya setIsLoadingondan kaldırın ya IsLoadingda bağımlılık olarak ekleyin .

//componentDidUpdate
  useEffect(() => {
    ...
    setIsloading(false);
  },[isLoading]);

ayrıca iki bağlama efektini buna benzer şekilde birleştirebilirsiniz (sizinki de çalışıyor, ancak bunun biçimsel olarak tercih edilebilir olduğunu düşünüyorum):

//componentDidMount
  useEffect(() => {
    if (id) {
      setIsloading(true);
      return props.onLoad(userService.articles.get(id));
    }
    setIsloading(false);
    props.onLoad(null);

    //componentWillUnmount
    return function () {
      props.onUnload()
    }
  }, []);

ikinci madde için: bileşeninizin yeniden yazılması hakkında shouldComponentUpdate; Öncelikle shouldComponentUpdate, her zaman geri döndüğünüz trueve sadece loadingdurumu tetiklemek için kullandığınız için mevcut durumunuzun makul olmadığını belirtmeliyim; ve React.memo ile yazılmaya uygun değildir (~ shouldComponentUpdatesınıf bileşenlerine eşdeğerdir ); bu nedenle, loadingdurumu belirlemek için her props değişikliğinde çalıştırılacak bir şeye ihtiyacınız vardır propsve bunun için bağımlılığı aşağıdaki gibi bir efekt kullanabilirsiniz :

//manually keeping old props id
const prevPropsId = useRef();

useEffect(() => {
   if (prevPropsId.current !== props.match.params.id) {
      setIsLoading(true);
   }
   prevPropsId.current = props.match.params.id;
 }, [props.match.params.id]);
// this hook only run if `props.match.params.id` change 

Benim farkındalığıma göre, bu işi yapacak, (ilk etapta mantığı neden bu şekilde yazdığınızı anlamakta zorlanmanıza rağmen) ve eğer iyi gitmiyorsa, mantığı ihtiyaçlarınıza uyacak şekilde biraz ayarlayabilirsiniz, sahne değişim efektinin nasıl çalıştığını düşünün. Ayrıca birçok kolu gereğini typeErrordurumunda id, paramsya da matchyok ve Opsiyonel zincirleme burada kullanışlı bir araç olabilir ->props.match?.params?.id

2 deckele Dec 23 2020 at 23:26

Eski yaşam döngüsü kancalarını kaçırırsanız, bunları her zaman özel kancalar olarak yeniden oluşturabilirsiniz:

function useComponentDidMount(effect) {
  useEffect(() => {
    effect();
  }, []);
}
function useComponentWillUnmount(effect) {
  useEffect(() => {
    return effect;
  }, []);
}
function useComponentDidUpdate(effect, dependencies) {
  const hasMountedRef = useRef(false);
  const prevDependenciesRef = useRef(null)
  useEffect(() => {
    // don't run on first render, only on subsequent changes
    if (!hasMountedRef.current) {
      hasMountedRef.current = true;
      prevDependenciesRef.current = dependencies;
      return;
    }
    // run effect with previous dependencies, like in componentDidUpdate!
    effect(...prevDependenciesRef.current || []);
    prevDependenciesRef.current = dependencies;
  }, dependencies)
}

Kullanım (örneğiniz yeniden düzenlendi):

  //componentDidMount
  useComponentDidMount(() => {
    if (id) {
      setIsloading(true);
      props.onLoad(userService.articles.get(id));
      return;
    }
    setIsloading(false);
    props.onLoad(null);
  });

  //componentDidUpdate
  useComponentDidUpdate((prevId) => {
    if (prevId) {
      props.onUnload();
    }
    if (id) {
      props.onLoad(userService.articles.get(id));
      return;
    }
    props.onLoad(null);
    setIsloading(false);
  }, [id]);

  //componentWillUnmount
  useComponentWillUnmount(() => {
     props.onUnload();
  });