In this post, we learned a basics of React Context API. However, we need to learn how to put that Context API in practice.
 
What will we do?
 
We will create simple to-do application with one input field and button “Add item” for adding new item to our list. Also, we will have “Remove” button for every item, so we can remove them after job’s done.
 

 
Coding time!
 
Firstly, we will create new ToDoContext.

const ToDoContext = React.createContext();

After that, we will create new Provider, our to-do list, and there we will define all functions and states. As you can see, we have two states. First state contains values of default to-do items – list and also empty todo state. We have one function – createNewToDoItem for creating new item, and another one – deleteItem to remove item from list. Those functions are the same as functions without Context API, no changes at all. Also, we will have two functions to handle Enter for submit new item and to handle input changes. All those four functions should look like this:

constructor(props) {
  super(props);

  this.state = {
    list: [
      {
        todo: "clean the house"
      },
      {
        todo: "buy milk"
      }
    ],
    todo: ""
  };
}

createNewToDoItem = () => {
  this.setState(({ list, todo }) => ({
    list: [
      ...list,
      {
        todo: todo
      }
    ],
    todo: ""
  }));
};

deleteItem = indexToDelete => {
  this.setState(({ list }) => ({
    list: list.filter((ToDoList, index) => index !== indexToDelete)
  }));
};

handleKeyPress = e => {
  if (e.target.value !== "") {
    if (e.key === "Enter") {
      this.createNewToDoItem();
    }
  }
};

handleInput = e => {
  this.setState({
    todo: e.target.value
  });
};

Now, we should properly pass values from Provider to Consumer – we want to pass down list and also deleteItem function. We will not pass down createNewToDoItem, if you’re wondering why – that’s because it’s not function for single item. It’s globally for whole list and we don’t want to pass down it unnecessary. Our Provider should contains text input and “Add item” button and also should pass down props to children components.

<ToDoContext.Provider
  value={{ list: this.state.list, deleteItem: this.deleteItem }}
>
  <div className="ToDo">
    <h1 className="ToDo-Header">
      Simple To-Do App using React Context API
    </h1>
    <div className="ToDo-Container">
      <input
        type="text"
        value={this.state.todo}
        onChange={this.handleInput}
        onKeyPress={this.handleKeyPress}
      />

      <button className="ToDo-Add" onClick={this.createNewToDoItem}>
        ADD ITEM
      </button>

    </div>
  </div>

  {this.props.children}
</ToDoContext.Provider>

Consumer will use list and deleteItem function passed from Provider. With list, we will render items in to-do list, while deleteItem will be used to remove item with same index.

<ToDoContext.Consumer>
  {({ list, deleteItem }) =>
    list.map((item, key) => {
      return (
        <div key={key}>
          {item.todo}
          <button
            className="ToDoItem-Delete"
            onClick={deleteItem.bind(this, key)}
          >
            REMOVE
          </button>
        </div>
      );
    })
  }
</ToDoContext.Consumer>

Finally, in our App, we should make Consumer nested inside Provider like:

<div className="App">
  <ToDoList>
    <ToDoItems />
  </ToDoList>

</div>

 
Conclusion
 
By using prop drilling we pass list of items and deleteItem to our to-do items. If this was too hrad for you to follow, I provided example here in codesandbox, so you can play with those states, etc – https://codesandbox.io/s/zzqml2m2y4