Реакция на хук useState / useEffect не возвращает информацию должным образом - PullRequest
0 голосов
/ 07 мая 2020

Я новичок в React и использую React hooks. У меня есть функциональный компонент, который должен отображать некоторую информацию на странице. Я получаю и возвращаю массив заданий правильно, и я могу выполнить итерацию в нем и успешно показать его информацию, но также хочу получить другой массив: location. этот массив основан на массиве jobs: сначала мне нужно получить jobs, затем получить его идентификатор местоположения, а затем получить информацию и поместить ее в свой массив местоположений, который будет использоваться на моей информационной странице позже. проблема в том, что в моей форме, когда я хочу перебрать местоположения, вместо фактического отображения location.country перед моим текстом он трижды повторяет текст JSX «Местоположение:» в моей форме (у меня есть 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 таких объекта заданий, и для каждого я хочу напечатать правильное местоположение в соответствии с массивом job.location location, который я получил в useEffect. все остальные поля массива jobs работают правильно. как правильно реализовать локацию?

1 Ответ

1 голос
/ 07 мая 2020

Вы извлекаете данные для местоположений для отдельных заданий, но переопределяете состояние местоположений только при использовании .then(setLocations)

Вместо этого вы должны сохранять местоположения как объект с идентификатором задания в качестве ключа

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 для обновления всех местоположений в одном go

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]
    }

Теперь вы должны отметить, что местоположение, соответствующее каждому идентификатору задания, является просто объектом и не массив (согласно обсуждению в чате), поэтому вам не нужно отображать

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