React: componente care interacționează între ele

M-am pierdut în hățișul React-ului și am nevoie de cineva cu o busolă :slight_smile:

Am înțeles cum fac handing-ul evenimentelor în interiorul unei componente, capturez event-ul și modific unul dintre state-urile componentei pentru a triggera randarea. Dar cum fac să export o funcție (sau state?) ca să fie accesibil din “exterior”?

De exemplu un scenariu de genul ăsta:

<Button onClick={vreau sa triggerez refresh-ului componentei de mai jos} title="Refresh" />
<ProductList functia_de_triggerare_a_refresh_ului={cum_ajung_aici?} />

Intuiesc vag că aș putea avea un state în Button pe care să-l partajez cu ProductList, și când Buton-ul alterează acel state, să reacționeze și lista. Dar mi se pare forțat și arficial, nici nu sunt sigur că ar funcționa.

Idei?

Vocea #1 are dreptate. Vocea #2 nu :slight_smile:

In React, totul functioneaza pe baza de state.

Da, nasol cu vocile astea disonante :slight_smile: Deci ar trebui să meargă ceva de genul, right?

function Container() {
   const [blabla, setBlabla] = useState(0);

   <Button onClick={setBlabla} />
   <ProductList state={blabla} />
}

Parcă ar avea logică, dar nu-mi dau seama dacă React e suficient de deștept pentru asta, trebuie să testez. Chestia cu hook-urile este că sunt deosebit de intortocheate, greu de înțeles când vor funcționa și când nu.

E destul de destept, numai la ProductList ii pasezi
state={blabla}
in cazul asta

Edit: si cum zicea mai jos pghoratiu dupa mine, in button nu ar trebui sa ai acces la chestia care ar trebui sa fie noul state, deci vrei sa scrii setarea de noul state tot in componenta container, iar in Button doar sa chemi props.onClick

E cea mai proasta idee sa ai un state in button. Ideal este sa pastrezi un singur state undeva la nu nivel superior in cazul tau e vorba de componenta care include si butonul si lista. Nu distribui state-ul intre componente mai mici, o sa ai multe probleme.

La componenta de button transmiti doar un callback care sa modifice state-ul componentei parinte. In componenta parinte vei avea de asemenea state pentru lista si faci push acolo la date.

Asta ar fi varianta cea mai simpla, te poti complica ulterior cu state centralizat la nivel de app (redux & friends).

<Button onClick={() => setProductList([])} title="Refresh" />
// astea sunt date din state, sa fii sigur ca modifici referenta la array altfel nu se detecteaza modificarile
<ProductList productList={productList} /> 

Da, da, inițial le-am denumit “state”, dar ca să nu fie vreo cofuzie le-am redenumit in “blabla”.

Right, când am început să scriu exemplul mi-am dat seama că state-ul ar trebui instanțiat într-un container care le conține pe amândouă. Dupa care variabila s-o pasez componentei pasive, adică lista, iar funcția s-o pasez “executorului”, adică butonului. Makes sens. Nu eram sigur că React știe dacă știe să manipuleze hook-urile în felul ăsta. Dacă da, este deosebit de deștept :slight_smile:

Mare atentie cu asta onClick={setBlabla} poti sa ai multe probleme:

Ca regula generala eu tot timpul folosesc sintaxa

onClick={() => setBlabla()}

daca nu vrei sa te complici cu setBlaBla,bind().

Gata, am înţeles, butonul doar ar trebui să cheme un lambda de-al părintelui. Butonul doar dă un semnal părintelui că userul a dat click pe buton, modul în care e modificat state-ul e în sarcina Container-ului.

Mersi de ajutor, m-aţi scutit de multe săpături prin internet.

Nu trebuie sa sapi pentru asa ceva, React are documentatie destul de buna cu exemple bune

