0

I'm quite new to React, and i'm trying to make a ToDoList. I have a Modal with a submit button that when pressed should add a ToDoItem. But since i didn't want to prop drill my way through this i wanted to use the Context API. The Context API confuses me quite a bit, maybe i'm just a moron, but i have a hard time understanding why i have to make a hook and pass that as the value in the provider. I thought that in the ToDoContext that i already defined the default value as a empty array, so i just did it again.

In the console at line 62, which is my initial render it says that it's undefined, after the pressing the Add ToDo I get the same message. Showing my console after pressing the Add ToDo

App.jsx

import React, { useState } from "react";
import { render } from "react-dom";
import { ThemeProvider } from "emotion-theming";
import { defaultTheme } from "./theme";
import { Global, css } from "@emotion/core";
import Header from "./components/Header";
import ToDoList from "./components/ToDoList";
import AddBtn from "./components/AddBtn";
import ToDoContext from "./ToDoContext";

    const App = () => {
      const [toDoItems] = useState([]);

      return (
        <>
          {/*Global styling*/}
          <Global
            styles={css`
              * {
                margin: 0;
                padding: 0;
                box-sizing: border-box;
                list-style: none;
                text-decoration: none;
              }
            `}
          />

          {/*App render start from here*/}
          <ThemeProvider theme={defaultTheme}>
            <ToDoContext.Provider value={toDoItems}>
              <Header />
              <main>
                <ToDoList />
                <AddBtn />
              </main>
            </ToDoContext.Provider>
          </ThemeProvider>
        </>
      );
    };

    render(<App />, document.getElementById("root"));

ToDoContext.jsx

import { createContext } from "react";

const ToDoContext = createContext([[], () => {}]);

export default ToDoContext;

AddBtn.jsx

import React, { useState, useContext } from "react";
import { css } from "emotion";
import Modal from "../Modal";
import ToDoContext from "../ToDoContext";

const BtnStyle = css`
  position: fixed;
  bottom: 0;
  right: 0;
  cursor: pointer;
  display: block;
  font-size: 7rem;
`;

const ModalDiv = css`
  position: fixed;
  left: 50%;
  background-color: #e6e6e6;
  width: 60%;
  padding: 20px 20px 100px 20px;
  display: flex;
  flex-direction: column;
  align-items: center;
  max-width: 400px;
  height: 50%;
  transform: translate(-50%, -50%);
  border-radius: 20px;
  top: 50%;
`;

const textareaStyle = css`
  resize: none;
  width: 100%;
  height: 200px;
  font-size: 1.25rem;
  padding: 5px 10px;
`;

const timeStyle = css`
  font-size: 3rem;
  display: block;
`;

const modalSubmit = css`
  width: 100%;
  font-size: 3rem;
  cursor: pointer;
  margin-top: auto;
`;

const Label = css`
  font-size: 2rem;
  text-align: center;
  display: inline-block;
  margin-bottom: 50px;
`;

const AddBtn = () => {
  const [showModal, setShowModal] = useState(true);
  const [time, setTime] = useState("01:00");
  const [toDoItems, setToDoItems] = useContext(ToDoContext);
  console.log(toDoItems);
  return (
    <>
      <div className={BtnStyle} onClick={() => setShowModal(!showModal)}>
        <ion-icon name="add-circle-outline"></ion-icon>
      </div>

      {showModal ? (
        <Modal>
          <div className={ModalDiv}>
            <div>
              <label className={Label} htmlFor="time">
                Time
                <input
                  className={timeStyle}
                  type="time"
                  name="time"
                  value={time}
                  onChange={(e) => setTime(e.target.value)}
                />
              </label>
            </div>
            <label className={Label} htmlFor="desc">
              Description
              <textarea
                className={textareaStyle}
                name="desc"
                placeholder={`Notify yourself this message in ${time}`}
              ></textarea>
            </label>
            <button
              className={modalSubmit}
              onClick={() => {
                setToDoItems(
                  toDoItems.push({
                    time,
                  })
                );
              }}
            >
              Add ToDo
            </button>
          </div>
        </Modal>
      ) : null}
    </>
  );
};

export default AddBtn;

1 Answer 1

2

There are few issues in your code to fix:

  • useState returns a value and a setter. With this line of code, const [toDoItems] = useState([]);, you are just passing an empty array to your context.

So do this:

const toDoItems = useState([]);
  • In your ToDoContext.js, just pass an empty array as argument (initial value)
const ToDoContext = createContext([]);

Working copy of your code is here. (see console logs)

Also, I noticed that you are pushing the todo in setTodoItems in AddBtn.js.

Don't do this:

onClick={() => {
                setToDoItems(
                  toDoItems.push({
                    time
                  })
                );
              }}

Do this:

onClick={() => {
                setToDoItems(
                  toDoItems.concat([
                    {
                      time
                    }
                  ])
                );
              }}
Sign up to request clarification or add additional context in comments.

3 Comments

hope the answer has helped ... let me know if you have any questions... also consider to accept the answer..thanks.
This worked, so thanks for the help, but i'm still unsure why push is wrong compared to concat. toDoItems is an array, so i'm setting the new value to be the original array + pushing the new array into it. Is it because you can't update the state with a new value from the first arr?
Nevermind i found a good article explaining it. medium.com/javascript-in-plain-english/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.