我试图将从axios.get请求中获得的对象数组Map为一组React组件子级。下面是我收到的完整错误:<ShowListing />
我在这里的目标是创建一个Admin组件,在这个组件中可以创建新的节目,可以编辑和删除现有的节目。我已经确认axios请求的response.data是一个对象数组,我没有将对象本身作为子对象传递,而是将它们作为道具传递给<ShowListing />
组件。我知道这个组件可以和那些道具一起工作。有人能帮我找出哪里出了问题吗?
下面是Admin组件的代码。错误似乎发生在第107-113行:
import { useState, useEffect } from 'react'
import styles from './Admin.module.css'
import axios from 'axios'
import FormData from 'form-data'
import ShowListing from './ShowListing.js'
const Admin = async () => {
const [formValues, setFormValues] = useState({
eventTitle: null,
location: null,
date: null,
time: null,
ticket: null,
desc: null,
image: null
})
const [currShows, setCurrShows] = useState(null)
useEffect(async () => {
axios.get("http://localhost:4000/getShows").then(response => {
console.log(response.data)
setCurrShows(response.data)
})
})
const handleSubmit = async (e) => {
e.preventDefault()
const formData = new FormData()
// FILE READER
const getImageFile = () => {
return new Promise(resolve => {
const reader = new FileReader()
reader.onload = function () {
resolve(reader.result)
// console.log(`IMAGE FILE:\n ${imageFile}`) // imageFile IS NOT UNDEFINED HERE, BASE64 STRING
}
reader.readAsDataURL(document.getElementById("image").files[0])
})
}
const imageFile = await getImageFile()
Array.from(document.getElementById("form").elements).forEach(element => {
switch (element.name){
case "image":
formData.append(`${element.name}`, imageFile) // UNDEFINED. WHY?
break
case "submit":
break
default:
formData.append(`${element.name}`, element.value)
}
})
console.log([...formData])
try {
const response = axios.post('http://localhost:4000/uploadShow', formData)
console.log(response)
alert('NEW SHOW SUBMITTED')
document.getElementById("form").reset()
} catch (e) {
alert(e)
console.log(e)
}
}
return (
<div>
<div className={styles.main}>
<div className={styles.titleContainer}>
<h1>KMAC ADMIN</h1>
</div>
<div className={styles.formWindow}>
<div className={styles.newShowHeader}>
<h1>New Show</h1>
<form className={styles.showForm} id="form" method="post" encType="multipart/form-data" onSubmit={e => handleSubmit(e)}>
<label htmlFor="eventTitle">Event Title: </label>
<input className={styles.fieldInput} type="text" name="eventTitle" onChange={e => setFormValues({...formValues, eventTitle: e.target.value})}/>
<br />
<label htmlFor="location">Location: </label>
<input className={styles.fieldInput} type="text" name="location"onChange={e => setFormValues({...formValues, location: e.target.value})} />
<br />
<label htmlFor="date">Date: </label>
<input className={styles.fieldInput} type="date" name="date" onChange={e => setFormValues({...formValues, date: e.target.value})}/>
<br />
<label htmlFor="time">Time: </label>
<input className={styles.fieldInput} type="time" name="time" onChange={e => setFormValues({...formValues, time: e.target.value})}/>
<br />
<label htmlFor="ticket">Ticket: </label>
<input className={styles.fieldInput} type="text" name="ticket" onChange={e => setFormValues({...formValues, ticket: e.target.value})}/>
<br />
<textarea name="desc" placeholder="Event Description" rows="8" onChange={e => setFormValues({...formValues, desc: e.target.value})}/>
<br />
<label htmlFor="image">Select Image (15MB or less): </label>
<input type="file" id="image" name="image" accept="image/jpeg" onChange={e => setFormValues({...formValues, image: e.target.files})}/>
<br />
<button className={styles.submit} name="submit" type="submit">Submit</button>
</form>
</div>
</div>
</div>
<div>
{
currShows.map(show => {
return <ShowListing params={show} />
})
}
</div>
</div>
)
}
export default Admin
以下是ShowListing组件的代码:
import { useState } from 'react'
import axios from 'axios'
import styles from './ShowListing.module.css'
// SHOW OBJECT SHAPE:
// eventTitle: null,
// location: null,
// date: null,
// time: null,
// ticket: null,
// desc: null,
// image: null
const ShowListing = (props) => {
// Toggle deletion warning
const [deleteWarning, setDeleteWarning] = useState(false)
const [editForm, setEditForm] = useState(false)
const [formValues, setFormValues] = useState({
eventTitle: null,
location: null,
date: null,
time: null,
ticket: null,
desc: null,
image: null
})
// covert props.params.date to format "year-month-day", call for date input default value
const dateConvert = () => {
const dateArr = props.params.date.split('-')
const year = dateArr.pop()
dateArr.unshift(year)
return dateArr.join('-')
}
// covert props.param.time to 24-hour format, call for time input default value
const timeConvert = () => {
const timeArr = props.params.time.split(' ')
const time = timeArr[0].split(":")
if (timeArr[1] === 'PM')
time[0] = ((parseInt(time[0])) + 12).toString()
if (parseInt(time[0]) < 10)
time[0] = "0" + time[0]
return time.join(":")
}
const handleDelete = () => {
// TODO: delete request with props.params._id
// Alert deletion and reload page
alert(`SHOW DELETED:\n${props.params.eventTitle}`)
window.location.reload()
}
const handleEditSubmit = (e) => {
e.preventDefault()
// TODO: post request for show update with props.params._id
console.log(formValues)
alert(`SHOW EDITED:\n${formValues.eventTitle}\nFORMERLY:\n${props.params.eventTitle}`)
window.location.reload()
}
return (
<div className={styles.temp}>
<div className={styles.container}>
{
deleteWarning &&
<div className={styles.deleteWarning}>
<div><p>Delete this show listing?</p></div>
<div><button className={`${styles.deleteButton} ${styles.deleteYes}`} onClick={handleDelete}>Yes</button></div>
<div><button className={`${styles.deleteButton} ${styles.deleteNo}`} onClick={() => setDeleteWarning(false)}>No</button></div>
</div>
}
<div className={styles.title}>
<p>{props.params.eventTitle}</p>
</div>
<div className={styles.date}>
<p>{`${props.params.date} -- ${props.params.time}`}</p>
</div>
<div className={styles.edit} onClick={() => setEditForm(true)}>
<img src="images/icons8-edit-30.png" />
</div>
<div className={styles.delete} onClick={() => setDeleteWarning(true)}>
<img src="images/icons8-trash-30.png" />
</div>
<br/>
</div>
{
editForm &&
<div className={styles.formContainer}>
<div className={styles.formFrame}>
<form id="editForm" onSubmit={e => handleEditSubmit(e)}>
<label className={styles.formLabel} htmlFor="eventTitle">Event Title: </label>
<br />
<input className={styles.fieldInput} type="text" name="eventTitle" defaultValue={props.params.eventTitle} onChange={e => setFormValues({...formValues, eventTitle: e.target.value})}/>
<br />
<label className={styles.formLabel} htmlFor="location">Location: </label>
<br />
<input className={styles.fieldInput} type="text" name="location" defaultValue={props.params.location} onChange={e => setFormValues({...formValues, location: e.target.value})} />
<br />
<label className={styles.formLabel} htmlFor="date">Date: </label>
<br />
<input className={styles.fieldInput} type="date" name="date" defaultValue={dateConvert()} onChange={e => setFormValues({...formValues, date: e.target.value})}/>
<br />
<label className={styles.formLabel} htmlFor="time">Time: </label>
<br />
<input className={styles.fieldInput} type="time" name="time" defaultValue={timeConvert()} onChange={e => setFormValues({...formValues, time: e.target.value})}/>
<br />
<label className={styles.formLabel} htmlFor="ticket">Ticket: </label>
<br />
<input className={styles.fieldInput} type="text" name="ticket" defaultValue={props.params.ticket} onChange={e => setFormValues({...formValues, ticket: e.target.value})}/>
<br />
<br />
<textarea className={styles.formDesc} name="desc" placeholder="Event Description" rows="8" defaultValue={props.params.desc} onChange={e => setFormValues({...formValues, desc: e.target.value})}/>
<br />
<label className={styles.formLabel} htmlFor="image">Please update image (15MB or less): </label>
<input style={{color: "red"}} type="file" id="image" name="image" accept="image/jpeg" onChange={e => setFormValues({...formValues, image: e.target.files})}/>
<br />
<br />
<button className={styles.submit} name="submit" type="submit">Submit</button>
<button name="cancel" onClick={() => setEditForm(false)}>Cancel</button>
</form>
</div>
</div>
}
</div>
)
}
export default ShowListing
更新:根据phasma的建议,我从Admin
组件和useEffect
中删除了async
。这清除了原来的错误,但现在我收到了一个新的错误:Admin.js:107 Uncaught TypeError: Cannot read properties of null (reading 'map')
为什么在useEffect
中设置currShows
时它为空?
1条答案
按热度按时间8ehkhllq1#
您将
Admin
组件标记为async
,这对于React组件是无效的。删除该修饰符,错误就会清除。edit;为了回答您的新问题,currShows在调用完成之前为null,这很可能是在第一次呈现之后。
null
可能是一个加载微调器或者其他指示后台正在工作的东西,但希望这能帮助清除错误。