我的应用程序工作正常,我可以刷新其他页面。但是当我刷新一个事件正在编辑(EditEvent组件)的页面时,它给了我这个错误信息:Uncaught TypeError:无法读取未定义的属性(读取'name')。我注意到所有的状态函数都是未定义的刷新后,甚至在顶层(App.js)。有人能帮帮我吗?
App.js
import React from "react";
import { Routes, Route } from 'react-router-dom';
import { useState, useEffect } from "react";
import Home from "./components/Home";
import SignUp from "./components/SignUp";
import Login from "./components/Login";
import EditEvent from "./components/EditEvent";
import NewEvent from "./components/NewEvent";
function App() {
const [currentUser, setCurrentUser] = useState("");
const [events, setEvents] = useState([])
const [clients, setClients] = useState([])
useEffect(() => {
fetch('/auth')
.then(r => {
if(r.ok){
r.json().then(user => {
setCurrentUser(user)
setClients(user.clients)
}
)
}
})
},[])
useEffect(() => {
fetch('/events')
.then(r => {
if(r.ok){
r.json().then(events => setEvents(events)
)
}
})
},[])
function handleLogin(user) {
setCurrentUser(user)
}
function handleSetUser(user) {
setCurrentUser(user)
}
function handleEditEvent(editedEvent) {
const unchangedEvents = events.filter(event => event.id !== editedEvent.id)
setEvents([...unchangedEvents,editedEvent])
}
function handleDeleteEvent(deletedEvent){
const updatedEvents = events.filter((event) => event.id !== deletedEvent.id)
setEvents([...updatedEvents])
}
function handleNewEvent(newEvent) {
setEvents([...events,newEvent])
}
console.log(events)
return (
<div className="App">
<Routes>
<Route path="/home" element ={<Home currentUser={currentUser} setCurrentUser={setCurrentUser} events={events} clients={clients} onEventDelete={handleDeleteEvent} addEvent={handleNewEvent}/>} />
<Route path="/" element={<Login onLogin={handleLogin}/>} />
<Route path="/signup" element={<SignUp setUser={handleSetUser}/>} />
<Route path="/events/:id" element={<EditEvent events={events} clients={clients} onEditEvent={handleEditEvent} />} />
<Route path="/newevent" element={<NewEvent events={events} clients={clients} addEvent={handleNewEvent}/>} />
</Routes>
</div>
);
}
export default App;
Home.js
import React from 'react';
import NavBar from './NavBar';
import Events from './Events';
import Vendors from './Vendors';
import { useState } from "react"
import NewEvent from './NewEvent';
function Home({ currentUser, setCurrentUser, events, clients, onEventDelete, addEvent }) {
const [active, setActive] = useState('Events')
return (
<div>
<NavBar currentUser={currentUser} setCurrentUser={setCurrentUser} setActive = {setActive}/>
{active === "Events" && <Events events={events} clients={clients} onEventDelete={onEventDelete} />}
{active === "Vendors" && <Vendors />}
{active === "NewEvent" && <NewEvent clients={clients} addEvent={addEvent} currentUser={currentUser} setActive={'Events'}/>}
</div>
);
}
export default Home;
Events.js
import React from "react";
import EventCard from "./EventCard";
import "../Container.css";
function Events ( { events, onEventDelete } ) {
const renderEvents = events.sort( (a,b) => a.id > b.id ? 1 : -1).map((event) => ( <EventCard key={event.id} event={event} onEventDelete={onEventDelete}/> ))
return (
<section className="twitter">
<h1 className="header">Upcoming Events</h1>
<div className="container">
{renderEvents}
</div>
</section>
)
}
export default Events;
EventCard.js
import React from 'react';
import { useNavigate } from 'react-router-dom'
import "../Container.css";
function EventCard( { event, onEventDelete }) {
const navigate = useNavigate();
function handleEventDelete() {
fetch(`/events/${event.id}`, {
method: 'DELETE'
})
.then(()=> {
onEventDelete(event)
});
}
function getTime(eventTime) {
const time = eventTime.split('T')[1];
const hour = time.split(':')[0];
const minutes = time.split(':')[1];
let timeValue = '';
if (hour > 0 && hour <= 12) {
timeValue= "" + hour
} else if (hour > 12) {
timeValue= "" + (hour - 12);
} else if (hour === 0) {
timeValue= "12"
}
const standardTime = timeValue + ':' + minutes;
const dayNight = timeValue = (hour >= 12) ? " P.M." : " A.M.";
return standardTime + dayNight;
}
function handleEdit(e) {
e.preventDefault()
navigate(`/events/${event.id}`)
}
return ( <div className='card' >
<h1 className='title'>{event.name}</h1>
<p>Client: {event.client.name}</p>
<p>Date: {event.start_date}</p>
<p>Time: {getTime(event.start_time)}</p>
<p>Location: {event.location}</p>
<p>Description: {event.description}</p>
<br></br>
<ul>
Vendors:
{event.vendors.map((vendor) =>
<li key={vendor.id}>{vendor.name}</li>)}
</ul>
<button id='edit-button' onClick={handleEdit} >Edit</button >
<button id='delete-button' onClick={handleEventDelete}>Delete Event</button>
</div>)
}
export default EventCard;
EditEvent.js
import React from 'react'
import { useState } from "react";
import { Link, useNavigate, useParams} from "react-router-dom";
import "../index.css"
function EditEvent ( { events, onEditEvent, clients } ) {
const params = useParams();
const event = events.find((event) => event.id == params.id)
const navigate = useNavigate();
const [name, setName] = useState(event.name);
const [description, setDescription] = useState(event.description);
const [location, setLocation] = useState(event.location);
const [budget, setBudget] = useState(event.budget);
const [currentCost, setCurrentCost] = useState(event.current_cost);
const [startDate, setStartDate] = useState(event.start_date);
const [startTime, setStartTime] = useState(getTime(event.start_time));
const [endDate, setEndDate] = useState(event.end_date);
const [endTime, setEndTime] = useState(event.end_time);
const [selectedClient, setSelectedClient] = useState(event.client.name)
function getTime(eventTime) {
const time = eventTime.split('T')[1];
const hour = time.split(':')[0];
const minutes = time.split(':')[1];
let timeValue = '';
if (hour > 0 && hour <= 12) {
timeValue= "" + hour
} else if (hour > 12) {
timeValue= "" + (hour - 12);
} else if (hour == 0) {
timeValue= "12"
}
const standardTime = timeValue + ':' + minutes;
const dayNight = timeValue = (hour >= 12) ? " P.M." : " A.M.";
return standardTime + dayNight;
}
function handleClientChange(e) {
setSelectedClient(e.target.value)
}
function handleSubmitChanges(e) {
e.preventDefault()
const client = clients.find((client) => client.name == selectedClient)
const editedEvent = {
name: name,
description: description,
start_date: startDate,
start_time: startTime,
end_date: endDate,
end_time: endTime,
locaiton: location,
budget: budget,
current_cost: currentCost,
id: event.id,
client_id: client.id,
}
fetch(`/events/${editedEvent.id}`, {
method: 'PATCH',
headers: {
'Content-Type' : 'application/json'
},
body: JSON.stringify(editedEvent)
})
.then(r => r.json())
.then(editedEvent => {
onEditEvent(editedEvent)
navigate("/home")
})
}
console.log(selectedClient)
return event ? (
<div className='edit-background'>
<form className="edit-form" onSubmit={handleSubmitChanges}>
<div className="edit-title">Edit Event</div>
<div className="input-container ic0">
<input id="name" className="input" type="text" defaultValue={name} onChange={(e) => setName(e.target.value)}/>
<label className="edit-cut edit-cut-short">Name</label>
</div>
<div className="input-container ic0">
<input id="desc" className="input" type="text" defaultValue={description} onChange={(e) => setDescription(e.target.value)}/>
<label className="edit-cut edit-cut-short">Description</label>
</div>
<div className="input-container ic0">
<input id="start-date" className="input" type="text" defaultValue={startDate} onChange={(e) => setStartDate(e.target.value)}/>
<label className="edit-cut edit-cut-short">Start Date</label>
</div>
<div className="input-container ic0">
<input id="start-time" className="input" type="text" defaultValue={startTime} onChange={(e) => setStartTime(e.target.value)}/>
<label className="edit-cut edit-cut-short">Start Time</label>
</div>
<div className="input-container ic0">
<input id="end-date" className="input" type="text" defaultValue={endDate} onChange={(e) => setEndDate(e.target.value)}/>
<label className="edit-cut edit-cut-short">End Date</label>
</div>
<div className="input-container ic0">
<input id="end-time" className="input" type="text" defaultValue={endTime} onChange={(e) => setEndTime(e.target.value)}/>
<label className="edit-cut edit-cut-short">End Time</label>
</div>
<div className="input-container ic0">
<input id="location" className="input" type="text" defaultValue={location} onChange={(e) => setLocation(e.target.value)}/>
<label className="edit-cut edit-cut-short">Location</label>
</div>
<div className="input-container ic0">
<input id="budget" className="input" type="text" defaultValue={budget} onChange={(e) => setBudget(e.target.value)}/>
<label className="edit-cut edit-cut-short">Budget</label>
</div>
<div className="input-container ic0">
<input id="current-cost" className="input" type="integer" defaultValue={currentCost} onChange={(e) => setCurrentCost(e.target.value)}/>
<label className="edit-cut edit-cut-short">Current Cost</label>
</div>
<select value={selectedClient} onChange={handleClientChange}>
{clients.map((client) => <option key={client.id}>{client.name}</option>)}
</select>
<button type="submit" className="submit">Edit</button>
<Link to={"/home"}>
<button id='submit'>Cancel</button >
</ Link>
</form>
</div>
) : null
};
export default EditEvent;
NavBar.js
import React from "react";
import "../NavBar.css";
import { useNavigate } from 'react-router-dom';
function NavBar( {currentUser, setCurrentUser, setActive } ) {
const navigate = useNavigate()
function handleLogOut() {
navigate('/')
fetch('/logout',{method: "DELETE"}).then((r) => {
if(r.ok){
setCurrentUser(null)
}
})
};
return (
<main className="main">
<aside className="sidebar">
<p className="greeting">Hello {currentUser.first_name}</p>
<nav className="nav">
<button className="nav-button" onClick={() => setActive("NewEvent")}>New Event</button>
<button className="nav-button" onClick={() => setActive("Events")}>Events</button>
<button className="nav-button" onClick={() => setActive("Vendors")}>Vendors</button>
<button className="nav-button" onClick={handleLogOut}>Logout</button>
</nav>
</aside>
</main>
)
}
export default NavBar;
在您的代码片段中,所有访问任何name
属性的地方都在Array.prototype.map
回调中,当数组为空时,这应该是安全的,除了EditEvent
组件中的一个地方,其中events
prop是由事件id搜索的。
Array.prototype.find
返回undefined,如果数组中没有匹配的元素。
EditEvent
应该在访问结果之前检查是否发现了event
。
的例子:
function EditEvent ( { events, onEditEvent, clients } ) {
const { id } = useParams();
const event = events.find((event) => String(event.id) === id);
const navigate = useNavigate();
const [name, setName] = useState(event?.name ?? "");
const [description, setDescription] = useState(event?.description ?? "");
const [location, setLocation] = useState(event?.location ?? "");
... etc
以上使用可选链接操作符和Nullish Coalescing将初始状态设置为事件属性,或者在event[x]
为null或undefined的情况下设置为空字符串。