[My memorandum] React Hooks. useContext, useReducer, useMemo, useCallback, useRef.

Hi. I'm studying React now. I've created a chatbot(with WordPress Rest API) and a weather app using React before.
Now, I think I understood how to use 'useState', 'useEffect' but I've not understood other hooks.
So, Today I wanna organize my brain that how to use other hooks to write this article!

useContext

The useContext hook makes us easy to pass data not to pass down every parent to child to grandchild component manually.

Manual way

  • Parent App.js
function App() {
  return (
      <Title head={'sample title'} text={'sample text'}/>
  );
}
  • Child Title.jsx
const Title = ({head,text}) => {
    return (
        <div>
            <h1>{head}</h1>
            <Text text={text}/>
        </div>
    )
}
  • Grandchild Text.jsx
const Text = ({text}) => {
    return (
        <div>
            <p>{text}</p>
        </div>
    )
}

useContext

How it works?

We can use data in every child, grandchild using useContext without using props relay. In this above pattern, we can get data that is _text= {'sample text'} _without though the Title components.

  • App.js

Set createContext and props data.
First, we have to import createContext from react to use useContext.
And then, we'll set Provider where we want to pass data.
In service provider has a value which comes from word variable.
That value of the word variable can be passed to other children or nested components.

import { createContext } from 'react';
import Title from './components/Title';

export const SampleContext = createContext()

function App() {
  const word = {
    title: "'sample title',"
    text: 'sample text'
  }
  return (
   <SampleContext.Provider value={word}>
      <Title />
    </SampleContext.Provider>
  );
}
  • Title.jsx

In child components, import useContext and a variable from App.js that used createContext().
We can access 'word' variables that in App.js using useContext like this.
So, I want you to focus on the tag here. It doesn't have any props value but it can display the data from the word variable.

import { useContext } from 'react'
import { SampleContext } from '../App'
import Text from './Text'

const Title = () => {
    const contextTitle = useContext(SampleContext)
    return (
        <>
        <h1>{contextTitle.title}</h1>
        <Text />
        </>
    )
}
  • Text.jsx

The way to get data is the same as Title.jsx.
It can get data from App.js directly without any props.

import { useContext } from 'react'
import { SampleContext } from '../App'

const Text = () => {
    const contextText = useContext(SampleContext)
    return (
        <p>{contextText.text}</p>
    )
}

useContext + useState

I'll introduce how to combine useContext and useState.
Here is the code that can change values of title and text to click buttons from Title.jsx and Text.jsx.

  • App.js
import { useState, createContext } from 'react';
import Title from './components/Title';

export const SampleContext = createContext()

function App() {
  const [title, setTitle] = useState('Default Title')
  const [text, setText] = useState('Default Text')
  return (
    <SampleContext.Provider value={{ titles: [title, setTitle], texts: [text, setText] }}>
      <Title />
    </SampleContext.Provider>
  );
}
  • Title.jsx
import { useContext } from 'react'
import { SampleContext } from '../App'
import Text from './Text'

const Title = () => {
    const {titles} = useContext(SampleContext)
    const [title, setTitle] = titles
    const handleClick = () => {
        setTitle('Changed from child components')
    }
    return (
        <>
        <h1>{title}</h1>
        <button onClick={handleClick}>Change</button>
        <Text />
        </>
    )
}
  • Text.jsx
import { useContext } from 'react'
import { SampleContext } from '../App'

const Text = () => {
    const {texts}= useContext(SampleContext)
    const [text, setText] = texts
    const handleText = () => {
        setText('Changed from grand child component.')
    }
    return (
        <>
        <p>{text}</p>
        <button onClick={handleText}>change</button>
        </>
    )
}

Note: If you use this, it wouldn't work.

const title = useContext(SampleContext.title);

useReducer

The useReducer hook can be used for state management like useState.
We can use useState but useReducer is a suited handle for complex structure states.
It looks like Redux!

How to use

I created a simple counter function.

import React, { useReducer } from 'react'

const Counter = () => {
    const reducerFunc = (state, action) => {
        switch (action) {
            case 'PLUS':
                return state + 1;
            case 'MINUS':
                return state - 1;
            case 'RESET':
                return 0;
            default:
                return state;
        }
    }
    const [count, dispatch] = useReducer(reducerFunc, 0);
    return (
        <div>
            <h1>{count}</h1>
            <button onClick={() => dispatch('PLUS')}>+</button>
            <button onClick={() => dispatch('MINUS')}>-</button>
            <button onClick={() => dispatch('RESET')}>0</button>
        </div>
    )
}

'reducerFunc' would be receiving state and action and then update state that follows dispatched action type.
We'll use useReducer like this.

const [state, dispatch] = useReducer(Reducer, intialState)

It's useful to create functions that have many patterns.

useMemo and useCallback

The useMemo hook returns a memoized value and useCallback returns a memoized callback.
To return memoized value or callback, it would be held the result of the process and returns the held value without processing until a certain trigger. It helps the performance of a website.

useMemo(() => func(that has very expensive value), deps) 
useCallback(func(that has very expensive function), deps)

For useMemo, it'll be rendered when the 'deps' value changes.
It does not render when it is not needed, it could be improved performance.
Functions passed to useMemo will be executed during rendering. API request should be written in useEffect, not useMemo.
useMemo is effective for JSX.

For useCallback, it's good to use in useEffect if that has functions call again and again. And also good for handler events when a button is clicked.
It improves performance when the page re-rendered.

useRef

The useRef hook has a special feature that can store data without rendering.

useRef hook mainly has two ways to use.

First, it would be returned 'ref' object with the current property.
useRef hook can use like below.

const refObj = useRef(initVal)
const val = refObj.current;

And we can update ref object like this. This is an example of that input box would be a focus with a button click.

import React,{ useRef } from 'react'

const Input = () => {
    const refObj = useRef(null)
    const handleRef = () => {
        refObj.current.focus()
    }
    return (
        <div>
          <input ref={refObj} type='text' />
          <button onClick={handleRef}>click</button>
        </div>
    )
}

useRef is useful for the input box because it would be rendered when the value changed. It won't render just input every word.

EX.)
useRef => typing...(not render) 'HELLO' => update value(render)
useState => using set property. typing...(render every word, 5times for this time) 'HELLO' => update value(render)

When you want to update only holding values and don't want to re-render, useRef is a good choice!

Conclusion

I'm a beginner at using these hooks, so I'll be lost which hooks are better for use in my case? or how can I use this? for sure. I was completely lost in how these hooks work, but now, I could get it a little bit. I wanna use to it with using these for my project,

I hope this article could help your or my development journey.

Thank you.

20