I'm running into an issue with setState and I'm not exactly sure what I'm doing incorrectly.
I'll provide the full code below.
I start off with a function class to call my API to pull data from the database, then pass this to my Applicants Class. The Applicants Class is a datatable with the far right column being an edit button to bring a modal popup which will include a form to update any applicants in my table. (image below)
As you can see from my imports, I'm using ReactTable v7.7, so I'm able to set custom headers in my datatable. I'm trying to add a button that calls my classes ToggleModal function. This will set the modalDisplayBool to true (so the modal is visible) and then pass in that rows data. When the Modal is visible, I have a button to close it which calls the same ToggleModal function to hide the modal and reset the rows data.
My Modal 'X' button to close the modal works perfectly fine. It is the 'Edit' button in my Header that doesn't seem to work. When I click this, I receive the following error in my console:
Warning: Can't call setState on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to 'this.state' directly or define a 'state = {};' class property with the desired state in the Applicants component.
PS. I've also tried binding the class function in the constructor and binding in the onClick, but this doesn't change anything that I can see. Additionally, since I'm using React v17, it's not advised to use ComponentDidMount or any of the sort as they are antipatterns. However, I will note that I tried using the SAFE_ version, and this still didn't change my out come.
import React from 'react'
import { useApi, handleHttpServiceCallback } from '../common/services/HttpServices'
import { ReactTableBasicApplicantsPage } from '../common/datatable/ReactTable'
import Modal from '../common/modal/Modal'
import Button from '@material-ui/core/Button'
export default function ApplicantsPage() {
const url = '/users/applicants'
const { data, isLoading, hasError, httpStatus, redirectURL } = useApi(url, {initialLoad: true}, { credentials: 'include' })
var responseFromCallback = handleHttpServiceCallback(data, isLoading, hasError, httpStatus, redirectURL)
if(responseFromCallback)
return responseFromCallback
return (
<Applicants data={data}/>
)
}
class Applicants extends React.Component {
constructor(props) {
super(props)
this.state = {
modalDisplayBool: true, // Will be false initially, but I can't get this value to be true when clicking the 'Edit' button, so setting it to true for now to test
selectedRowData: {},
data: props.data
}
const headerCol = {
Header: () => null, // No header
id: 'edit_applicant',
sortable: false,
filterable: false,
Cell: ({ row }) => (
<span>
<Button variant="outlined" color="primary" onClick={() => this.toggleModal(row.original)}> // This Doesn't Work
Edit
</Button>
</span>
)
}
const headerFound = this.state.data.column.some(x => x.id === headerCol.id)
if(!headerFound)
this.state.data.column.push(headerCol)
}
toggleModal = (selectedRowData) => {
this.setState({
modalDisplayBool: !this.state.modalDisplayBool,
selectedRowData
})
}
render() {
return (
<>
<h1>Applicants Page</h1>
<ReactTableBasicApplicantsPage columns={this.state.data.column} dataIn={this.state.data.data}/>
<Modal show={this.state.modalDisplayBool}>
<div className="ttp-modal-main">
<div className="ttp-modal-header">
<h1>Modal Header</h1>
<button
type="button"
className="btn btn-danger"
onClick={() =>this.toggleModal({})} // This Works
>
<span aria-hidden="true">×</span>
</button>
</div>
<section className="ttp-modal-content">
<p>This is the main content of the modal</p>
</section>
<section className="ttp-modal-footer">
<div>Footer area</div>
</section>
</div>
</Modal>
</>
)
}
}
With help from @vishnu-shekhawat, I fixed my issue.
As mentioned in their comment, I simply moved my headerCol
variable into my classes render
. See code below
class Applicants extends React.Component {
constructor(props) {
super(props)
this.state = {
modalDisplayBool: true,
selectedRowData: {},
data: props.data
}
}
toggleModal = (selectedRowData) => {
this.setState({
modalDisplayBool: !this.state.modalDisplayBool,
selectedRowData
})
}
render() {
// vvvv Moving this here fixed my issue
const headerCol = {
Header: () => null, // No header
id: 'edit_applicant',
sortable: false,
filterable: false,
Cell: ({ row }) => (
<span>
<Button variant="outlined" color="primary" onClick={() => this.toggleModal(row.original)}>
Edit
</Button>
</span>
)
}
const headerFound = this.state.data.column.some(x => x.id === headerCol.id)
if(!headerFound)
this.state.data.column.push(headerCol)
return (
<>
<h1>Applicants Page</h1>
<ReactTableBasicApplicantsPage columns={this.state.data.column} dataIn={this.state.data.data} />
<Modal show={this.state.modalDisplayBool}>
<div className="ttp-modal-main">
<div className="ttp-modal-header">
<h1>Modal Header</h1>
<button
type="button"
className="btn btn-danger"
onClick={() =>this.toggleModal({})}
>
<span aria-hidden="true">×</span>
</button>
</div>
<section className="ttp-modal-content">
<p>This is the main content of the modal</p>
</section>
<section className="ttp-modal-footer">
<div>Footer area</div>
</section>
</div>
</Modal>
</>
)
}
}