Реакция: данные не отображаются, пока страница не обновится

В настоящее время я создаю простой рабочий процесс CRUD с использованием React и GraphQL. После создания объекта (в данном случае article, который состоит только из id, title и description.), я возвращаюсь на страницу Index, на которой отображаются все созданные в данный момент статьи. Моя проблема заключается в том, что после создания статьи на индексной странице созданная статья не отображается, пока я не обновлю страницу. Я использую apollo для запроса API-интерфейса graphql и отключил кеширование, поэтому я не уверен, почему данные не отображаются. Я установил точки останова в моей функции ArticlesIndex's componentDidMount и убедился, что она выполняется, и во время выполнения база данных действительно включает недавно добавленную article.

Моя серверная сторона на самом деле никогда не срабатывает, когда выполняется запрос на стороне клиента для получения всех статей. Я не уверен, что кэширует эти данные и почему они не извлекаются с сервера, как ожидалось.

Мой компонент ArticlesCreate вставляет новую запись и перенаправляет обратно на компонент ArticlesIndex следующим образом:

handleSubmit(event) {  
    event.preventDefault();  
    const { client } = this.props;

    var article = {
      "article": {
        "title": this.state.title,
        "description": this.state.description
      }
    };

    client
    .mutate({ mutation: CREATE_EDIT_ARTICLE, 
      variables: article })
    .then(({ data: { articles } }) => {
        this.props.history.push("/articles");  
    })
    .catch(err => {
        console.info("err", err);
    });

  }
}

тогда мой компонент ArticlesIndex извлекает все статьи из базы данных следующим образом:

componentDidMount = () => {
    const { client } = this.props; //client is an ApolloClient
    client
    .query({ query: GET_ARTICLES })
    .then(({ data: { articles } }) => {
        if (articles) {
          this.setState({ loading: false, articles: articles });
        }
    })
    .catch(err => {
        console.info("err", err);
    });
};

и я настроил ApolloClient, чтобы он не кэшировал данные, как в моем App.js, следующим образом:

const defaultApolloOptions = {
  watchQuery: {
    fetchPolicy: 'network-only',
    errorPolicy: 'ignore',
  },
  query: {
    fetchPolicy: 'network-only',
    errorPolicy: 'all',
  },
}

export default class App extends Component {
  displayName = App.name;

  client = new ApolloClient({
    uri: "https://localhost:44360/graphql",
    cache: new InMemoryCache(),
    defaultOptions: defaultApolloOptions
  });

  //...render method, route definitions, etc
}

Почему это происходит и как я могу это решить?

Предполагая, что articles является массивом this.setState({ loading: false, articles: [...articles] });? Или JSON нужно парсить?

FortyTwo 18.02.2019 17:57
articles действительно является массивом, однако настройка состояния работает правильно. Проблема, насколько я понял, заключается в том, что articles в обратном вызове .then моего запроса в componentDidMount содержит устаревшие данные (до того, как был выполнен вызов создания)
GregH 18.02.2019 17:59

Как ты возвращаешься? Кнопка «Назад» в браузере или вызов компонента «Индекс»?

FortyTwo 18.02.2019 18:03
this.props.history.push("/articles"); в компоненте ArticlesCreate (этот маршрут предназначен для компонента ArticlesIndex
GregH 18.02.2019 18:04
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
2
4
2 135
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я вижу, что вы получаете данные и устанавливаете состояние своих компонентов при начальном монтировании. Скорее всего, когда вы перенаправляете, он не запускает хук жизненного цикла componentDidMount, поскольку он уже смонтирован, если это проблема, попробуйте использовать хук жизненного цикла компонентдидобдате, чтобы ваш компонент знал, что было обновление, и повторно установил данные.

Он устанавливает состояние, поэтому следует вызывать рендеринг. Вы должны звонить серверу из componentDidMount, а не из componentDidUpdate

FortyTwo 18.02.2019 17:55

Я могу подтвердить, что componentDidMount вызывается после того, как мой компонент создания перенаправляется обратно к моему индексному компоненту. Однако по какой-то причине запрос, похоже, на самом деле не выполняется и работает с устаревшими данными. (articles в обратном вызове не обновляется, но этот код выполняется)

GregH 18.02.2019 17:56
Ответ принят как подходящий

Похоже, проблема в том, что ApolloBoost не поддерживает defaultOptions, как было отмечено в этом выпуске github. Чтобы решить проблему, я изменил:

const defaultApolloOptions = {
  watchQuery: {
    fetchPolicy: 'network-only',
    errorPolicy: 'ignore',
  },
  query: {
    fetchPolicy: 'network-only',
    errorPolicy: 'all',
  },
}

export default class App extends Component {
  displayName = App.name;

  client = new ApolloClient({
    uri: "https://localhost:44360/graphql",
    cache: new InMemoryCache(),
    defaultOptions: defaultApolloOptions
  });

  //...render method, route definitions, etc
}

К:

const client = new ApolloClient({
  uri: "https://localhost:44360/graphql"
});

client.defaultOptions = {
  watchQuery: {
    fetchPolicy: 'network-only',
    errorPolicy: 'ignore',
  },
  query: {
    fetchPolicy: 'network-only',
    errorPolicy: 'all',
  },
};

export default class App extends Component {
    //....
}

Другие вопросы по теме