简体   繁体   中英

React not re-rendering on change

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;

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.

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM