Как изменить значение свойства подкомпонента, переданного в качестве столбца в React Table? - PullRequest
1 голос
/ 05 августа 2020

Я использую React Table Библиотеку в веб-приложении.

Я передаю компонент в виде столбца в таблицу. Столбцы и данные для таблицы выглядят следующим образом.

  columns = [
    {
      Header: "Name",
      accessor: "name"
    },
    {
      Header: "Action",
      accessor: "action"
    }
  ];

  sampleData = [
    {
      id: 1,
      name: "Product one",
      action: (
        <TestComponent
          id={1}
          inProgress={false}
          onClickHandler={id => this.onClickHandler(id)}
        />
      )
    },
    {
      id: 2,
      name: "Product two",
      action: (
        <TestComponent
          id={2}
          inProgress={false}
          onClickHandler={id => this.onClickHandler(id)}
        />
      )
    }
  ];

My TestComponent Как показано ниже.

const TestComponent = ({ id, inProgress, onClickHandler }) => {
  return (
    <div>
      {inProgress ? (
        <p>In Progress </p>
      ) : (
        <button onClick={() => onClickHandler(id)}>click me</button>
      )}
    </div>
  );
};

Какова моя цель, когда пользователь нажимает на кнопке click me необходимо вызвать Backend API. В то время inProgress prop должно быть true, и оно должно передаваться в таблицу и требовать текст как In Progress, пока вызов API не завершится.

I мог бы сделать это, изменив state, как показано ниже.

  onClickHandler(id) {
    const newData = this.sampleData.map(data => {
      if (data.id === id) {
        return {
          ...data,
          action: (
            <TestComponent
              id={1}
              inProgress={true}
              onClickHandler={id => this.onClickHandler(id)}
            />
          )
        };
      }
      return data;
    });
    this.setState({ data: newData });

    // Here I Call the Backend API and after complete that need to show the click me button again.
    setTimeout(() => {
      this.setState({ data: this.sampleData });
    }, 3000);
  }

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

Вы можете использовать эту StackBlitz Ссылку, чтобы дать мне лучшее решение. Спасибо.

1 Ответ

1 голос
/ 05 августа 2020

Вместо того, чтобы передавать inProgress prop в TestComponent, вы могли бы поддерживать локальное состояние в TestComponent, которое используется для определения, показывать ли текст прогресса или кнопку, и передавать только id и onClickHanlder props в TestComponent.

Когда кнопка нажата в TestComponent, вы можете установить локальное состояние TestComponent для отображения текста прогресса, а затем вызвать функцию onClickHandler, переданную как prop, передав в опоре id и функции обратного вызова в качестве аргументов. Эта функция обратного вызова будет вызываться после завершения запроса API. Эта функция обратного вызова определена внутри TestComponent и только переключает локальное состояние TestComponent, чтобы скрыть текст о ходе выполнения и снова показать кнопку.

Измените TestComponent на, как показано ниже:

const TestComponent = ({ id, onClickHandler }) => {
  const [showProgress, setShowProgress] = React.useState(false);

  const toggleShowProgress = () => {
    setShowProgress(showProgress => !showProgress);
  };

  const handleClick = () => {
    setShowProgress(true);
    onClickHandler(id, toggleShowProgress);
  };

  return (
    <div>
      {showProgress ? (
        <p>In Progress </p>
      ) : (
        <button onClick={handleClick}>click me</button>
      )}
    </div>
  );
};

Я использовал useState хук для поддержания локального состояния TestComponent, поскольку это функциональный компонент, но вы также можете использовать тот же logi c в компоненте класса.

Измените массив TestComponent в sampleData так, чтобы он передавал только два свойства: id и onClickHandler.

{
   id: 1,
   name: "Product one",
   action: <TestComponent id={1} onClickHandler={this.onClickHandler} />
 }

и измените метод onClickHandler в компоненте App на:

onClickHandler(id, callback) {
   // make the api request, call 'callback' function when request is completed
    setTimeout(() => {
      callback();
    }, 3000);
}

Демо

Edit crazy-fire-fvlhm

Alternatively, you could make onClickHandler function in App component to return a Promise that is fulfilled when API request completes. This way you don't have to pass a callback function from TestComponent to onClickHandler method in App component.

Change onClickHandler method to:

onClickHandler(id) {
   return new Promise((resolve, reject) => {
     setTimeout(resolve, 3000);
   });
}

and change TestComponent to:

const TestComponent = ({ id, onClickHandler }) => {
  const [showProgress, setShowProgress] = useState(false);

  const toggleShowProgress = () => {
    setShowProgress(showProgress => !showProgress);
  };

  const handleClick = () => {
    setShowProgress(true);

    onClickHandler(id)
      .then(toggleShowProgress)
      .catch(error => {
        toggleShowProgress();
        // handle the error
      });
  };

  return (
    
      {showProgress ? (
        In Progress 
      ) : (
        
      )}
    
  );
};

Demo

Отредактируйте Practical-sinoussi-r92qj

...