【问题标题】:React open pop up from react-table从反应表反应打开弹出窗口
【发布时间】:2021-06-10 13:39:49
【问题描述】:

我正在使用 react.js 构建一个应用程序,它有一个使用 react table library 构建的表。

在此表中,我希望有一个按钮(或其他任何东西)可以打开一个显示 png 的弹出窗口。 png 由单元格内容决定,因此在所有弹出窗口中可能相同也可能不同。

看来我需要使用一个非常简单的模式,所以我决定使用react bootstrap library 构建它,如下所示

import React, { useState } from "react";
import Modal from 'react-bootstrap/Modal';
import Button from 'react-bootstrap/Button';

const PopUp = ({ link }) => {
  const [show, setShow] = useState(false);

  const handleClose = () => setShow(false);
  const handleShow = () => setShow(true);

  return (
    <>
      <Button variant="primary" onClick={handleShow} size="sm">
        Pathway
      </Button>

      <Modal
        show={show}
        onHide={handleClose}
        dialogClassName={'IMG_path'}
        size="lg"
      >
        <Modal.Header closeButton>
          <Modal.Title>IMG title</Modal.Title>
        </Modal.Header>
        <Modal.Body closeButton>
          <img src={"./img/" + link}
               id="id"
               alt="description"
               className="img-fluid"/>
        </Modal.Body>
      </Modal>
    </>
  );
};

export default PopUp;

然后我在反应表旁边测试了它,我的意思是在同一个 div 中,它工作得非常好。

然后我使用以下代码添加到表中

import React from "react";
import { useTable, usePagination, useSortBy } from 'react-table';

import PopUp from "./PopUp";

const MakePopup = ({ values }) =>  values && <PopUp link={values} /> ;

function Table({ columns, data }) {
  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    prepareRow,
    page, 
    canPreviousPage,
    canNextPage,
    pageOptions,
    pageCount,
    gotoPage,
    nextPage,
    previousPage,
    setPageSize,
    state: { pageIndex, pageSize },
  } = useTable(
    {
      columns,
      data,
      autoResetPage: true,
      initialState: { pageIndex: 0 },
    },
    // hook for sorting
    useSortBy,
    // hook for pagination
    usePagination
  )

  return (
    <>
      <table {...getTableProps()} className={"table table-striped table-bordered table-hover"}>
        <thead>
          {headerGroups.map(headerGroup => (
            <tr {...headerGroup.getHeaderGroupProps()}>
              {headerGroup.headers.map(column => (
                // Add the sorting props to control sorting. For this example
                // we can add them into the header props
                <th {...column.getHeaderProps(column.getSortByToggleProps())} scope={"col"}>
                  {column.render('Header')}
                  <span>
                    {column.isSorted
                      ? column.isSortedDesc
                        ? ' ????'
                        : ' ????'
                      : ''}
                  </span>
                </th>
              ))}
            </tr>
          ))}
        </thead>
        <tbody {...getTableBodyProps()}>
          {page.map((row, i) => {
            prepareRow(row)
            return (
              <tr {...row.getRowProps()}>
                {row.cells.map(cell => {
                  return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
                })}
              </tr>
            )
          })}
        </tbody>
      </table>
      {/*
        Pagination can be built however you'd like.
        This is just a very basic UI implementation:
      */}
      <div className="pagination">
        <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>{' '}
        <button onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
          {'<<'}
        </button>{' '}
        <button onClick={() => previousPage()} disabled={!canPreviousPage}>
          {'<'}
        </button>{' '}
        <span className='page-of'>
          Page{' '}
          <strong>
            {pageIndex + 1} of {pageOptions.length}
          </strong>{' '}
        </span>
        <button onClick={() => nextPage()} disabled={!canNextPage}>
          {'>'}
        </button>{' '}
        <button onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}>
          {'>>'}
        </button>
      </div>
    </>
  )
}

function MyTable(props) {
  const columns = [
    {
      Header: 'AA',
      accessor: 'AA',
    },
    {
      Header: 'BB',
      accessor: 'BB',
      sortType: "basic"
    },
    ...
    ...
    ...
    {
      Header: 'Img',
      accessor: 'url',
      sortType: "basic",
      disableSortBy: true,
      Cell: ({ cell: {value} }) => <MakePopup values={value} />
    }
  ];

  const data = props.tableData;

  return (
      <Table columns={columns} data={data} />
  )
}

