So I've been beating my head against a wall for a couple days now scouring through Google and questions on here. I've done quite a bit of changes to the code I've written and re-written. The problem I'm getting is that the POST request to the DB works fine. If I refresh the page, the new entry is there. Somewhere in my code, I know I'm not properly updating the state. From what I've gathered, an issue like mine happens when you're not passing a new array into state in order for a re-render to trigger.
At this point I'm lost, and any insight on to what I'm doing wrong would be appreciated.
Here's the code:
export default function Form () {
const [chatData, setChatData] = useState([{
chat: Number,
isConverted: Boolean,
}])
console.log(chatData)
const changeHandler = name => (e) => {
setChatData({...chatData, [name]: e.target.value})
}
const createChat = (e) => {
e.preventDefault()
const data = { ...chatData }
const postData = () => {
try {
axios.post("/api/create", data)
} catch (error) {
console.error(error)
}
}
postData()
}
return (
<div>
<Box sx={{maxWidth: 200}} display="flex" alignItems="center" justifyContent="center" margin="auto">
<form onSubmit={createChat}>
<FormControl fullWidth sx={{ m: 1, minWidth: 120 }}>
<InputLabel id="chat_number_label">Chat Number</InputLabel>
<Select
labelId="chat_number_label"
id="chat_input_select"
defaultValue=""
value={chatData.chat}
onChange={changeHandler("chat")}
name="chat">
<MenuItem value={1}>1</MenuItem>
<MenuItem value={2}>2</MenuItem>
<MenuItem value={3}>3</MenuItem>
<MenuItem value={4}>4</MenuItem>
<MenuItem value={5}>5</MenuItem>
<MenuItem value={6}>6</MenuItem>
<MenuItem value={7}>7</MenuItem>
<MenuItem value={8}>8</MenuItem>
<MenuItem value={9}>9</MenuItem>
<MenuItem value={10}>10</MenuItem>
</Select>
</FormControl>
<FormControl fullWidth sx={{ m: 1, minWidth: 120 }}>
<InputLabel id="is_converted_label">Converted to Ticket</InputLabel>
<Select
labelId="is_converted_label"
id="is_converted_select"
defaultValue=""
value={chatData.isConverted}
onChange={changeHandler("isConverted")}
name="isConverted">
<MenuItem value={true}>True</MenuItem>
<MenuItem value={false}>False</MenuItem>
</Select>
</FormControl>
<Button color="primary" variant="contained" type="submit" value="Submit">Submit</Button>
</form>
</Box>
</div>
)
}
EDIT: Per request, this is where all my chats are displayed on the page
export default function AllChats () {
const [chatList, setChatList] = useState([])
useEffect(() => {
const fetchAllChats = async () => {
try {
const res = await axios.get("/api")
setChatList(res.data)
} catch (error) {
console.error(error)
}
}
fetchAllChats()
}, [])
const headers = [
{
label: "Chat Number", key: "chat"
},
{
label: "Date", key: "createdAt"
},
{
label: "Converted into Ticket", key:"isConverted"
}
]
const csvLink = {
filename: "chat_data.csv",
headers: headers,
data: chatList
}
return (
<Container maxWidth="md">
<TableContainer component={Paper}>
<Table sx={{ minWidth: 650 }}>
<TableHead>
<TableRow>
<TableCell>Chats Number</TableCell>
<TableCell align="right">Date</TableCell>
<TableCell align="right">Converted into ticket</TableCell>
</TableRow>
</TableHead>
<TableBody>
{ chatList.map((val, _key) => {
return (
<TableRow key={val.chat}
sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
>
<TableCell omponent="th" scope="row">{val.chat}</TableCell>
<TableCell align="right">{val.createdAt}</TableCell>
<TableCell align="right"> {String(val.isConverted)} </TableCell>
</TableRow>
)})}
</TableBody>
</Table>
</TableContainer>
<CSVLink {...csvLink}>Export to CSV</CSVLink>
</Container>
)
}
Here's my App.js
function App() {
return (
<>
<AllChats />
<Form />
</>
);
}
export default App;
CodePudding user response:
You are initiating chatData State with an OBJECT, but with-in an array like this:
const [chatData, setChatData] = useState([{
chat: Number,
isConverted: Boolean,
}])
So when you are retrieving the chatData
, it is returning the array, not the object.
You need to remove the array while initiating it, and directly initiate it with an OBJECT like this:
const [chatData, setChatData] = useState({
chat: Number,
isConverted: Boolean,
})
It will solve the problem.
And if don't, then you can contact me through my profile.
CodePudding user response:
setChatList
is only called on first render in fetchAllChats
. Your chatList
is never being updated after the post
request in createChat
. You are updating your database but your frontend has no knowledge that your chats were updated. You need to update your chatList
with setChatList
upon a successful post
. For instance:
axios.post("/api/create", data).then(response => {
setChatList([...chatList, response.data]);
})
For the above to work, your backend should return the chat
in the response in the same format as in the get
request in fetchAllChats()
. Or the response could contain the entire updated chat list. If you don't have control over the backend, you could run fetchAllChats()
after a successful POST, but this might not be ideal as it is additional load in terms of network and database operations.
In either case, you would need access to functions from <AllChats />
like setChatList
in your <Form />
component, so you should lift state up to a common ancestor (<App />
in this case)