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. 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
  2. 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
  3. 7.

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

    props.onClick(props)}> <h3>{props.name}</h3> <div>For only ${props.price}</div> </div> ); }
  4. 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> ); }
  5. 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} /> ); } }
  6. 10.

    Komponent funkcyjny z hookami function ProductsPage() { const [products, setProducts]

    = useState([]); setEffect(() => { fetchProducts().then(results => setProducts(results)); }, []) return ( <Products products={products} /> ); }
  7. 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> ) }
  8. 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> ) } }
  9. 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> ) } }
  10. 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" });
  11. 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" })
  12. 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> ) }
  13. 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> ); }
  14. 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> ) } }
  15. 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));
  16. 25.

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

    zależności useEffect( functionThatHandlesEffect, arrayWithDependencies );
  17. 26.

    useEffect() domyślnie odpala funkcję po każdym renderze useEffect(() => {

    // will run after every render() window.document.title = "New title"; });
  18. 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" }
  19. 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); }; });
  20. 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] );
  21. 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); }; }, [] );
  22. 31.

    useEffect() odpowiednik w komponencie klasowym componentDidMount() { const this.interval =

    setInterval(logSomethingEverySecond, 1000); } componentWillUnmount() { clearInterval(this.interval); };
  23. 32.
  24. 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> ) }
  25. 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> ) }
  26. 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> ) }
  27. 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> ) }
  28. 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> ) }
  29. 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