• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

[React] Custom hook bez przeładowania rodzica

Object Storage Arubacloud
+1 głos
306 wizyt
pytanie zadane 31 stycznia 2022 w JavaScript przez Oskar Szkurłat Bywalec (2,780 p.)

Cześć,

Chciałem sobie uwspółcześnić kod, bo miałem wrapper komponentu (taki ala HOC), który zwracał callback z obiektem z referencjami do zmieniania stanów wewnątrz tego wrappera. I to działało, dokładnie tak jak chciałem, czyli miałem np. buttonComponent.setText('nowy tekst'). Po wywołaniu metody przychodzącej z callbacka, odświeżany był z nowym napisem tylko przycisk, a rodzic trzymający go już nie.

Postanowiłem zamienić wrapper w customowego hooka. Jednak nie przewidziałem, że stany z customowego hooka są trzymane w rodzicu? Tak przynajmniej najwyraźniej sądzę, bo przy przerenderowaniu teraz przycisku, przerenderowywany jest również rodzic :(.

const buttonToChangePattern = useAntPattern(buttonToChangeOptions.current)

Czy ktoś ma pomysł, jak mógłbym to zabezpieczyć, żeby przeładowywał się tylko np. przycisk, a div trzymający różne przyciski nie? Bo nie chciałbym robić specjalnie teraz otoczki w postaci kolejnego komponentu, bo wtedy ten hook mija mi się z celem.

Czy da się sprawić, żeby customowy hook działał, jak komponent, tzn. miał swoje oddzielne pamięci i przy zmianie zmieniał się tylko on? Bo wydawało mi się, że tak powinno to działać w Reacie. Na różnych filmikach widziałem, że można bez problemu z HOC przejść na hook.

Link do kodu na Git Hubie:
https://github.com/Amaranthusss/ant-design-patterns

Przykładowo w komponencie ButtonExample.ts można postawić breakpoint na return i wtedy widać, że przy przerenderowaniu przycisku (który jest zwracany z hooka), przeładowuje się cały ButtonExample.ts

A może jeszcze w czymś innym robię błąd i stąd te przeładowanie rodzica?

Z góry dzięki.

1 odpowiedź

+3 głosów
odpowiedź 1 lutego 2022 przez rafal.budzis Szeryf (85,260 p.)
wybrane 2 lutego 2022 przez Oskar Szkurłat
 
Najlepsza
Musisz sobie zadać pytanie co robił HOC. A HOC tworzy często nowy komponent i przekazuje zmodyfikowane propsy. Więc bez tworzenia nowego komponentu się nie obędzie również w przypadku hooka.

Komponent w którym jest wywoływołanie hooka zawsze się ponownie wyrenderuje gdy zmieni się w jego state.

Jak chcesz coś jeszcze dopytać to śmiało. Nie podaje przykładu ponieważ powiem szczerze że nie chce mi się szukać tego kodu w tym repo. Jak coś wrzuć konkretny kod z 2 plików rodzic > dziecko to może będę w stanie podpowiedzieć coś więcej ;)

Ogólnie w React im więcej małych komponentów tym lepiej ;)
komentarz 1 lutego 2022 przez Oskar Szkurłat Bywalec (2,780 p.)
edycja 1 lutego 2022 przez Oskar Szkurłat

Oki, po doczytaniu w dokumentacji Reacta i z tego co tutaj napisałeś, faktycznie wychodzi na to, że customowe hooki, mimo że są odrębną funkcją, w tym przypadku zwracającą komponent, stany przechowują w rodzicu. Stąd te przerenderowania. Bo customowy hook to dalej hook, czyli tylko funkcja bez ciała.

Mój hook z założenia miał zwracać komponent (jako parametr element) i obiekt z referencjami do metod zmieniającymi stany w tym komponencie i tylko w nim, nazwany controller.

Podlinkowuję przykład, gdzie widać, w jaki sposób ja korzystałem, tzn. tu jest rodzic ButtonExample, który ma w sobie dwa wywołania mojego customowego hooka useAntPattern. Czyli zamysł był taki, że tworzę dwa komponenty wewnątrz tego rodzica i steruję z poziomu rodzica dziećmi i ich przerenderowaniami w środku. Przycisk buttonToChangeIconPattern po wciśnięciu zmienia ikonkę w buttonToChangePattern. I są to te dzieci-komponenty.

