React Hooks - Part 2

Content

  • Context API
  • Additional Hooks

> Init

> Case of study

+ Step = branch

Context API

> Props vs Store

Props vs Store

Props Drilling !!!! 

Context API

> Store

State

Action

New State

State + Action = Merge past state and modify just with the new action

Context API

> Characteristics 

  • Not need pass props through every level of the tree: Share global data.
  • Out the box: Built on the top of react.
  • Easy to use with hooks.

Context API

> Characteristics 

  • Create Context.
  • Context.provider.
  • useContext hook
import React, { createContext, useReducer } from "react";
import { fetchCatsActions, deleteCatAction, addCatAction } from "./AppActions";
import AppReducer from "./AppReducer";

// Initial State
const initialState = {
  cats: []
};

// Create context
export const GlobalContext = createContext(initialState);

// Provider component
export const GlobalProvider = ({ children }) => {
...

  return (
    <GlobalContext.Provider
      value={{
        cats: state.cats,
        ...catActions
      }}
    >
      {children}
    </GlobalContext.Provider>
  );
};
export default function useGetCatsData (requestId, catNumber) {
  const { cats, fetchCats } = useContext(GlobalContext);

  useEffect(() => {
    getCat();
  }, [requestId]);

  async function getCat () {
    const data = await catRequest(catNumber);

    fetchCats(data);
  }

  useDebugValue(cats.length === 0 ? 'Empty cat data' : 'Already fetched cat data');

  return cats;
}

Context API

> Actions

export const addCatAction = dispatch => cat => {
  return dispatch({
    type: ADD_CAT,
    payload: cat
  });
};

export default reducer (state, action) => {
  switch (action.type) {
....
    case ADD_CAT:
      return {
        ...state,
        cats: [action.payload, ...state.cats]
      };
    default:
      return state;
  }
};

Use Reducer

  const [state, dispatch] = 
        useReducer(AppReducer, initialState);


  const fetchCats = fetchCatsActions(dispatch);
  const deleteCat = deleteCatAction(dispatch);
  const addCat = addCatAction(dispatch);

  const catActions = {
    fetchCats,
    deleteCat,
    addCat
  };

  return (
    <GlobalContext.Provider
      value={{
        cats: state.cats,
        ...catActions
      }}
    >
      .....

Context API

> Actions

function CatList() {
  const { addCat } = useContext(GlobalContext);

  const addCatOnClick = async (ev) => {
    const data = await catRequest(1);

    addCat(data[0]);
  }
  
  ...

Extra hooks

> Actions

  • useCallback
  • useMemo
  • useRef
  • useLayoutEffect
  • useDebugValue

useCallback

> Additional Hooks

function CatList({numberOfCats}) {
  const [catData, setCatData] = useState([]);

  async function fetchCats () {
    const data = await catRequest(numberOfCats);
    setCatData(data);
  }

  // fetch more cats
  const onClick = (ev) => {
    fetchCats();
  }

  useEffect(() => {
    fetchCats();
  }, []);
  
  ....
 

React Hook useEffect has a missing dependency: 'fetchCats'. Either include it or remove the dependency array  react-hooks/exhaustive-deps

 

useCallback

> Additional Hooks

function CatList({numberOfCats}) {
  const [catData, setCatData] = useState([]);

  const fetchCats = useCallback(async () => {
    const data = await catRequest(numberOfCats);
    setCatData(data);
  }, [numberOfCats]);

  // fetch more cats
  const onClick = (ev) => {
    fetchCats();
  }

  useEffect(() => {
    fetchCats();
  }, [fetchCats]);

Returns a memoized callback.

useMemo

> Additional Hooks

import React, { useEffect } from 'react';

let renderCount = 0;

export default function CatTail() {

  useEffect(() => {
    renderCount ++;
  });

  return (
    <div>
      <h3>Render tail count = {renderCount}</h3>
    </div>
  )
}
function CatList() {
...

  return (
....
      <CatTail />
...  
 );
}

export default CatList;

useMemo

> Additional Hooks

Returns a memoized value.

...

function CatList() {
  ...

  const memoElement = useMemo(() => {
    return <CatTail />;
  }, [catData.length]);

  return (
    <div className="list">      
      ...
      {memoElement}
    </div>
  );
}

export default CatList;

useLayoutEffect & Use Ref

> Additional Hooks

  ....
  const listRef = useRef(null);
  ...
  useLayoutEffect(() => {
    if (listRef.current.clientHeight > 600) {
        listRef.current.style.border = `2px solid #9c88ff`;
    } else {
      listRef.current.style.border = '';
    }
  });

  return (
    <div className="list" ref={listRef}>      
      ...
    </div>
  );
}

useDebugValue

> Additional Hooks

  }

  useDebugValue(cats.length === 0 ? 'Empty cat data' : 'Already fetched cat data');

  return cats;

Conclusions

> Reuse everywhere!

  • Context API: easy context sharing.
  • Store + useReducer + useContext
  • Performance: useMemo - useCallback.
  • Layout and render sync: useLayout & useRef
  • UsedebugValue

Gracias!

Ben Awad: https://www.youtube.com/watch?v=ommC6fS1SZg

 https://medium.com/@jan.hesters/usecallback-vs-usememo-c23ad1dc60

https://reactjs.org/docs/hooks-reference.html

Made with Slides.com