Da, ştiu, am citit o parte din ea deja, dar e foarte multă informaţie de asimilat. Problema unui începător cu framework nou este mai degrabă cauzată de faptul că nu citeşte informaţiile alea în cheia corectă. O scurtă conversaţie cu cineva familiarizat poate aduce instant lumină acolo unde mai devreme părea beznă. În câteva minute, de la o intuiţie vagă am sărit la înţelegere aproape totală :slight_smile:

1 Like

Hooray, chiar funcţionează. Dacă o să mai fie cineva interesat în viitor, las aici un exemplu funcţional.

import { useState } from "react";

function Button({ onClick }) {
    return(
        <button onClick={ onClick }>Click me!</button>
    );
}


function Counter({ blabla }) {
    return (
        <div>{ blabla }</div>
    );
}

function App() {
    const [ blabla, setBlabla ] = useState(0);

    return (
        <div>
            <Button onClick={ () => setBlabla(blabla + 1) } />
            <Counter blabla={ blabla }/>
        </div>
    );
}

export default App;
1 Like

O chestie de care probabil ca o sa te lovesti, in cazul in care variabila de state blabla este un array sau obiect cand vrei ca react stie ca a fost modificat va trebui sa modifici referinta.

Exemplu:

blabla.push(12) - nu schimba referinta, array-ul ramane acelasi cu un extra element, nu se face re-rendering.
[…blabla] sau blabla.slice(0) - faci o copie a array-ului original care contine si extra elementul respectiv.

Pentru tipurile simple de date JS string/number/boolean nu ai problema asta.

Păi stai puţin, nu e obligatoriu să foloseşti întotdeauna setterul (sau cum se cheamă funcţia aia) pentru a modifica state-ul? Că cel puţin în scenariul nostru blabla este oricum declarat const, nu ai cum să faci push asupra lui.

Din cate îmi dau seama, array-ul/obiectul trebuie clonat, clona modificată şi trimisă lui setBlabla(). Pare cam ineficient, mai ales dacă array-urile sunt mari.

Ba da, dar dacă ai de exemplu:

const [foo, setFoo] = setState({bar: 0});

Va fi foarte tentant să faci ceva de genul foo.baz = 1. Și te vei scărpina foarte eficient în creștetul capului când nu va funcționa :smiley:

Btw, fii atent și la treaba asta, că eu m-am ars bine de tot :facepalm:

https://blog.iamntz.com/20427/atunci-cand-nu-mai-stii-javascript/

Hehe, da, știam de treaba asta, n-am ales întâmplător expresia “array-ul/obiectul trebuie clonat” (în loc de “copiat”). Copierea e o chestie înșelătoare în limbajele care nu fac distincție foarte clară între referință și copie.

Dacă nu mă însel, în php e o chestie asemănătoare, trimiți un obiect într-o funcție, îl modifici în funcție crezând că lucrezi asupra unei copii locale și te trezești că s-a modificat și obiectul original din funcția apelantă.

Doar referinta la obiect/array e constanta, tu poti sa modifici orice vrei in el si sa pastrezi aceeasi referinta.

Este.
Ca sa minimizeze impactul pe rendering cand afisezi linii care reprezinta date dintr-un array va trebui sa folosesti prop-ul “key” care ar trebui sa reprezinte un ID unic al entitatii. In acest caz la re-render va face rendering doar la diferenta (elementul nou adaugat pe care a putut sa-l identifice prin ID).

1 Like

Dap, exemplu:

function x($obj)
{
    $obj->blabla = 42;
}

function y()
{
    $obj = new stdClass;
    $obj->blabla = 7;

    x($obj);

    echo $obj->blabla;
}

y();

Rezultat echo: 42. Foarte intuitiv, right? :slight_smile:

Numa mie mi se pare absolut normal ca functioneaza asa? :thinking:

2 Likes

Bleah, ai dreptate, poți să faci push într-un array declarat const. Mă rog, nu că m-aș aștepta ca React să triggereze ceva dacă modific o variabilă, nu cred în magie :slight_smile: Deși… se aparent s-ar putea face: https://www.codegrepper.com/code-examples/javascript/javascript+variable+observer