Реагируйте после ошибки типа обновления: статьи[(статьи.длина — 1)] не определена

#javascript #reactjs

Вопрос:

Я создаю приложение react, и у меня проблема. Всякий раз, когда я обновляю страницу, я получаю ошибку типа: статьи[(статьи.длина — 1)] не определена, и это происходит из-за параметра src. Я хочу отобразить изображения 3 новейших статей, которые я добавил на сервер json. Но если я изменю src, например, на»», и после этого я запущу сервер, все будет работать нормально. Я могу изменить значение src обратно на articles[(статьи.длина — 1)] и без обновления всего, как следует. Я думаю, проблема в том, что статьи компилируются до того, как они получат значение от сервера json, и я не знаю, как это можно исправить. Перепробовал множество способов, таких как получение сдачи, но ни один из них не сработал.

в ArticlesList.js

 const ArticlesList = ({ articles }) => {
  
  return (
    <div className="whole">
      {console.log(articles.length)}
      <Carousel  fade> 
        <Carousel.Item>
          <img
            className="d-block w-100"
            src={articles[articles.length-1].img}
            alt="First slide"
            width="1100" height="400"
          />
          <Carousel.Caption>
            <h3>TESTESTESSTESTESTES</h3>
          </Carousel.Caption>
        </Carousel.Item>
        <Carousel.Item>
          <img
            className="d-block w-100"
            src={articles[articles.length-2].img}
            alt="Second slide"
            width="1100" height="400"
          />
          <Carousel.Caption>
            <h3>Second slide labelxd</h3>
          </Carousel.Caption>
        </Carousel.Item>
        <Carousel.Item>
          <img
            className="d-block w-100"
            src={articles[articles.length-3].img}
            alt="Third slide"
            width="1100" height="400"
          />
          <Carousel.Caption>
            <h3>Third slide label</h3>
          </Carousel.Caption>
        </Carousel.Item>
      </Carousel>
      <CardGroup className="articles"> 
          {articles.map((article) => (
            <Col xs={4} md={4} lg={4} key={article.id}>
              <Article article={article}/>
            </Col>
          ))}
      </CardGroup>
    </div>
  )
}
 

и в App.js

 function App() {

  const [articles, setArticles] = useState([])

  useEffect(() => {
    const getArticles = async () =>{
      const articlesFromServer = await fetchArticles()
      setArticles(articlesFromServer)
    }

    getArticles()
  }, [])

  const fetchArticles = async () =>{
    const res = await fetch(
      'http://localhost:5000/articles')
    const data = await res.json()

    return data
  }
  return (
    <Router>
      <>
      <Header />
      <Route path='/' exact render={(props) => (
        <>
          <ArticleList articles={articles} />
        </>
      )} />
      <Route path='/details/:id' exact component={ArticleDetails} />
      </>
    </Router>
  );
}

 

Комментарии:

1. Можете ли вы подтвердить, что статьи внутри ArticlesList не являются неопределенными, когда вы передаете их в качестве параметра?

2. Вы смотрите на визуализацию списка статей или списков статей? Ваше соглашение об именах меняет их местами.

3. Список статей ты прав, мой плохой

Ответ №1:

Когда вы обновляете страницу, приложение пытается получить данные с внутреннего сервера, но ваш компонент ArticleDetails уже загружен. Поскольку articles состояние является пустым массивом, оно будет возвращено articles[articles.length-x] как undefined (что, в свою очередь, приведет к необнаруженной ошибке articles[articles.length-x].img ).

Поэтому в таких случаях используйте необязательную цепочку следующим образом.

 articles[articles.length-x]?.img
 

Полный код будет выглядеть следующим образом.

 const ArticlesList = ({ articles }) => {
  
  return (
    <div className="whole">
      {console.log(articles.length)}
      <Carousel  fade> 
        <Carousel.Item>
          <img
            className="d-block w-100"
            src={articles[articles.length-1]?.img}
            alt="First slide"
            width="1100" height="400"
          />
          <Carousel.Caption>
            <h3>TESTESTESSTESTESTES</h3>
          </Carousel.Caption>
        </Carousel.Item>
        <Carousel.Item>
          <img
            className="d-block w-100"
            src={articles[articles.length-2]?.img}
            alt="Second slide"
            width="1100" height="400"
          />
          <Carousel.Caption>
            <h3>Second slide labelxd</h3>
          </Carousel.Caption>
        </Carousel.Item>
        <Carousel.Item>
          <img
            className="d-block w-100"
            src={articles[articles.length-3]?.img}
            alt="Third slide"
            width="1100" height="400"
          />
          <Carousel.Caption>
            <h3>Third slide label</h3>
          </Carousel.Caption>
        </Carousel.Item>
      </Carousel>
      <CardGroup className="articles"> 
          {articles.map((article) => (
            <Col xs={4} md={4} lg={4} key={article.id}>
              <Article article={article}/>
            </Col>
          ))}
      </CardGroup>
    </div>
  )
}
 

Надеюсь, это решит вашу проблему.

Комментарии:

1. Большое спасибо! вау, я не знаю, как я это пропустил

Ответ №2:

Основное недоразумение, которое у вас есть, кроется внутри App компонента. Вы предполагаете, что жизненный цикл React componentDidMount будет ожидать асинхронных вызовов (в вашем случае fetchArticles ).

Что происходит, так это то, что App компонент будет монтироваться независимо от того, вернул ли ваш API нужные вам статьи. Поэтому каждый компонент, который не защищает от не определенного значения articles , обречен на сбой с нулевым исключением.

Добавьте нулевые проверки для статей в этих компонентах.

Ответ №3:

Я не знаю, как реагировать, но я бы предложил это

Это основано на моем подходе в Vue и т. Д. Я бы проверил длину articles , прежде чем делать что-либо, что зависело бы от того, есть ли там контент.

В вашей функции рендеринга не могли бы вы просто вставить if , например , вот так:

 const ArticlesList = ({ articles }) => {
  let result = ""
  if (articles amp;amp; articles.length >0){

    result  = ( // Put things for .length-1 
         )
  } 
  if (articles amp;amp; articles.length >1){

    result  = ( // Put things for .length-2 
         )
  } 
        if (articles amp;amp; articles.length >2){

    result  = ( // Put things for .length-3 
         )
  }
  return result 
 

Пожалуйста, не кричите на меня, если это неправильный синтаксис реакции: я просто показываю вам принцип, который я бы использовал в Vue. 😎

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

Вам нужно только один раз указать, как отобразить статью:

 result = ""
const last3articles = articles.slice(Math.max(articles.length-3,0)).reverse()
last3articles.forEach(article=>{
   result  = ........// the part for a single article.
})
 

Комментарии:

1. Это тоже правильно. Но допустим, если length меньше 2. Тогда articles[articles.length-3].img это снова приведет к необнаруженной ошибке, верно ?

2. Ах, я пропустил тот факт, что вы ссылались на различные индексы статей. Я обновил свое предложение

3. Это тоже работает! спасибо c: