如何更改作为列传递给 React Table 的子组件的道具的值?

How to change the value of a prop of Sub Component passed as a column to React Table?

我在 Web 应用程序中使用 React Table 库。

我将一个组件作为列传递给 table。 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)}
        />
      )
    }
  ];

我的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 道具需要 true 它应该传递给 table 并且需要文本为进行中,直到 API 呼叫完成。

我可以按如下方式更改 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 Link 为我提供更好的解决方案。谢谢

而不是将 inProgress 属性传递给 TestComponent,您可以在 TestComponent 中维护一个本地状态,用于确定是否显示进度文本或按钮,并且只传递idonClickHanlder 道具 TestComponent.

TestComponent中点击按钮时,可以设置TestComponent的本地状态显示进度文本,然后调用作为prop传递的onClickHandler函数,传入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 的本地状态,因为它是一个功能组件,但您也可以在 class 组件中使用相同的逻辑。

sampleData 数组中的 TestComponent 更改为仅传递两个属性,idonClickHandler

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

并将 App 组件中的 onClickHandler 方法更改为:

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

演示

或者,您可以使 App 组件中的 onClickHandler 函数成为 return 一个 Promise,当 API 请求完成时,它会被执行。这样您就不必将回调函数从 TestComponent 传递到 App 组件中的 onClickHandler 方法。

onClickHandler 方法更改为:

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

并将TestComponent更改为:

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 (
    <div>
      {showProgress ? (
        <p>In Progress </p>
      ) : (
        <button onClick={handleClick}>click me</button>
      )}
    </div>
  );
};

演示