Więc teraz rozumiem, że bez budowania zwykłego komponentu, jako wrapper/pattern/hoc (w sumie o to może chcę dopytać, jakie nazewnictwo jest poprawne dla reacta najbardziej dla definicji komponentu uniwersalnego, a może używa się ich wszystkich i coś innego oznaczają? W stylu klasy z OOP, gdzie konfigurujesz wartości stałe (tu przez props) i komponent potem żyje swoim życiem, zarządza swoimi pamięciami i można go wywoływać w wielu miejscach i konfigurować do potrzeb wywołania. Przykładem może być tabelka z przyciskami w toolbaru, gdzie na stronie A jest przycisków np. 4, a na stronie B przycisków 7, w zależności od potrzeb. A mimo to unika się powielania kodu i całej jego logiki przez użycie takiego komponentu.

A może masz pomysł na jeszcze inne, eleganckie rozwiązanie przerobienia hooka, tak aby zwracał komponenty z odrębnymi obszarami swoich pamięci? Bo staram się nauczyć dobrych nawyków Reactowych, bo póki co programuję na zasadzie "ja bym zrobił to tak". :D

Super odpowiedź, dziękuję :)

1
komentarz 2 lutego 2022 przez rafal.budzis Szeryf (85,260 p.)

O kurczę racja twój hook w tej chwili jest nieco bez sensu bo bardziej przypomina komponent niż hooka. I wydaje mi się że było by łatwiej gdybyś go przerobił po prostu na komponent :) 

W react nie musisz samemu sterować renderem dzieci. Zostaw to reactowi! React za każdym razem renderuje dzieci gdy przekazujesz nowe propsy ;) 

Hooki są po to aby w komponencie było mniej logiki :) Tutaj mały przykłąd jak można to wykorzystać ;) 

 

import { ChangeEvent, useCallback, useRef, useState } from 'react'
import { Tooltip } from 'antd'
import _ from 'lodash'

import {
  IPatternOptions,
  IValue,
} from './interface';

// hook
const usePreparedOnChangeCallback = (props: IPatternOptions<any>) => {
    const [value, setValue] = useState<IValue>()

    const onChange = useCallback(
      (event: ChangeEvent<any>): void => {
        setValue(event.target.value)
        if (_.isFunction(props.default?.onChange)) {
          props.default?.onChange(event)
        }
      },
      [props.default]
    )

    return {onChange, value}
}

// component
const AntPatternComponent = (props: IPatternOptions<any>) => {
    const [options, setOptions] = useState<any>(props.default ?? {})
    const [tooltipOptions, setTooltipOptions] = useState<any>(
        props.tooltipOptions ?? ({} as any)
    )
    const {onChange, value} = usePreparedOnChangeCallback(props);

    return  <Tooltip {...tooltipOptions}>
        <props.element {...options} onChange={onChange} value={value}>
          {options?.children ?? undefined}
        </props.element>
    </Tooltip>

}

export default AntPatternComponent

Zwróć uwagę że dzięki użyciu hooka w komponencie nie jest dostępna funkcja setValue więc masz lepszą separacje/hermetyzacje ;) 

komentarz 18 lutego 2022 przez Oskar Szkurłat Bywalec (2,780 p.)

W sumie teraz mi nasunęło się pytanie - w jaki sposób Ty proponujesz układać hooki w projekcie w takim przypadku? Bo za pomocą customowego hooka zapewniłem hermetyzację, ale on dotyczy tylko tego komponentu.

Na ogół widziałem, że customowe hooki trzyma się w globalnym folderze hooks. Ale gdy tam trzymać będę hook dotyczący tego komponentu, to czy to nie jest zbyt duży rozrzut po projekcie? Lepiej trzymać customowe hooki w folderze komponentu, którego dotyczą? A globalne / uniwersalne hooki w tym folderze hooks?

Jeżeli tak, to czy dobrym będzie według Ciebie standardem stworzenie jednego pliku eksportującego wszystkie custom hooki dla tego komponentu? np. AntPattern.hooks.ts, a w nim export const useOnInputChanged = (...) => {...} ?

 

1
komentarz 18 lutego 2022 przez rafal.budzis Szeryf (85,260 p.)

Odnośnie układania plików obowiązuje jedna zasada. Zmieniał ułożenie plików aż nie poczujesz że jest dobrze ;) Mi się bardzo podoba koncepcja trzymania globalnych hooków w hooks a customowe odnoszące się do jednego komponentu w folderze tego komponentu. Sam tak robię i polecam ;) 

Co do plików ja wole mieć każdy hook w osobnym pliku ;) Ja u siebie robię tak :

- root
    - hooks
        - useCośTam.ts
    - components
        - Button
            - hooks
                - useCośButton.ts
            - Button.tsx
            - Button.test.tsx

 

Podobne pytania

+1 głos
1 odpowiedź 151 wizyt
pytanie zadane 27 maja 2021 w JavaScript przez p4wix Obywatel (1,040 p.)
0 głosów
1 odpowiedź 267 wizyt
pytanie zadane 29 grudnia 2020 w JavaScript przez sKodowany Obywatel (1,150 p.)
0 głosów
1 odpowiedź 262 wizyt

92,555 zapytań

141,403 odpowiedzi

319,557 komentarzy

61,940 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...