React useState / useEffect挂钩无法正确返回信息

时间:2020-05-07 09:35:22

标签: javascript arrays reactjs react-hooks

我是React的新手,并且使用React钩子。我有一个功能组件,需要在页面上显示一些信息。我收到并正确返回Jobs数组,可以在其中进行迭代并成功显示其信息,但也想接收另一个数组:location。该数组基于jobs数组:我需要首先接收jobs,然后获取其位置ID,然后接收信息,并将其放入我的位置数组中,以便以后在我的信息页面中使用。问题是,当我想在位置中进行迭代时,在表单中,而不是在文本前面实际显示location.country时,它在表单中重复了JSX文本“ Location:” 3次(我有3个工作对象)。我知道我必须将该位置数组保存在useEffect中,但是它仅接受2个参数。这是我的代码:

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(() => {
    for (const job of jobs) {
      fetchJSON(`/api/jobs/view-location/${job.location}/`, { headers: headers })
        .then(setLocations)// *** Need to handle #6 here
    }
  }, [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.map(location => (
 <Col key={location.id} style={{ color: 'black' }}>Location:{location.country}</Col>))
}

我有3个这样的作业对象,对于每个作业对象,我想根据在useEffect中收到的job.location位置数组来打印正确的位置。 jobs数组的所有其他字段均正常工作。如何正确实现位置部分?

1 个答案:

答案 0 :(得分:1)

您获取单个作业的位置数据,但仅在使用.then(setLocations)时覆盖位置状态

您必须改为将位置存储为以工作ID为键的对象

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(() => {
    for (const job of jobs) {
      fetchJSON(`/api/jobs/view-location/${job.location}/`, { headers: headers })
        .then((locations) => {
           setLocations(prev => ({...prev, [job.id]: locations}))
        })
    }
  }, [jobs])

  return [jobs, locations]
}

但是,对您来说,更好的方法是使用Promise.all一次更新所有位置

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(() => {
          async function fetchLocations() {
            const promises = [];
            for (const job of jobs) {
              promises.push(fetchJSON(`/api/jobs/view-location/${job.location}/`, { headers: headers })
                .then((locations) => {
                   return {[job.id]: locations }
                }))
            }
            const data = await Promise.all(promises);
            setLocations(prev => Object.assign({}, ...data))
           }
            fetchLocations();
          }, [jobs])
        return [jobs, locations]
    }

现在您必须注意,与每个工作ID对应的位置只是一个对象,而不是一个数组(根据聊天中的讨论),因此您不需要映射

{locations[job.id] && <Col key={locations[job.id].id} style={{ color: 'black' }}>Location:{locations[job.id].country}</Col>}