Как структурировать код React с помощью Apollo Query, чтобы случайно запрошенный массив объектов не перерисовывался с изменением состояния?

Проблема: Я использую Apollo Client, и колода визуализируется как эта «/ deck / 2», и я хочу случайным образом перемешать карты и отображать только по одной с кнопкой для просмотра следующей. Я продолжаю сталкиваться с проблемой повторного рендеринга React каждый раз, когда изменяется состояние (мой счетчик индекса onClick +1), который перетасовывает карты, поскольку переменная shuffledCards находится внутри запроса. Я не знаю, как этого избежать.

Как я могу перетасовать список, не беспокоясь о том, что они будут перетасованы "onClick" кнопки. Я полагаю, что есть способ получить рандомизированный массив за пределами рендеринга, который я могу сделать в Regular response, но с помощью запросов Apollo, которые я не могу понять.

Здесь я спотыкаюсь из-за моего неопытности в React и Graphql с Apollo, и я не нашел похожего проекта Apollo graphql, на который можно было бы опираться. Я не могу использовать карту для объекта, но, может быть, есть способ использовать карту для отображения 1 объекта массива за раз? Не нашел рабочего решения.

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

Вот код:

    import React, { Component, Fragment } from "react";
    ```
    import CardItem from "./CardItem";

    const CARDS_QUERY = gql`
      query CardsQuery($id: ID!) {
        ```
    `;

    export class Cards extends Component {
      constructor(props) {
        super(props);
        this.state = {
          index: 0
        };

        this.goToNext = this.goToNext.bind(this);
      }

      goToNext() {
        this.setState({
          index: this.state.index + 1
        });
      }

      shuffle(array) {
        for (let i = array.length - 1; i > 0; i--) {
          const j = Math.floor(Math.random() * (i + 1));
          [array[i], array[j]] = [array[j], array[i]];
        }
        return array;
      }

      render() {
        let { id } = this.props.match.params;
        id = parseInt(id);

        return (
          <Fragment>
            <Query query = {CARDS_QUERY} variables = {{ id }}>
              {({ data, error, loading }) => {
                if (loading) {
                  return <Loading />;
                }
                if (error)
                }

                const CardsToRender = data.deck.cards;

                //This variable gets reshuffled at every re-render
                const shuffledCards = this.shuffle(CardsToRender);

                //Single item to be returned
                const item = shuffledCards[this.state.index];

                if (this.state.index >= shuffledCards.length) {
                  return (
                    <div>
                      <h1>Finished</h1>
                    </div>
                  );
                } else {
                  return (
                    <Fragment>
               // Here I can get one item to display, but if I press next, the state changes which fires a re-render, 
           //shuffling the cards once more.  My intention is to only shuffle cards at first render until the browser page is
           //refreshed or user navigates away
              <h1>{item.front}</h1>
              <h1>{item.back}</h1>

                   //My second attempt is to map out the cards, but I have only been able to render a list,
                  // but not one at a time.  Maybe there is a simple code solution in my .map to display
                    //one at a time without needing to change state?
                      {shuffledCards.map(card => (
                        <CardItem key = {card.id} card = {card} />
                      ))}
                      <p>
                        <button onClick = {this.goToNext}>Next</button>
                      </p>
                    </Fragment>
                  );
                }
              }}
            </Query>
          </Fragment>
        );
      }
    }

    ```

Буду благодарен за любую оказанную помощь. Спасибо!

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
1
0
541
2

Ответы 2

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

Реорганизуйте ваш компонент на две части.

1) ShuffleCards.js (дайте любое имя по своему усмотрению :)) - переместите свой компонент в «ShuffleCards» и передайте перемешанные шнуры дочернему компоненту, где вы можете обновить состояние для рендеринга следующей карты.

// ShuffledCards.js

 import React, { Component, Fragment } from "react";
    ```
    import CardItem from "./CardItem";

    const CARDS_QUERY = gql`
      query CardsQuery($id: ID!) {
        ```
    `;

    export class ShuffleCards extends Component {
      constructor(props) {
        super(props);
      }

      shuffle(array) {
        for (let i = array.length - 1; i > 0; i--) {
          const j = Math.floor(Math.random() * (i + 1));
          [array[i], array[j]] = [array[j], array[i]];
        }
        return array;
      }

      render() {
        let { id } = this.props.match.params;
        id = parseInt(id);
        return (
          <Fragment>
            <Query query = {CARDS_QUERY} variables = {{ id }}>
              {({ data, error, loading }) => {
                if (loading) {
                  return <Loading />;
                }
                if (error) {
                }
                const CardsToRender = data.deck.cards;
                const shuffledCards = this.shuffle(CardsToRender);
                return (
                    <Cards shuffledCards = {shuffledCards} /> 
                );
              }}
            </Query>
          </Fragment>
        );
      }
    }

Переместите код, который обрабатывает отображаемую карту и обновляет состояние, в компонент «Карты».

import React, { Component, Fragment } from "react";
import CardItem from "./CardItem";

export class Cards extends Component {
      constructor(props) {
        super(props);
        this.state = {
          index: 0
        };

        this.goToNext = this.goToNext.bind(this);
      }

      goToNext() {
        this.setState({
          index: this.state.index + 1
        });
      }

    render() {
    const {shuffledCards} = this.props || [];
    return (
        <div>
        {
            this.state.index >= shuffledCards.length ?
              <div>
                <h1>Finished</h1>
              </div>
              :
              <Fragment>
                  <h1>{item.front}</h1>
                  <h1>{item.back}</h1>
                  {
                      shuffledCards.map(card => (
                      <CardItem key = {card.id} card = {card} />
                      ))
                  }
                  <p>
                  <button onClick = {this.goToNext}>Next</button>
                  </p>
              </Fragment>
        }
        </div>
        )
    }
}

Вы вызываете this.shuffle () в своей функции рендеринга - поэтому он будет перемешиваться при каждом рендеринге.

Переместите это в свой конструктор, и он будет вызван только один раз.

constructor(props) {
  super(props);
  this.state = {
    index: 0
  };

  this.goToNext = this.goToNext.bind(this);
  const CardsToRender = data.deck.cards;
}

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