【发布时间】: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} />
)
}
现在单元格具有调用模式的按钮,但它从未出现:(
在这里搜索我发现this 和this 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;
现在我收到以下编译错误,应用程序无法启动
错误:无效的挂钩调用。钩子只能在体内调用 的一个功能组件。这可能发生在以下情况之一 原因:
- 您可能有不匹配的 React 版本和渲染器(例如 React DOM)
- 您可能违反了 Hooks 规则
- 您可能在同一个应用程序中拥有多个 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