Komponenty funkcyjne i rerender

0

Dzień dobry,
Mam problem podczas nauki reacta.

  { id: 1, title: "Wiadomosc numer 1", body: "Zawartosc wiadomosci numer 1" },
  { id: 2, title: "Wiadomosc numer 2", body: "Zawartosc wiadomosci numer 2" },
  { id: 3, title: "Wiadomosc numer 3", body: "Zawartosc wiadomosci numer 3" },
];
setInterval(() => {
  const index = data.length + 1;
  console.log("aktualizacja");
  data.push({
    id: index,
    title: `Wiadomosc numer ${index}`,
    body: `Zawartosc wiadomosci numer ${index}`,
  });
}, 2000);

const App = () => {
  const [comments, setComments] = useState(data);
  console.log(comments);
  const getData = () => {
    setComments(data);
  };
  useEffect(() => {
    setInterval(() => {
      console.log("update z setinterval");
      getData();
    }, 5000);
  }, []);
  let divs = comments.map((comment) => (
    <div key={comment.id}>
      <h4>{comment.title}</h4>
      <div>{comment.body}</div>
    </div>
  ));
  return (
    <div className="App">
      <>{divs}</>
    </div>
  );
};

React nie rerenderuje divów po użyciu map().
Robi to tylko na początku, a potem nie aktualizuje wiadomości z tablicy.
Może mi ktoś wytłumaczyć jak to działa?

0

Czemu rozdzieliłeś kod na dwa setInterval z czego jedno jest poza komponentem App i hookiem useEffect/useLayoutEffect?

0

Robiłem z kursu to tylko, że autor kursu użył komponentu klasowego w którym to działa, a ja chcę się dowiedzieć jak to samo zrobić z komponentem funkcyjnym

0

Rozumiem, ale pytam, dlatego, bo jest to źle zrobione. Nie powinno się modyfikować stanu poza Reactem, a pierwsze użycie setInterval tym właśnie jest.

Problem renderowania naprawia spread operator, bo nie jest kopiowana referencja do tablicy, która zostaje zmodyfikowana poza Reactem... w jakiś dziwny sposób.

const [comments, setComments] = useState([...data]); // <-- podczas przypisania tablicy trzeba użyc spread operatora

const getData = () => {
  setComments([...data]); // tutaj tak samo spread operator
};

I to wystarczy, żeby przykład zadziałał i zaczął renderować nowe elementy.

Dodatkowo podrzucam kod jak to powinno wyglądać uporządkowane, bo cały ten fragment z przykładu powinien się znaleźć wewnątrz komponentu App

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

const App = () => {
  console.log('render');

  const data = useRef([
    { id: 1, title: 'Wiadomosc numer 1', body: 'Zawartosc wiadomosci numer 1' },
    { id: 2, title: 'Wiadomosc numer 2', body: 'Zawartosc wiadomosci numer 2' },
    { id: 3, title: 'Wiadomosc numer 3', body: 'Zawartosc wiadomosci numer 3' },
  ]);
  const [comments, setComments] = useState([...data.current]);

  useEffect(() => {
    const primaryID = setInterval(() => {
      console.log('aktualizacja -> data');

      const index = data.current.length + 1;

      data.current.push({
        id: index,
        title: `Wiadomosc numer ${index}`,
        body: `Zawartosc wiadomosci numer ${index}`,
      });
    }, 2000);

    const secondaryID = setInterval(() => {
      console.log('aktualizacja -> comments');

      setComments([...data.current]);
    }, 5000);

    return () => {
      clearInterval(primaryID);
      clearInterval(secondaryID);
    };
  }, []);

  const divs = comments.map((comment) => (
    <div key={comment.id}>
      <h4>{comment.title}</h4>
      <div>{comment.body}</div>
    </div>
  ));

  return <div className="App">{divs}</div>;
};

export default App;

0

Dzięki wielkie @Xarviel .

1 użytkowników online, w tym zalogowanych: 0, gości: 1