现在单元格具有调用模式的按钮,但它从未出现:(

在这里搜索我发现thisthis other 答案表明模态应该在表格之外而不是每个单元格内的按钮旁边,所以我将代码修改为这个

import React, { useState } from "react";
import { useTable, usePagination, useSortBy } from 'react-table';
import Modal from 'react-bootstrap/Modal';
import Button from 'react-bootstrap/Button';

// PopUp 
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const [link, setLink] = useState('.png');

const handleClick = ( link ) => {
  setShow(true);
  setLink(link);
};

function Table({ columns, data }) {

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    prepareRow,
    page, 
    canPreviousPage,
    canNextPage,
    pageOptions,
    pageCount,
    gotoPage,
    nextPage,
    previousPage,
    setPageSize,
    state: { pageIndex, pageSize },
  } = useTable(
    {
      columns,
      data,
      autoResetPage: true,
      initialState: { pageIndex: 0 },
    },
    // hook for sorting
    useSortBy,
    // hook for pagination
    usePagination
  )

  return (
    <>
      <table {...getTableProps()} className={"table table-striped table-bordered table-hover"}>
        <thead>
          {headerGroups.map(headerGroup => (
            <tr {...headerGroup.getHeaderGroupProps()}>
              {headerGroup.headers.map(column => (
                // Add the sorting props to control sorting. For this example
                // we can add them into the header props
                <th {...column.getHeaderProps(column.getSortByToggleProps())} scope={"col"}>
                  {column.render('Header')}
                  {/* Add a sort direction indicator */}
                  <span>
                    {column.isSorted
                      ? column.isSortedDesc
                        ? ' ????'
                        : ' ????'
                      : ''}
                  </span>
                </th>
              ))}
            </tr>
          ))}
        </thead>
        <tbody {...getTableBodyProps()}>
          {page.map((row, i) => {
            prepareRow(row)
            return (
              <tr {...row.getRowProps()}>
                {row.cells.map(cell => {
                  return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
                })}
              </tr>
            )
          })}
        </tbody>
      </table>
      {/*
        Pagination can be built however you'd like.
        This is just a very basic UI implementation:
      */}
      <div className="pagination">
        <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>{' '}
        <button onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
          {'<<'}
        </button>{' '}
        <button onClick={() => previousPage()} disabled={!canPreviousPage}>
          {'<'}
        </button>{' '}
        <span className='page-of'>
          Page{' '}
          <strong>
            {pageIndex + 1} of {pageOptions.length}
          </strong>{' '}
        </span>
        <button onClick={() => nextPage()} disabled={!canNextPage}>
          {'>'}
        </button>{' '}
        <button onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}>
          {'>>'}
        </button>
      </div>
    </>
  )
}

function MyTable(props) {
  const columns = [
    {
      Header: 'AA',
      accessor: 'AA',
    },
    {
      Header: 'BB',
      accessor: 'BB',
      sortType: "basic"
    },
    ...
    ...
    ...
    {
      Header: 'Img',
      accessor: 'url',
      sortType: "basic",
      disableSortBy: true,
      Cell: ({ cell: { png } }) => png && (
        <Button
          variant="primary"
          onClick={ () => handleClick(png) }
          size="sm"
        >
          Pathway
        </Button>
      )
    }
  ];

  const data = props.genesData;

  return (
    <>
      <Table columns={columns} data={data} />
      <Modal
        show={show}
        onHide={handleClose}
        dialogClassName={'IMG_path'}
        size="lg"
      >
        <Modal.Header closeButton>
          <Modal.Title>IMG title</Modal.Title>
        </Modal.Header>
        <Modal.Body closeButton>
          <img src={"./img/" + link}
               id="id"
               alt="description"
               className="img-fluid"/>
        </Modal.Body>
      </Modal>
    </>
  )
}

export default MyTable;

现在我收到以下编译错误,应用程序无法启动

错误:无效的挂钩调用。钩子只能在体内调用 的一个功能组件。这可能发生在以下情况之一 原因:

  1. 您可能有不匹配的 React 版本和渲染器(例如 React DOM)
  2. 您可能违反了 Hooks 规则
  3. 您可能在同一个应用程序中拥有多个 React 副本 请参阅 react-invalid-hook-call 以获取有关如何调试和 解决这个问题。

指向这部分代码

   4 | import Button from 'react-bootstrap/Button';
   5 | 
   6 | // PopUp states
>  7 | const [show, setShow] = useState(false);
   8 | const handleClose = () => setShow(false);
   9 | // const handleShow = () => setShow(true);
  10 | const [link, setLink] = useState('.png');

现在我不确定如何解决这个问题。我一直在考虑使用redux之类的状态管理库,但我认为它不会解决问题。我正在使用 bootstrap 中的模态,但我会使用它本来的样子,因为我认为模态对于我需要的功能可能有点多。

谢谢

===========================

根据答案编辑

按照@Afzal Zubair 的建议,我将函数内的钩子移动如下:

import React, { useState } from "react";
import { useTable, usePagination, useSortBy } from 'react-table';
import Modal from 'react-bootstrap/Modal';
import Button from 'react-bootstrap/Button';

function Table({ columns, data }) {

  // PopUp states
  const [show, setShow] = useState(false);
  const handleClose = () => setShow(false);
  // const handleShow = () => setShow(true);
  const [link, setLink] = useState('.png');

  const handleClick = ( link ) => {
    setShow(true);
    setLink(link);
  };

  const {
    getTableProps,
    getTableBodyProps,
  ...
  ...
  ...
  ...
  return (
    <>
      <Table columns={columns} data={data} />
      <Modal
        show={show}
        onHide={handleClose}
        dialogClassName={'IMG_path'}
        size="lg"
      >
        <Modal.Header closeButton>
          <Modal.Title>KEGG pathway</Modal.Title>
        </Modal.Header>
        <Modal.Body closeButton>
          <img src={"./img/" + link}
               alt="plant-pathogen_interaction"
               className="img-fluid"/>
        </Modal.Body>
      </Modal>
    </>
  )
}

现在我得到一个不同的编译错误

编译失败。

./src/components/table/ReactTable_PopUp.jsx 第 193:27 行: 'handleClick' 未定义 no-undef Line 208:15: 'show' is not 已定义 no-undef 第 209:17 行:未定义“handleClose” no-undef 第 217:32 行:“链接”未定义 no-undef

搜索关键字以了解有关每个错误的更多信息。

参考以下代码

 190     Cell: ({ cell: { png } }) => png && (
 191       <Button
 192         variant="primary"
 193         onClick={ () => handleClick(png) }
 194         size="sm"
 195       >
 196         Pathway
 197       </Button>
 198     )

 204  return (
 205    <>
 206      <Table columns={columns} data={data} />
 207      <Modal
 208        show={show}
 209        onHide={handleClose}

 216        <Modal.Body closeButton>
 217          <img src={"./img/" + link}
 218               alt="plant-pathogen_interaction"
 219               className="img-fluid"/>
 220        </Modal.Body>

谢谢

================================================ ======================

已解决

@Afzal Zubair 是对的,钩子需要移动到函数元素,函数 MyTable 在我的代码中

function MyTable(props) {

  // PopUp states
  const [show, setShow] = useState(false);
  const handleClose = () => setShow(false);
  const [link, setLink] = useState('.png');

  const handleClick = ( link ) => {
    setShow(true);
    setLink(link);
  };  

  const columns = [
    {
      Header: 'AA',
      accessor: 'AA',
    },
    {
      Header: 'BB',
      accessor: 'BB',
      sortType: "basic"
    },
    ...
    ...

现在可以了!

【问题讨论】:

    标签: javascript reactjs popup bootstrap-modal react-table


    【解决方案1】:

    您似乎在 react 组件之外使用了 useState 挂钩。

       4 | import Button from 'react-bootstrap/Button';
       5 | 
       6 | // PopUp states
    >  7 | const [show, setShow] = useState(false);
       8 | const handleClose = () => setShow(false);
       9 | // const handleShow = () => setShow(true);
      10 | const [link, setLink] = useState('.png');
    

    你应该在 Table 组件之外使用 modal,但是你不能在 react 组件之外使用 react hooks。

    我建议在反应组件中使用这些钩子,准确地说是功能组件。 您可以参考此文档以更好地理解,link

    【讨论】:

    • 你是对的!我不敢相信我犯了这个错误。我将状态移至函数并使用新错误更新了问题
    • @Alfonso 我很高兴我的回答很有帮助。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-06
    • 2020-06-16
    相关资源
    最近更新 更多