I am having some trouble with the React useState.
I have a modal that I popup based on a form submit. Prior to the modal being loaded the application calls an api which returns some data that is then displayed within the modal in a table.
I have narrowed down the issue to what looks to be a problem with my code useState of the ingredients array this line:
const [editTableData, setEditTableData] = useState(updatedIngredients)
My plan is to use this state in my modal to make the ingredient list editable however I removed this from the code that that I could troubleshoot the issues I am facing with just initially setting the state and resetting the state.
My issue is around Resetting State and from what I have read I have tried a couple of approaches.
-
Resetting modal state with a key. I tried adding this line to the modal setting the key to a unique guid that is generated but this did not work:
<Modal key={uuidv4()} show={show} onHide={closeModal} size="xl">
-
onHide or close or Submit of the modal set the state (setEditTableData) to all null values
const initialState = { name: null, quantity: null, unit:null, ingredientId: null }
const closeModal = () => {
handleClose(true)
setEditTableData({
...initialState,
});
}
This works to reset the state to all null which fixes an issue I had earlier where the state would display the previous recipes ingredients. However whenever I reload the modal now after first load the editTableData state is returns as empty and does not get reset with the new updatedIngredients
Full Code:
import { Form, Modal, Button, Table } from "react-bootstrap"
import { parseIngredient, parseInstruction } from '@jlucaspains/sharp-recipe-parser';
import axios from "axios";
import { v4 as uuidv4 } from "uuid"
import { useState } from "react"
export default function AddRecipeModal( { show, handleClose, modalTitle, modalImage, modalIngredients, modalSteps }) {
// this parses out the name from the the modalIngredients and returns a new array called updatedIngredients
const updatedIngredients = modalIngredients.map((modalIngredient) => {
const parsedIngredient = parseIngredient(modalIngredient.raw, 'en')
return { // <--- return a new object...
...modalIngredient, // <--- that has all the properties from modalIngredient...
// v--- with these properties overwritten
ingredientId: uuidv4(),
name: parsedIngredient.ingredient,
unit: parsedIngredient.unit,
quantity: parsedIngredient.quantity
}
});
console.log(updatedIngredients)
const [editTableData, setEditTableData] = useState(updatedIngredients)
console.log(editTableData)
// this handle submit is for the add button on the modal to call the backend api to create the recipe
const handleSubmit = async (e : any) => {
try {
// this prevents an auto refresh from happening
// e.preventDefault()
const resp = await axios.post("http://localhost:8000/recipe/add",
{ title: modalTitle,
ingredients: updatedIngredients,
steps: modalSteps,
image: modalImage
})
handleClose(true)
console.log(resp.data)
} catch (error : any) {
console.log(error.response)
}
}
//trying to reset the state of EditTableData when the modal is hidden or closed
const initialState = { name: null, quantity: null, unit:null, ingredientId: null }
const closeModal = () => {
handleClose(true)
setEditTableData({
...initialState,
});
}
return (
<Modal key={uuidv4()} show={show} onHide={closeModal} size="xl">
<Form onSubmit={handleSubmit}>
<Modal.Header closeButton>
<Modal.Title>
{modalTitle}
</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form.Group className="container">
<p><img src={modalImage} height="250px" /></p>
</Form.Group>
<Form.Group className="container">
<Form.Group className="container">
<Form.Label><strong>Recipe Ingrededients</strong></Form.Label>
<div className="app-container">
<Table striped bordered hover>
<thead>
<tr>
<th>Ingredient</th>
<th>Quantity</th>
<th>Unit</th>
</tr>
</thead>
<tbody>
{updatedIngredients.map(({ ingredientId, name, quantity, unit }) => (
<tr key={ingredientId}>
<td>{name}</td>
<td>{quantity}</td>
<td>{unit}</td>
</tr>
)
)}
</tbody>
</Table>
</div>
</Form.Group>
</Form.Group>
<Form.Group className="container">
<Form.Label><strong>Recipe Instructions</strong></Form.Label>
<div key={uuidv4()}>{modalSteps.map((modalStep) => {
// console.log(modalStep)
return(
<ul>{modalStep.raw}</ul>
)
})}</div>
</Form.Group>
<div className="d-flex justify-content-end" >
<Button variant="primary" type="submit">Add</Button>
</div>
</Modal.Body>
</Form>
</Modal>
)
}
Feel like I am just missing something small with this but it is driving me crazy.