I'm creating 2 pages (Summary and Cycles pages) using react.js
.
On the Summary page, there is a column named CN
that every item links to the Cycles page.
Summary page has a path /route/summary/location=abc
and Cycles page has a path /route/cycle/location=abc/deviceId=4410
For example, if I click the value from CN
column in the first row of the table inside the Summary page, I will be redirected to the Cycles page with the path /route/cycle/location=abc/deviceId=4410
.
In the Summary page, I use https://github.com/react-bootstrap-table/react-bootstrap-table2 for the table component and I use a columnRenderer
function inside columns.js
to render a custom item inside the table like this one:
How can I put the pathname
(example "abc") to a Link component inside cnColumnRenderer
function in columns.js
?
Summary page with the path: /route/summary/location=abc
Cycles page with the path: /route/cycle/location=abc/deviceId=4410
Error because of invalid hook call while rendering the Summary page
table code inside Summary page (inside Summary.js):
hint: focus on columns
variable from './columns' and its implementation
import React from "react"
import { useLocation } from "react-router-dom"
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory, {
PaginationProvider,
PaginationListStandalone
} from 'react-bootstrap-table2-paginator';
import ToolkitProvider, { Search } from 'react-bootstrap-table2-toolkit';
import columns from './columns'
const Summary = () => {
const location = useLocation()
const locationName = location['pathname'].replace('/route/summary/location=', '')
// console.log('Summary, location:', locationName)
// example: location = "/route/summary/location=abc" and locationName = "abc"
// ...some code here...
return (
<React.Fragment>
<div className="container-fluid ppa-route-summary-root">
<Row>
<Col className="col-12">
{/* ...some code here... */}
{/* TABLE CARD */}
<Card>
<CardBody>
<PaginationProvider
pagination={paginationFactory(paginationOptions)}
keyField='id'
columns={columns}
data={tableData}
>
{
({ paginationProps, paginationTableProps }) => (
<ToolkitProvider
keyField='id'
columns={columns}
data={tableData}
search
>
{
toolkitProps => (
<React.Fragment>
{/* ...some code here... */}
{/* TABLE ITSELF */}
<Row>
<Col xl="12">
<div className="table-responsive">
{
isTableLoading ?
<ReactLoading
type={'spin'}
color={'crimson'}
height={'5rem'}
width={'5rem'}
className='table-loading'
/> :
<BootstrapTable
keyField={"id"}
responsive
bordered={false}
striped={false}
// defaultSorted={defaultSorted}
// selectRow={selectRow}
classes={
"table align-middle table-nowrap"
}
headerWrapperClasses={"thead-light"}
{...toolkitProps.baseProps}
{...paginationTableProps}
/>
}
</div>
</Col>
</Row>
{/* ...some code here... */}
</React.Fragment>
)
}
</ToolkitProvider>
)
}
</PaginationProvider>
</CardBody>
</Card>
</Col>
</Row>
</div>
</React.Fragment>
)
}
export default Summary
columns.js:
import React from 'react'
import { Link, useLocation } from 'react-router-dom'
// IMAGES
import IconLocation from '../../../images/icons/location.svg'
const cnColumnRenderer = (cell, row, rowIndex, formatExtraData) => {
// console.log('columns, cnColumnRenderer:', cell, row, rowIndex, formatExtraData)
const deviceVersion = cell.split('-')[1] // example: deviceVersion = "4410"
const location = useLocation()
// console.log('Summary columns, location:', location['pathname'])
// here is the pathname I wanted: "/route/cycle/location=abc" so I can take the "location" path value as below:
const locationName = location['pathname'].replace('/route/summary/location=', '') // the result is locationName = "abc"
// then put the locationName inside the Link component
return(
<div className='route-summary-cn'>
<img src={IconLocation} alt='' className='icon-location'/>
{/* below is the pathname I wanted: "/route/cycle/location=abc/deviceId=4410" */}
<Link to={`/route/summary/location=${locationName}/deviceId=${row['deviceId']}`}>
{deviceVersion}
</Link>
</div>
)
}
const columns = [
{
dataField: 'deviceName',
text: 'CN',
formatter: cnColumnRenderer,
sort: true
},
{
dataField: 'convertedTotalCycle',
text: 'Cycle',
sort: true,
},
// ...some code here...
]
export default columns
Note: let me know if the question is confusing. I will try to update it.
React hooks are only valid in React functional components, not in any callbacks, loops, conditional blocks. If you need the location data in the callback it needs to be passed in.
From what I can tell it seems you need to move the columns.js
code into the main component so the location
values can be closed over in scope.
const Summary = () => {
const location = useLocation();
const locationName = location['pathname'].replace('/route/summary/location=', '')
// example: location = "/route/summary/location=abc" and locationName = "abc"
// ...some code here...
const cnColumnRenderer = (cell, row, rowIndex, formatExtraData) => {
// console.log('columns, cnColumnRenderer:', cell, row, rowIndex, formatExtraData)
const deviceVersion = cell.split('-')[1] // example: deviceVersion = "4410"
// then put the locationName inside the Link component
return(
<div className='route-summary-cn'>
<img src={IconLocation} alt='' className='icon-location'/>
{/* below is the pathname I wanted: "/route/cycle/location=abc/deviceId=4410" */}
<Link to={`/route/summary/location=${locationName}/deviceId=${row['deviceId']}`}>
{deviceVersion}
</Link>
</div>
);
};
const columns = [
{
dataField: 'deviceName',
text: 'CN',
formatter: cnColumnRenderer,
sort: true
},
{
dataField: 'convertedTotalCycle',
text: 'Cycle',
sort: true,
},
// ...some code here...
];
return (
...
);