简体   繁体   English

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

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

I am using React Table Library in Web Application.我在 Web 应用程序中使用React 表库。

I am passing a component as a column to the table.我将一个组件作为列传递给表。 Columns and data for the table looks like below.表格的列和数据如下所示。

  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 Looks like below.我的TestComponent如下所示。

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

What my purpose is, When user click on click me button it needs to call a Backend API .我的目的是,当用户单击click me按钮时,它需要调用Backend API At that time inProgress prop need to be true and it should pass to the table and need text as In Progress until API call completed.那时inProgress道具需要为true ,它应该传递到表格并需要文本作为正在进行中,直到 API 调用完成。

I could be able to do it changing state as below.我可以改变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);
  }

I could be able to achieve what I need But I am not satisfied the way I am changing the state .我可以实现我所需要的但我对更改state的方式不满意。 I need to know is there a better way of doing this without changing state like this.我需要知道是否有更好的方法来做到这一点,而无需像这样更改state

You can use this StackBlitz Link for giving me a better solution.您可以使用此StackBlitz Link 为我提供更好的解决方案。 Thanks.谢谢。

Instead of passing inProgress prop to TestComponent , you could maintain a local state in the TestComponent that is used to determine whether to show progress text or a button and only pass the id and onClickHanlder props to TestComponent .您可以在TestComponent中维护一个本地 state ,而不是将inProgress道具传递给TestComponent ,用于确定是显示进度文本还是按钮,并且只将idonClickHanlder道具传递给TestComponent

When button is clicked in TestComponent , you could set the the local state of TestComponent to show the progress text and then call the onClickHandler function passed as prop, passing in the id prop and a callback function as arguments. When button is clicked in TestComponent , you could set the the local state of TestComponent to show the progress text and then call the onClickHandler function passed as prop, passing in the id prop and a callback function as arguments. This callback function will be called when API request is completed.当 API 请求完成时,将调用此回调 function。 This callback function is defined inside TestComponent and only toggles the local state of the TestComponent to hide the progress text and show the button again.此回调 function 在TestComponent内部定义,仅切换TestComponent的本地 state 以隐藏进度文本并再次显示按钮。

Change your TestComponent to as shown below:将您的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>
  );
};

i have used useState hook to maintain local state of the TestComponent as it is a functional component but you could use the same logic in a class component as well.我使用useState挂钩来维护TestComponent的本地 state,因为它是一个功能组件,但您也可以在 class 组件中使用相同的逻辑。

Change the TestComponent in sampleData array to only be passed two props, id and onClickHandler .sampleData数组中的TestComponent更改为仅传递两个道具, idonClickHandler

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

and change onClickHandler method in App component to:并将App组件中的onClickHandler方法更改为:

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

Demo演示

编辑 crazy-fire-fvlhm

Alternatively, you could make onClickHandler function in App component to return a Promise that is fulfilled when API request completes.或者,您可以在App组件中创建onClickHandler function 以返回Promise ,该 API 请求完成时已完成。 This way you don't have to pass a callback function from TestComponent to onClickHandler method in App component.这样您就不必将回调 function 从TestComponent传递给App组件中的onClickHandler方法。

Change onClickHandler method to: onClickHandler方法更改为:

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

and change TestComponent to:并将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>
  );
};

Demo演示

编辑实用-sinoussi-r92qj

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM