Create a simple useContext with useReducer in React

min read

Day 40/100 #100DaysOfCode #React #ReactNative

Nay mình sẽ kết hợp giữa useContext + useReducer, vừa qua mình đã chia sẻ về các hooks trong react như: useContext, useReducer, ... Mọi người có thể xem sơ qua về nó trước nhé

+ useReducer in React
+ useContext in React

Create a simple useContext with useReducer in React

Trong dự án nhỏ và vừa ta kết hợp hai cái hooks này là cũng quá ok rồi, còn quản lý state phức tạp quá thì dùng Redux để ta có thể dispath được nhiều action để update state
Về useContext, useReducer mình đã nói sơ qua về các bài viết chia sẻ trước rồi, trong bài viết hôm này mình dùng code trước copy vào chỉnh sửa tí và run nó thôi

+ Đầu tiền tạo file UseContext.js

import React,{useReducer, useState} from 'react'
export const MContext = React.createContext();

/* CREATE ACTION */
export const ADD_TODO = "ADD_TODO";
export const REMOVE_TODO = "REMOVE_TODO";
export const EDIT_TODO = "EDIT_TODO";

/* CREATE DATA */
const initialTodos = {
  todos: [
    {
      id: 1,
      title: "Laravel 8",
      complete: false,
    },
    {
      id: 2,
      title: "React Native",
      complete: false,
    },
  ]
}

/* CREATE REDUCER FUNCTION */
const reducer = (state, action) => {
  switch (action.type) {

    case ADD_TODO: {
      return {
        ...state, todos: [...state.todos, action.payload]
      }
      break;
    }

    case EDIT_TODO: {
      return {
        ...state,
        todos: state.todos.map(item => item.id==action.payload.id?action.payload:item)
       
      }
      break;
    }

    case REMOVE_TODO: {
      return {
        ...state,
        todos: state.todos.filter(item => item.id != action.payload.id)
      }
      break;
    }

    default:
      return state;
      break;
  }

}

const MyProvider = (props)=>{
    const [state,dispatch] = useReducer(reducer,initialTodos)
    return(
        <MContext.Provider value={{ state, dispatch }}>
         {props.children}
      </MContext.Provider>
    )
}
export default MyProvider;

Các bạn nhìn bên trên, bạn thấy mình có dùng useReducer và khởi tạo nó, còn cài function reducer là mình copy từ bài viết trước, bạn có thể xem lại nhé

const [state,dispatch] = useReducer(reducer,initialTodos);

Để các component children dispath action đến reducer, thì ta cần add dispath nó đến Provider như sau:

<MContext.Provider value={{ state, dispatch }}>
         {props.children}
</MContext.Provider>

+ Tiếp tục ta tạo ProductComponent.js như code sau:

import React,{useContext} from 'react'
import MyProvider from './UseContext';
import TitleComponent from './TitleComponent'
function ProductComponent() {
  
  return (
    <>
        <h1>Product Component</h1>
        <MyProvider>
            <TitleComponent />
        </MyProvider>
    </>
  )
}

export default ProductComponent

Bạn nhìn thấy ta có gọi TitleComponent bên trong MyProvider, chính vì thế mà TitleComponent có thể dispath một action đến reducer

+ Tạo file TitleComponent.js

import React,{useContext} from 'react'
import {MContext} from './UseContext';

function TitleComponent() {
  const { state, dispatch } = useContext(MContext);
  console.log(state)
  const add_todo = () => {
    const id = state.todos.length + 1;
    dispatch({
      type: "ADD_TODO",
      payload: {
        "id": id,
        "title": "Exampe useReducer , action " + id,
        "complete": false
      }
    })
  }
 
  const edit_todo = (todo)=>{
    todo.title = todo.title +"(Edit)";
    dispatch({
      type: "EDIT_TODO",
      payload: todo
    })
  }
 
  const remove_todo = (todo) => {
    dispatch({
      type: "REMOVE_TODO",
      payload: todo
    })
  }

  return (
    <div>
      
       <ul>
        {
          state.todos.map(item => {
            return (
              <li key={item.id}>{item.title}
               ---- <button onClick={() => remove_todo(item)} style={{ background: 'red' }}>remove todo</button>
               ---- <button onClick={() => edit_todo(item)} style={{ background: 'yellow' }}>edit todo</button>
               </li>
            )
          })
        }
      </ul>

       <button onClick={()=>add_todo()}>add product</button>
    
    </div>

  )
}

export default TitleComponent

Đoạn code bên trên mình lấy từ bài viết trước, bạn có thể xem lại bài viết useReducer nhé, bạn nhìn component trên chắc cũng hiểu rồi, ta gửi dispath một action đến reducer để (add,update,edit), đồng thời state nó cũng được cập nhật theo
Cho nên mình nói với mọi người, nếu dự án nhỏ và vừa, ta dùng useReducer+useContext, thấy nó nhẹ nhàng hơn, dễ cấu hình hơn

x

Ủng hộ tôi bằng cách click vào quảng cáo. Để tôi có kinh phí tiếp tục phát triển Website!(Support me by clicking on the ad. Let me have the money to continue developing the Website!)