为什么在使用上下文的应用程序中通过 useEffect 获取数据时可选链接允许呈现?

Why does optional chaining allows rendering when fetching data through useEffect in an app that uses context?

我是 webdev 世界的新手,想学习 ReactJS。我遵循了我在 YouTube 上找到的由 Traversy 制作的教程,他制作了一个任务跟踪器,现在我想对其进行一些更改以学习和练习更多内容。

我想为约会使用上下文(教程中最初命名为任务),使用 react-calendar 添加日历并使用 react-router-dom。 我在尝试使列表呈现时卡住了一段时间,因为它只呈现为“空”。后来发现这个 post 与我的问题类似:

我根据那个 post 更改了一些代码,现在它确实呈现了约会列表,但我不知道为什么它以前不起作用,我不确定它为什么起作用在工作,在忙。我什至不知道我是在正确使用上下文还是只是在钻井。帮助将不胜感激。谢谢。

此外,如果我的代码一团糟,我很抱歉,我是新手。

App.js

import { createContext, useState, useEffect } from "react";
import Dashboard from "./views/Dashboard";
import './App.css';
import { BrowserRouter as Router, Route, Routes} from "react-router-dom";
import AddAppointmentForm from "./views/AddAppointmentForm";

export const AppContext = createContext();
export const AppUpdateContext = createContext();

function App() {
  const [appointments, setAppointments] = useState([])
  const updateAppointments = (apptList) => {
    setAppointments(apptList)
  }

  return (
    <AppContext.Provider value={ appointments }>
      <AppUpdateContext.Provider value={ updateAppointments }>
        <Router>
          <Routes>
            
              <Route path="/" element={<Dashboard appointments={appointments} />} />
              {/* <Route path="/add" element={<AddAppointmentForm />} />  TBA */} 
            
          </Routes>
        </Router>
      </AppUpdateContext.Provider>
    </AppContext.Provider>
  );
}

export default App;

Dashboard.js

import { useEffect, useContext} from "react";
import { AppContext } from "../App";
import { AppUpdateContext } from "../App";
import AppointmentList from "../components/AppointmentList";
import Header from "../components/Header";

// function Dashboard() {  // this is how it used to be
  function Dashboard(props) {
  const appointments = useContext(AppContext)
  const setAppointments = useContext(AppUpdateContext)

  const fetchAppointmentList = async () => {
    const res = await fetch("http://localhost:5000/appointments");
    const data = await res.json();

    return data;
  }

  useEffect(() => {
    const getAppointments = async () => {
      const appointmentsFromServer = await fetchAppointmentList();
      setAppointments(appointmentsFromServer);
    }

    getAppointments();
    console.log("ñññññ",appointments)
  }, []);
  
  console.log("aagh",appointments)
  
  return (
    <div style={dashboardStyle}>
      <Header />
      {/* {appointments.lenght>0 ? (<AppointmentList />) : <p>empty</p>} this is how it used to be */}
      <AppointmentList appointments={props?.appointments}/>
    </div>
  );
}

const dashboardStyle = {
  maxWidth: "31.25rem",
  overflow: "auto",
  minHeight: "18.75rem",
  border: "1px solid steelblue",
  margin: "1.875rem auto",
  padding: ".5rem",
  boxSizing: "border-box",
}

export default Dashboard;

AppointmentList.js

import Appointment from "./Appointment";
import { AppContext } from "../App";
import { useContext } from "react";

function AppointmentList({ appointments }) {
// function AppointmentList() {  // this is how it used to be
  // const { appointments, setAppointments } = useContext(AppContext)
  console.log("appList",appointments)  // this is how it used to be

  return (
    <>
      {
        appointments.map(appt => (
          <Appointment key={appt.id} appointment={appt} />
        ))
      }
    </>
  );
}

export default AppointmentList;

Why does optional chaining allows rendering when fetching data through useEffect in an app that uses context?

<AppointmentList appointments={props?.appointments}/>

它允许通过防止意外访问可能为空或未定义的对象来进行渲染。 props 可能未定义的唯一方法是如果您只是不声明它,即 const Dashboard = () => {....const Dashboard = (props) => {.....

你正在通过道具钻appointments状态。 AppointmentList 可以使用 AppContext 上下文访问 appointments 状态,而 Dashboard 可以使用 AppUpdateContext 上下文更新 appointments 状态。

应用程序

function App() {
  const [appointments, setAppointments] = useState([]);
  const updateAppointments = (apptList) => {
    setAppointments(apptList);
  };

  return (
    <AppContext.Provider value={{ appointments }}> // <-- need object here
      <AppUpdateContext.Provider value={{ updateAppointments }}> // <-- and here
        <Router>
          <Routes>
              <Route path="/" element={<Dashboard />} /> // <-- don't pass props
          </Routes>
        </Router>
      </AppUpdateContext.Provider>
    </AppContext.Provider>
  );
}

仪表板

function Dashboard() { // <-- no props
  const { updateAppointments } = useContext(AppUpdateContext); // <-- access from context

  const fetchAppointmentList = async () => {
    const res = await fetch("http://localhost:5000/appointments");
    const data = await res.json();

    return data;
  };

  useEffect(() => {
    const getAppointments = async () => {
      const appointmentsFromServer = await fetchAppointmentList();
      updateAppointments(appointmentsFromServer);
    }

    getAppointments();
  }, []);

  return (
    <div style={dashboardStyle}>
      <Header />
      <AppointmentList /> // <-- don't pass props
    </div>
  );
}

约会列表

function AppointmentList() { // <-- no props
  const { appointments } = useContext(AppContext); // <-- access from context

  return appointments.map(appt => (
    <Appointment key={appt.id} appointment={appt} />
  ));
}