😸

RK

Introduction to React context API and useContext() hook.

React Context Api

Elo Elo, Hope you guys doing great, this post introduces you to react's context API and useContext() hook. we will learn about how to use React.CreateContext() to create a store and access them using useContext() Hook.

Credits section

image credits - @hannahmorgan7

What is context and where should we use it?

Ever in a situation where you have to pass props to a number of components to exchange data between components? well, it's known as props drilling.

Yes, props drilling is ok but in some places, props drilling will result in big messy code.

To solve these problems we can go with react context.

Context provides a way to pass data through the component tree without having to pass props down manually at every level. - reactjs.org

Let's get started by creating a react application using CRA.

create-react-app todo_context

yes we are following the to-do tradition LOL.

Add 2 new folders src/components and src/context let's concentrate on context first then we will create the components.

Add 2 new files inside the context folder provider.js and store.js now that we have created the required files we can start creating our first context.

Setup Context

store.js

import React from "react";

const Store = React.createContext({
  todos: [],
  addTodo: (todo) => {},
  deleteTodo: (index) => {}
});

export default Store;

Ok what is happening here, we are creating a context store/object using react's createContext function.

{
    text: "Finish that side project please ;-; "
}

finally, make sure to export Store so that we can use it from elsewhere.

provider.js

import { useState } from "react";
import Store from "./store";

const TodoProvider = (props) => {
  const [todos, setToDos] = useState([]);
  const addTodo = (todo) => {
    if (todo) {
      setToDos([...todos, todo]);
    }
    console.log(todos);
  };
  const deleteTodo = (index) => {
    if (todos[index]) {
      const fliteredArr = todos.filter((element, i) => i !== index);
      setToDos(fliteredArr);
    }
  };
  return (
    <Store.Provider
      value={{
        todos,
        addTodo,
        deleteTodo
      }}
    >
      {props.children}
    </Store.Provider>
  );
};

export default TodoProvider;

The provider is just like any functional component that has state other functions. as you can see we have a state const [todos, setToDos] = useState([]); and 2 functions addTodo and deleteTodo lets see one by one.

Tip: Always wrap what you want to rerender when the context change. since this may lead to lesser performance. having multiple atomic contexts is better than a huge single context for the entire application.

Setup Components

Add 2 new files AddTodoCtrl.js and TodoList.js inside the components.

AddTodoCtrl.js

import { useContext, useState } from "react";
import Store from "../context/store";

const AddTodoCtrl = (props) => {
  const [todo, setTodo] = useState("");
  const { addTodo } = useContext(Store);
  const handleOnClick = (event) => {
    if (todo) {
      addTodo(todo);
    } else {
      alert("please enter valid value");
    }
  };
  const handleOnChange = (event) => {
    if (event.target.value) {
      setTodo(event.target.value);
    }
  };
  return (
    <div>
      <input type="text" id="todoTxt" onChange={handleOnChange} />
      <button onClick={handleOnClick}> + </button>
    </div>
  );
};

export default AddTodoCtrl;

TodoList.js

import { useContext } from "react";
import Store from "../context/store";

const TodoList = (props) => {
  const { deleteTodo,todos } = useContext(Store);
  const removeItem = (index) => {
    deleteTodo(index);
  };
  return (
    <div className="list-container">
      {todos.map((todo, index) => {
        return (
          <div
            className="list-item"
            onClick={() => removeItem(index)}
            key={index}>
            {todo}
          </div>
        );
      })}
    </div>
  );
};

export default TodoList;

App.js

Now that we finished all the components we need for this application its finally time to glue all things together.

import AddTodoCtrl from "./components/AddTodoCtrl";
import TodoList from "./components/TodoList";
import TodoProvider from "./context/provider";
import "./styles.css";

export default function App() {
  return (
    <TodoProvider>
      <div className="App">
        <h1>To do</h1>
        <hr />
        <TodoList />
        <AddTodoCtrl />
      </div>
    </TodoProvider>
  );
}

Take styles.css content from here

Finally, run npm start.

Working application at codesanbox

This is my first article in a while, I am happy to start blogging again.

Found any bugs or you have any suggestions to improve my writing let me know via Twitter or Instagram.

Made with 💚 by rajakumar