简体   繁体   English

使用带有 graphql 的反应钩子时,按钮元素中的 onClick 不会触发反应表中的重新渲染

[英]onClick in button element not triggering re-render in react-table when using react hooks with graphql

I'm trying to render a table using react-table, however, this table has different states that are being pulled from a GraphQL database.我正在尝试使用 react-table 呈现表,但是,该表具有从 GraphQL 数据库中提取的不同状态。 Each button should effectively render the same UI for the table, but only display the shipments that have the correct status associated with what button the user clicked.每个按钮都应该有效地为表格呈现相同的 UI,但只显示与用户单击的按钮相关联的正确状态的货件。

My shipments query is as follows:我的货件查询如下:

import { gql } from 'apollo-boost';

export const GET_SHIPMENTS = gql`
      {
        shipments {
          created_at
          id
          status
          orders {
            order_items
          }
        }
      }
    `;

My table component using the GET_SHIPMENTS query looks like this:我使用GET_SHIPMENTS查询的表组件如下所示:

import React, { useState } from "react";
import { graphql } from 'react-apollo';
import { GET_SHIPMENTS } from '../graphql/ShipmentQueries';
import ReactTable from 'react-table';

import {
  Card,
  CardBody,
  Row,
  ButtonGroup,
  Button
} from "reactstrap";

function OrderTable ({ loading, shipments }) {
  const [shownShipment, setShownShipment] = useState({status: "created"});

  const columns = [
    {
      Header: 'ID',
      accessor: 'id',
    },
    {
      Header: 'Status',
      accessor: 'status',
    },
    {
      Header: 'Item Count',
      accessor: 'orders[0].order_items'
    },
    {
      Header: 'Time Stamp',
      accessor: 'created_at',
    },
  ];

if (loading) return <p>Loading...</p>;
    return (
        <div className="content">
            <ButtonGroup className="center">
                <Button 
                  name="created" 
                  onClick={() => setShownShipment(shownShipment.status === "created")}
                >
                  Created
                </Button>

                <Button 
                  name="awaiting driver" 
                  onClick={() => setShownShipment(shownShipment.status === "awaiting_driver")}
                >
                  Awaiting Driver
                </Button>

                <Button 
                  name="delivered" 
                  onClick={() => setShownShipment(shownShipment.status === "delivered")}
                >
                  Delivered
                </Button>
            </ButtonGroup>
          <Row className="mt-5">
              <Card>
                <CardBody>
                  <ReactTable
                    data={shipments}
                    columns={columns}
                    sortable={true}
                    resizable={false}
                    minRows={10}
                  />
                </CardBody>
              </Card>
          </Row>
        </div>
    );
  }

  export const OrderTableWithData = graphql(GET_SHIPMENTS, {
    props: ({data: { loading, shipments, shownShipments }}) => ({
      loading,
      shipments,
      shownShipments,
    }),
  })(OrderTable);

This is my first introduction into using hooks, so I know that I'm probably not utilizing them properly.这是我第一次介绍使用钩子,所以我知道我可能没有正确使用它们。 I'm not sure if I have to use the useEffect hook or not.我不确定是否必须使用useEffect挂钩。 I've scoured the Hooks docs and can't seem to find a clear answer.我已经搜索了 Hooks 文档,但似乎找不到明确的答案。 I feel like useState should work.我觉得useState应该可以工作。 Do I have to re-render the entire ReactTable element?我是否必须重新渲染整个 ReactTable 元素?

If you want shownShipment.status to be the string corresponding to the delivery status (such as 'delivered', 'awaiting_driver') etc, your buttonClick code should look like this:如果您希望 shownShipment.status 是与交付状态相对应的字符串(例如 'delivered'、'awaiting_driver')等,您的 buttonClick 代码应如下所示:

onClick={() => setShownShipment({status: "delivered"}) }

Try adding an effect to the react component like this to see the status updating after you click each button:尝试像这样向 react 组件添加效果,以查看单击每个按钮后的状态更新:

useEffect(() => { console.log(shownShipment); }, [shownShipment]);

Now that you have shownShipment set to the desired status, you can filter your total list of shipments from GQL based on this.现在您已将显示的发货设置为所需的状态,您可以根据此过滤来自 GQL 的发货总列表。 UseState again for the list of shipments you will actually give to your table. UseState 再次获取您将实际提供给您的餐桌的货物清单。 useEffect will be helpful here as well. useEffect 在这里也会有所帮助。 Something like this:像这样的东西:

// at the top of the component
var [shipmentsToDisplay, setShipmentsToDisplay] = useState([]);

useEffect(() => {
    // loop through all shipments and create a new array for only the ones 
    // you want to show.
    const filteredShipments = 
        shipments && 
            shipments.map(shipment => {
                if (shipment.status === shownShipment) {
                    return shipment;
                }
            }

    setShipmentsToDisplay(filteredShipments);
}, [shownShipment, shipments]);


// Render your table with these shipments rather than props.shipments
<ReactTable
    data={shipmentsToDisplay}
    columns={columns}
    sortable={true}
    resizable={false}
    minRows={10}       
/>

The solution for this code was as follows: (Some code removed for brevity)此代码的解决方案如下:(为简洁起见,删除了一些代码)

function OrderTable ({ loading, shipments }) {
  const [shipmentsToDisplay, setShipmentsToDisplay] = useState([]);

  useEffect(() => {
    if(shipments) {
      filterShipments("created");
    }
  }, [shipments]);

  function filterShipments(status) {
    let shownShipments = [];
    shipments.forEach(element => {
      if(element.status === status) {
        shownShipments.push(element);
      }
    });
    setShipmentsToDisplay(shownShipments);
  }

if (loading) return <Loading />;
    return (
        <div className="content">
            <ButtonGroup className="center">
                <Button name="pending" onClick={() => filterShipments("created")}>
                  Pending
                </Button>
                <Button name="ready" onClick={() => filterShipments("awaiting_driver")}>
                  Ready
                </Button>
                <Button name="completed" onClick={() => filterShipments("delivered")}>
                  Completed
                </Button>
            </ButtonGroup>
          <Row className="mt-5">
            <ReactTable
              data={shipmentsToDisplay}
              columns={columns}
              sortable={true}
              resizable={false}
              defaultPageSize={5}
              className="-striped -highlight"
              getTrProps={getTrProps}
              SubComponent={row => {
                return (
                  <ShipmentDetails
                    shipments={shipments}
                  />
                )
              }}
            />
          </Row>
        </div>
    );
  }

  export const OrderTableWithData = graphql(GET_SHIPMENTS, {
    props: ({data: { loading, shipments }}) => ({
      loading,
      shipments
    }),
  })(OrderTable);

The solution was to land on the Pending shipments, so for my state, I used the useEffect hook to land on the shipments that have created as a status.解决方案是登陆Pending shipping,因此对于我的 state,我使用useEffect挂钩登陆已created为状态的货物。

For my onClick function, I decided to filter through each shipment starting with the created shipments and update the state based on which status is associated with the button click.对于我的 onClick function,我决定从created的货件开始过滤每个货件,并根据与按钮单击关联的状态更新 state。 I don't know if that makes sense or not.我不知道这是否有意义。 I'm new to hooks and GraphQL.我是钩子和 GraphQL 的新手。

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

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