如何确保更新子组件的道具?

m4pnthwp  于 2022-10-15  发布在  React
关注(0)|答案(1)|浏览(158)

我对RTK查询有一个问题:我有一个封装表的第一个组件。当发生刷新时-例如,当我删除某些数据时-父组件接收数据并通过道具将其传递给子组件,但表永远不会更新。因此,删除的结果仍会显示在表格上。
什么是正确的“React/恢复”方法来生成表的刷新?
以下是一些代码:

const Results = (props) => {

    const router = useRouter()

    const { data, error, isError, isLoading, isFetching } = useGetItemsQuery();

    if(isLoading) {

        return ( 
            <>
                <Spinner animation="border"  size="sm" role="status" />{' '} Please wait while Loading...
            </>
        )
    }
    if(isError) {
        return (
            <>
                <Alert key="warning" variant="warning" style={{marginLeft: "10px"}}>
                        Warning - There was an error with the request :  {error.error}
                </Alert>
            </>
        )
    }

    const sizePerPageList = [
        {
            text: '5',
            value: 5,
        },
    ];

    if (data){

        return(
            <>
                <Card>
                    <Card.Body>
                        Traffic results
                        <TableResults data={data} sizePerPageList={sizePerPageList} />
                    </Card.Body>
                </Card>                
            </>
        )   
    }
}

export default Results;

对于表中的第二个组件:

const TableResults = (props) => {

    console.log('props - data ', props.data);

    const data = React.useMemo(
        () => props.data,
        []
      )

    const columns = React.useMemo(
        () => [
            {
                Header: 'bla bla',
                accessor: 'blabla', 
            }

        ],
        []
    )

    const IndeterminateCheckbox = React.forwardRef(
      ({ indeterminate, ...rest }, ref) => {
        const defaultRef = React.useRef()
        const resolvedRef = ref || defaultRef

        React.useEffect(() => {
          resolvedRef.current.indeterminate = indeterminate
        }, [resolvedRef, indeterminate])

        return (
          <>
            <input type="checkbox" ref={resolvedRef} {...rest} />
          </>
        )
      }
    )

    const {
        getTableProps,
        getTableBodyProps,
        headerGroups,
        page, // Instead of using 'rows', we'll use page,
        // which has only the rows for the active page

        // The rest of these things are super handy, too ;)
        canPreviousPage,
        canNextPage,
        pageOptions,
        pageCount,
        gotoPage,
        nextPage,
        previousPage,
        setPageSize,
        prepareRow,
        state: { pageIndex, pageSize, selectedRowIds },
        visibleColumns,
        preGlobalFilteredRows,
        setGlobalFilter,
        selectedFlatRows
      } = useTable({ columns, data }, useGlobalFilter, useFilters, useSortBy, usePagination, useRowSelect, 
      hooks => {
        hooks.visibleColumns.push(columns => [
          // Let's make a column for selection
          {
            id: 'selection',
            // The header can use the table's getToggleAllRowsSelectedProps method
            // to render a checkbox
            Header: ({ getToggleAllPageRowsSelectedProps }) => (
              <div>
                <IndeterminateCheckbox {...getToggleAllPageRowsSelectedProps()} />
              </div>
            ),
            // The cell can use the individual row's getToggleRowSelectedProps method
            // to the render a checkbox
            Cell: ({ row }) => (
              <div>
                <IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
              </div>
            ),
          },
          ...columns,
        ])
      } )

    return (
      <>
        <DeleteItemButton items={selectedFlatRows} />

        <BTable {...getTableProps()} striped bordered hover size="sm">
          <thead>
            {headerGroups.map(headerGroup => (
              <tr {...headerGroup.getHeaderGroupProps()}>
                {headerGroup.headers.map(column => (
                  <th
                    {...column.getHeaderProps(column.getSortByToggleProps())}
                  >
                    {column.render('Header')}
                  </th>
                ))}
              </tr>
            ))}
          </thead>
          <tbody {...getTableBodyProps()}>
            {page.map((row, i) => {
              prepareRow(row)
              return (
                <tr {...row.getRowProps()}>
                  {row.cells.map(cell => {
                    return (
                      <td
                        {...cell.getCellProps()}
                        style={{
                        //   padding: '10px',
                        //   border: 'solid 1px gray',
                        //   background: 'papayawhip',
                        }}
                      >
                        {cell.render('Cell')}
                      </td>
                    )
                  })}
                </tr>
              )
            })}
          </tbody>
        </BTable>
        <div className="pagination">
        <button onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
          {'<<'}
        </button>{' '}
        <button onClick={() => previousPage()} disabled={!canPreviousPage}>
          {'<'}
        </button>{' '}
        <button onClick={() => nextPage()} disabled={!canNextPage}>
          {'>'}
        </button>{' '}
        <button onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}>
          {'>>'}
        </button>{' '}
        <span>
          Page{' '}
          <strong>
            {pageIndex + 1} of {pageOptions.length}
          </strong>{' '}
        </span>
        <span>
          | Go to page:{' '}
          <input
            type="number"
            defaultValue={pageIndex + 1}
            onChange={e => {
              const page = e.target.value ? Number(e.target.value) - 1 : 0
              gotoPage(page)
            }}
            style={{ width: '100px' }}
          />
        </span>{' '}
        <select
          value={pageSize}
          onChange={e => {
            setPageSize(Number(e.target.value))
          }}
        >
          {[10, 20, 30, 40, 50].map(pageSize => (
            <option key={pageSize} value={pageSize}>
              Show {pageSize}
            </option>
          ))}
        </select>
      </div>
        </>
      )
}
export default TableResults;

DeleteItemButton将生成一个运行良好的简单RTK查询,并触发从主组件刷新数据:

deleteItems: builder.mutation({
        query(data) {

            // send array
            let sanitized;
            sanitized = keywords.filter(item => item);

            const data = {
                items: sanitized
            }
            //console.log('data: ', data);
          return {
            url: `items`,
            method: 'DELETE',
            body: data
          }
        },
        invalidatesTags: ['Items']
      }),

该应用程序在nextJS下运行。如有需要,敬请惠顾!
谢谢

ndh0cuux

ndh0cuux1#

什么是正确的“React/恢复”方法来生成表的刷新?
刷新数据的正确方法是使用RTK查询的providesTagsinvalidatesTags特性,您已经在这样做了。
您的表不刷新的原因是您显式地告诉它忽略对props.data的所有更改,并对所有后续呈现使用初始值。这显然不是你想要的,但这就是你在这里做的:

const data = React.useMemo(
        () => props.data,
        []
      )

具有空依赖项数组的useMemo将仅执行一次。一般来说,您在useMemo中使用的所有变量都应该作为依赖项包括在内。因此,依赖数组应该是[props.data]
当然,这个特定的useMemo不会“做任何事情”,可以安全地删除。如果您正在重新格式化props.data变量,并且只想在props.data的值更改时执行重新格式化,那么使用useMemo将是有意义的。

const data = React.useMemo(
   () => someExpensiveComputation(props.data),
   [props.data]
);

相关问题