【问题标题】:React Context API returns undefinedReact Context API 返回未定义
【发布时间】:2020-04-23 23:49:08
【问题描述】:

我对 React 很陌生,我正在尝试制作一个 ToDoList。我有一个带有提交按钮的模态,按下该按钮时应该添加一个 ToDoItem。但是因为我不想通过这个来支撑我的方式,所以我想使用 Context API。 Context API 让我很困惑,也许我只是个白痴,但我很难理解为什么我必须制作一个钩子并将其作为提供程序中的值传递。我认为在 ToDoContext 中我已经将默认值定义为空数组,所以我又做了一次。

在第 62 行的控制台中,这是我的初始渲染,它说它是未定义的,在按下添加待办事项后,我得到了相同的消息。

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;

【问题讨论】:

    标签: reactjs react-hooks react-context


    【解决方案1】:

    您的代码中有几个问题需要修复:

    • useState 返回 valuesetter。使用这行代码const [toDoItems] = useState([]);,您只是将一个空数组传递给您的上下文。

    这样做:

    const toDoItems = useState([]);
    
    • 在您的 ToDoContext.js 中,只需传递一个空数组作为参数(初始值)
    const ToDoContext = createContext([]);
    

    code is here 的工作副本。 (查看控制台日志)

    另外,我注意到您正在 AddBtn.js 中的 setTodoItems 中推送待办事项。

    不要这样做:

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

    这样做:

    onClick={() => {
                    setToDoItems(
                      toDoItems.concat([
                        {
                          time
                        }
                      ])
                    );
                  }}
    

    【讨论】:

    • 希望答案对您有所帮助...如果您有任何问题,请告诉我...也可以考虑接受答案...谢谢。
    • 这行得通,所以感谢您的帮助,但我仍然不确定为什么 push 与 concat 相比是错误的。 toDoItems 是一个数组,所以我将新值设置为原始数组+将新数组推入其中。是因为您无法使用第一个 arr 中的新值更新状态吗?
    • 没关系,我找到了一篇很好的文章来解释它。 medium.com/javascript-in-plain-english/…
    猜你喜欢
    • 2021-06-19
    • 1970-01-01
    • 1970-01-01
    • 2020-05-06
    • 2020-07-17
    • 2020-12-08
    • 1970-01-01
    • 2020-09-17
    相关资源
    最近更新 更多