我是React的新手,并且使用React钩子。我有一个功能组件,需要在页面上显示一些信息。我收到并正确返回jobs
数组,我可以使用map
对其进行迭代,并成功显示其信息,但也想接收另一个数组:location
。该数组基于jobs
数组:我需要首先接收jobs
,然后获取其位置ID,然后接收信息,并将其放入我的位置数组中,以便以后在我的信息页面中使用。问题是,当我添加位置数组时,我收到多个错误,例如res.json is not a function
等。这是我的代码:
function useJobs () {
const [jobs, setJobs] = React.useState([])
const [locations, setLocations] = React.useState([])
React.useEffect(() => {
fetch('/api/jobs/list-jobs', { headers: headers })
.then(r => r.json())
.then(setJobs)
}, [])
React.useEffect(() => {
jobs.map(job => (
axios.get(`/api/jobs/view-location/${job.location}/`, { headers: headers })
.then(res => res.json())
.then(setLocations)
))
}, [jobs], [])
return (jobs, locations)
}
export default function Jobs () {
const classes = useStyles()
const jobs = useJobs()
const locations = useJobs()
return (
<>
{jobs.map(job => (
<>
<div className={classes.root} key={job.id}>
......
<Row>
<Col style={{ color: 'black' }}>Title:{job.title} </Col>
<Col>Company Name:{job.company_name} </Col>
<Col style={{ color: 'black' }}>Internal Code:{job.internal_code} </Col>
</Row>
{locations.map(location => (
<Col key={location.id} style={{ color: 'black' }}>Location:{location.country}</Col>))
}
如您所见,在添加location
部分之前,我的job
信息正确显示。但是当我想根据job.location
GET请求提供的信息显示位置信息时,会收到这些错误。我做错了什么?正确的方法是什么?
答案 0 :(得分:2)
不需要通过res.json()
运行axios请求响应。提取请求是必需的。此外,axios
响应具有多个信息,并且数据由resp.data
useEffect依赖项也只是一个参数,而您传递了两个参数
React.useEffect(() => {
axios('/api/jobs/list-jobs', { headers: headers })
.then(res => setJobs(res.data))
}, [])
React.useEffect(() => {
jobs.map(job => (
axios.get(`/api/jobs/view-location/${job.location}/`, { headers: headers })
.then(res => setLocations(prev => ({...prev, [job.id]: res.data})))
))
}, [jobs])
useJobs
钩子同时返回位置和作业,因此您不需要执行两次,也不需要从useJobs作为对象返回结果,即拥有 return { jobs, locations }
代替
return ( jobs, locations )
完整代码:
function useJobs () {
const [jobs, setJobs] = React.useState([])
const [locations, setLocations] = React.useState({})
React.useEffect(() => {
axios('/api/jobs/list-jobs', { headers: headers })
.then(res => setJobs(res.data))
}, [])
React.useEffect(() => {
for (const job of jobs) {
axios(`/api/jobs/view-location/${job.location}/`, { headers: headers })
.then((data) => {
setLocations(prev => ({...prev, [job.id]: res.data}))
})
}
}, [jobs])
return [jobs, locations]
}
export default function Jobs () {
const classes = useStyles()
const { jobs,locations} = useJobs();
return (
<>
{jobs.map(job => (
<>
<div className={classes.root} key={job.id}>
......
<Row>
<Col style={{ color: 'black' }}>Title:{job.title} </Col>
<Col>Company Name:{job.company_name} </Col>
<Col style={{ color: 'black' }}>Internal Code:{job.internal_code} </Col>
</Row>
{locations[job.id].map(location => (
<Col key={location.id} style={{ color: 'black'
}}>Location:{location.country}</Col>))
}
答案 1 :(得分:1)
此行不返回jobs
和locations
:
return (jobs, locations)
相反,它计算jobs
,丢弃该结果,计算locations
,然后返回该值。
如果要返回包含jobs
和locations
的数组,则可以返回包含它们的数组作为条目:
return [jobs, locations];
并像这样使用它,而不是两次调用useJobs
:
const [jobs, locations] = useJobs();
或返回包含它们的对象作为属性:
return {jobs, locations};
并再次使用它,而不是两次调用useJobs
:
const {jobs, locations} = useJobs();
还有其他一些事情可以跳出来:
正如我在评论中提到的那样,您的代码正在fetch
API中成为猎枪的猎物:fetch
仅在 network 错误而不是HTTP上拒绝错误;您必须单独检查(通常通过检查response.ok
)。详细信息on my anemic little blog。
useEffect
仅接受最多两个参数,而不是三个。您在这里使用了三个:
React.useEffect(() => {
jobs.map(job => (
axios.get(`/api/jobs/view-location/${job.location}/`, { headers: headers })
.then(res => res.json())
.then(setLocations)
))
}, [jobs], [])
// −−−−−−^^^^−−−−−−−−−−−−−−−− remove
在一个地方使用fetch
但在另一个地方使用axios
似乎很奇怪。我建议对其中之一进行标准化。除非您有充分的理由使用axios
,否则我可能只会在fetch
上使用包装器来检查HTTP错误和拒绝。
我不使用axios
,但是Shubham Khatri points out在您的代码中的使用问题。
您正在将map
用作数组的简单迭代器。绝对不合适,map
是根据map
回调的结果创建一个 new 数组。如果您不使用map
的返回值,请改用forEach
(或for-of
)。
您正在循环执行每个作业的ajax调用,但随后将结果存储在locations
中。这意味着循环中每个调用的结果都会覆盖之前的所有结果。大概您打算对结果的 all 做些事情。
一起考虑:
// A reusable JSON fetch wrapper that handles HTTP errors
function fetchJSON(...args) {
return fetch('/api/jobs/list-jobs', { headers: headers })
.then(r => {
if (!r.ok) {
throw new Error("HTTP error " + r.status)
}
return r.json()
});
}
function useJobs () {
const [jobs, setJobs] = React.useState([])
const [locations, setLocations] = React.useState([])
React.useEffect(() => {
fetchJSON('/api/jobs/list-jobs', { headers: headers })
.then(setJobs)
}, [])
React.useEffect(() => {
// *** Don't use `map` as a simple iteration construct
for (const job of jobs) {
fetchJSON(`/api/jobs/view-location/${job.location}/`, { headers: headers })
.then(setLocations) // *** Need to handle #6 here
}
}, [jobs]) // *** No additional array here
return [jobs, locations]
}
export default function Jobs () {
const classes = useStyles()
const [jobs, locations] = useJobs() // *** Use jobs and locations here
return (
<>
{jobs.map(job => (
<>
<div className={classes.root} key={job.id}>
......
<Row>
<Col style={{ color: 'black' }}>Title:{job.title} </Col>
<Col>Company Name:{job.company_name} </Col>
<Col style={{ color: 'black' }}>Internal Code:{job.internal_code} </Col>
</Row>
{locations.map(location => (
<Col key={location.id} style={{ color: 'black' }}>Location:{location.country}</Col>))
}
...但是不能处理#6。
答案 2 :(得分:0)
除了其他答案,您在调用setLocations
时也遇到了问题。
因为您是从map函数内部调用的,所以每个作业都调用一次。
jobs.map(job => (
axios.get(`/api/jobs/view-location/${job.location}/`, { headers: headers })
.then(setLocations)
))
您实际上是在说:
setLocations('London');
setLocations('Paris');
很明显,如果您两次打来电话,您将失去伦敦,只保留最终位置。
您原本打算将所有位置存储在一个数组中,所以请等待所有诺言完成然后再将它们一起存储。
Promise.all(
jobs.map(job => (
axios.get(`/api/jobs/view-location/${job.location}/`, { headers: headers })
.then(response => response.data)
))
)
.then(allLocations => setLocations(allLocations))