Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Zacznij używaćHooków() w Reakcie

Zacznij używaćHooków() w Reakcie

Wygląda na to, że hooki będą wkrótce częścią Reacta, niezależnie czy tego chcemy czy nie.
Przyjrzyjmy się zatem czym są, jak działają i co mogą nam dać.

Kod źródłowy będzie dostępny na stronie http://kursreacta.pl/hooki

85977ebfe59c2ee669f2196930f1a701?s=128

Michał Taszycki

November 28, 2018
Tweet

Transcript

  1. Zacznij używaćHooków() w Reakcie

  2. Hooki? A co to?

  3. Hooki? A co to? — propozycja nowego API reacta —

    nic magicznego, wbrew pierwszemu wrażeniu — funkcje, które dają większe moźliwości komponentom funkcyjnym — dodają m.in. stan, efekty uboczne oraz referencje
  4. Hooki? A po co to komu?

  5. Hooki? A po co to komu? — Umożliwiają tworzenie prawie

    wszystkiego za pomocą funkcjonalnych komponentów — Zwiększają reużywalność kodu (zwłaszcza w obrębie efektów ubocznych) — eliminują część zastosowań HOC i renderProps
  6. ReactJS krótkie przypomnienie

  7. Funkcyjny komponent function Product(props) { return ( <div onClick={() =>

    props.onClick(props)}> <h3>{props.name}</h3> <div>For only ${props.price}</div> </div> ); }
  8. Funkcyjny komponent function Products({ products, onProductClick }) { return (

    <div> {products ? ( <div> <h1>Products:</h1> {products.map(product => ( <Product key={product.id} {...product} onClick={onProductClick} /> ))} </div> ) : ( <h1>Loading products...</h1> )} </div> ); }
  9. Komponent klasowy class ProductsPage extends React.Component { state = {

    products: [] } componentDidMount() { fetchProducts().then(results => this.setState({ products: results })) } render() { return ( <Products products={this.state.products} /> ); } }
  10. Komponent funkcyjny z hookami function ProductsPage() { const [products, setProducts]

    = useState([]); setEffect(() => { fetchProducts().then(results => setProducts(results)); }, []) return ( <Products products={products} /> ); }
  11. Najważniejsze wbudowane hooki — useState() — useEffect() — useRef() —

    useContext()
  12. Pozostałe wbudowane hooki — useLayoutEffect() — useMutationEffect() — useImperativeMethods() —

    useMemo() — useCallback() — useReducer()
  13. useState()

  14. useState() Pozwala na używanie stanu w komponentach funkcyjnych const [currentState,

    stateSetterFunction] = useState(initialState);
  15. useState() Na przykład function SillyEmailComponent() { const [email, setEmail] =

    useState("bob@example.com"); return ( <div> <h1>{email}</h1> <button onClick={() => setEmail("alice@example.com")} /> </div> ) }
  16. useState() Odpowiednik w klasowym komponencie class SillyEmailComponent extends ReactComponent {

    state = { email: "bob@example.com" }; render() { return ( <div> <h1>{this.state.email}</h1> <button onClick={() => this.setState({ email: "alice@example.com" })} /> </div> ) } }
  17. setState() Jeden stan na wiele danych class SillyEmailComponent extends ReactComponent

    { state = { email: "bob@example.com", firstName: "Bob" }; render() { return ( <div> <h1>"{this.state.firstName}" <{this.state.email}></h1> <button onClick={() => this.setState({ email: "alice@example.com", firstName: "Alice" })} /> </div> ) } }
  18. setState() działa wybiórczo state = { email: "bob@example.com", firstName: "Bob"

    }; // This will update only email and leave firstName intact this.setState({ email: "Alice" });
  19. useState() Nie uaktualnia stanu wybiórczo const [emailAndName, setEmailAndName] = useState({

    email: "bob@example.com", firstName: "Bob" }); // This will replace the whole state!!! setEmailAndName({ email: "Alice" }) // This will work as set state setEmailAndName(prevState => {...prevState, email: "Alice" })
  20. useState() Pozwala mieć wiele niezależnych zniennych stanowych function SillyEmailComponent() {

    const [email, setEmail] = useState("bob@example.com"); const [firstName, setFirstName] = useState("Bob"); return ( <div> <h1>"{firstName}" <{email}></h1> <button onClick={() => { setEmail("alice@example.com") setFirstName("Alice") }} /> </div> ) }
  21. useState() Se!er pozwala na zmianę za pomocą funkcji bardzo ważne

    jeśli nowy stan zależy od poprzedniego function Counter() { const [count, setCount] = useState(0); return ( <div> Count: {count} <button onClick={() => setCount(0)}>Reset</button> <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button> <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button> </div> ); }
  22. useState() Odpowiednik w klasowym komponencie class Counter extends ReactComponent {

    state = { count: 0 }; render() { return ( <div> Count: {count} <button onClick={() => setState({ count: 0)}>Reset</button> <button onClick={() => setState(state => ({count: state.count + 1})}>+</button> <button onClick={() => setState(state => ({count: state.count - 1})}>-</button> </div> ) } }
  23. useState() Pozwala na inicjalizacje za pomocą funkcji Przydatne jeśli to

    kosztowna operacja const [count, setCount] = useState(() => calculateFibonacciNumber(100)); Zamiast const [count, setCount] = useState(calculateFibonacciNumber(100));
  24. useEffect()

  25. useEffect() przyjmuje funkcję, która zajmie się efektami oraz (opcjonalną) tablicę

    zależności useEffect( functionThatHandlesEffect, arrayWithDependencies );
  26. useEffect() domyślnie odpala funkcję po każdym renderze useEffect(() => {

    // will run after every render() window.document.title = "New title"; });
  27. useEffect() odpowiednik w klasowym komponencie componentDidMount() { // will run

    after first render() window.document.title = "New title" } componentDidUpdate() { // will run after subsequent render() window.document.title = "New title" }
  28. useEffect() pozwala posprzątać po sobie za pomocą funkcji zwróconej z

    funkcji efektu useEffect(() => { // will run after every render() const subscriptionId = subscribeToChannel(props.channelId); return () => { // will clean up before executing next effect // or before the component is removed from UI removeSubscription(subscriptionId); }; });
  29. useEffect() może uruchamiać się warunkowo np. kiedy jakaś zależność się

    zmieni useEffect( () => { // will run only if channelId changes const subscriptionId = subscribeToChannel(props.channelId); return () => { // will clean up before executing next effect // or before the component is removed from UI removeSubscription(subscriptionId); }; }, [props.channelId] );
  30. useEffect() uruchomi się tylko raz jeśli przekażemy pustą tablicę oznacza

    to brak zależności i brak potrzeby odświeźania useEffect( () => { // will run only after first render() const interval = setInterval(logSomethingEverySecond, 1000); return () => { // will clean up once // before the component is removed from UI clearInterval(interval); }; }, [] );
  31. useEffect() odpowiednik w komponencie klasowym componentDidMount() { const this.interval =

    setInterval(logSomethingEverySecond, 1000); } componentWillUnmount() { clearInterval(this.interval); };
  32. useRef()

  33. useRef() Odpowiednik createRef w komponencie klasowym function CustomInput extends React.Component

    { constructor(props) { super(props) this.inputRef = React.createRef(); } setfocusOnInput = () => { this.inputRef.current.focus() } return ( <div> <input type="text" ref={this.inputRef} /> <button onClick={this.setfocusOnInput}>Focus</button> </div> ) }
  34. useRef() Pozwala na stworzenie obiektu referencji Przydatne gdy potrzebujemy dostać

    się do elementu DOM function CustomInput() { const inputRef = useRef(); function setfocusOnInput() { inputRef.current.focus() } return ( <div> <input type="text" ref={inputRef} /> <button onClick={setfocusOnInput}>Focus</button> </div> ) }
  35. useRef() Pozwala na tworzenie "zmiennych instancji" function CancellableTimeout(callback) { const

    timeoutRef = useRef(); useEffect(() => { timeoutRef.current = setTimeout(callback, 15000); return () => { clearTimeout(timeoutRef.current); } }) return ( <div> <button onClick={() => clearTimeout(timeoutRef.current)}>Cancel timeout</button> </div> ) }
  36. useContext()

  37. useContext() Pozwala m.in. na wygodniejsze używanie kontekstu zwłaszcza dla wielu

    kontekstów
  38. useContext() Zamiast function Message(props) { return ( <ThemeContext.Consumer> {theme =>

    ( <UserContext.Consumer> { currentUser => <div style={{backgroundColor: theme.backgroundColor}}> {props.message} </div> } </UserContext.Consumer> )} </ThemeContext.Consumer> ) }
  39. useContext() Mamy to function Message(props) { const theme = useContext(ThemeContext);

    const currentUser = useContext(UserContext); return ( <div style={{backgroundColor: theme.backgroundColor}}> You are logged in as {currentUser.name} </div> ) }
  40. Reguły używania hooków — Nie mogą być wywoływane wewnątrz instrukcji

    warunkowych, pętli, zagnieżdżonych funkcji itp. — kolejność wywoływania hooków musi być zachowana — Powinny się nazywać useXXX — Mogą byc wywoływane wewnątrz innych hooków
  41. Demo Własne hooki

  42. Chcesz więcej? kursreacta.pl/hooki @mehowte