sei-ec-remote / team-project-issues

0 stars 0 forks source link

useState is not setting the value immediately #148

Closed estebbins closed 1 year ago

estebbins commented 1 year ago

Describe the bug A clear and concise description of what the bug is. I am setting useState a the top of a function component and when console.logging the value I'm passing to use.State, it shows up perfectly, yet the state is not set

What is the problem you are trying to solve? I am trying to pass my label object as the state to the edit form

Expected behavior A clear and concise description of what you expected to happen. I expected that when I was able to clearly see the correct object one line above via console log and set useState, that it would immediately happen

What is the actual behavior? A clear and concise description of what actually happened. When it's working "the best" the state is one render behind.

Post any code you think might be relevant (one fenced block per file) Where updateLabel is successfully being passed down to EditLabelModal

import { Button } from 'react-bootstrap'
import EditLabelModal from './EditLabelModal'
import { useState, useEffect } from 'react'

const LabelsIndex = (props) => {
    const { msgAlert, user, labels, labelsError, triggerRefresh } = props

    const [editModalShow, setEditModalShow] = useState(false)
    const [updateLabel, setUpdateLabel] = useState({})

    // useEffect(()=>{console.log('updated label!!!!', updateLabel)}, [updateLabel])

    // console.log('labels: ', labels)

    if (labelsError) {
        return <p>Loading...</p>
    }
    // if no pets loaded yet, display 'loading'
    if (!labels) {
        return <p>Loading...</p>
        // otherwise if there are no pets, display that message
    } else if (labels.length === 0) {
        return <p>No files yet, go add some!</p>
    }

    const onClick = (e) => {
        console.log('labels index e value', e.target.value)
        setUpdateLabel(JSON.parse(e.target.value))
        console.log('!!!!!!UPDATELABEL', updateLabel)
        setEditModalShow(true)
    }

    const labelButtons = labels.map((label, i) => {
        // console.log('mapped labels', label)
        return (
            <>
                <Button 
                    className="m-2" 
                    style={{backgroundColor:`${label.color}`}}
                    key={label._id}
                    onClick={onClick}
                    value={JSON.stringify(label)}
                >{label.name}</Button>
                <EditLabelModal
                    key={i}
                    user={user}
                    editLabel={updateLabel}
                    msgAlert={msgAlert}
                    triggerRefresh={triggerRefresh}
                    show={editModalShow}
                    handleClose={() => setEditModalShow(false)}
                />
            </>
        )
})

    // return some jsx, a container with all the pet cards
    return (
        <>
            <div className="container-sm" >
                { labelButtons }
            </div>
        </>
    )
}

// export our component
export default LabelsIndex

EditLabelModal

import { useEffect, useState } from 'react'
import { Modal } from 'react-bootstrap'
import LabelForm from '../shared/LabelForm'
import { updateLabel } from '../../api/labels'
// import messages from '../shared/AutoDismissAlert/messages'

const EditLabelModal = (props) => {
    const { user, editLabel, show, handleClose, msgAlert, triggerRefresh } = props

    // console.log('props.label', props.label)
    const [label, setLabel] = useState(editLabel)
    console.log('basical props.label', editLabel)

    console.log('editcontmodal label', label)

    const onChange = (e) => {
        e.persist()

        setLabel(prevLabel => {
            const updatedName = e.target.name
            let updatedValue = e.target.value

            const updatedLabel = {
                [updatedName] : updatedValue
            }

            console.log('!!!!!!!!!!!!!the label', updatedLabel)
            console.log('!!!!!!!!!!!!!!the label (state)', label)

            return {
                ...prevLabel, ...updatedLabel
            }
        })
    }

    const onSubmit = (e) => {
        e.preventDefault()
        updateLabel(user, label)
            // close the modal
            .then(() => handleClose())
            // send a success message
            .then(() => {
                msgAlert({
                    heading: 'Hoist with someone elses petard!',
                    // !message: messages.updateLabelSuccess
                    message: 'Label successfully edited!',
                    variant: 'success'
                })
            })
            .then(() => triggerRefresh())
            // if there is an error, tell the user about it
            .catch(() => {
                msgAlert({
                    heading: 'Oh No! Hoisted by our petard!',
                    // !message: messages.updateLabelFailure
                    message: 'Label not edited',
                    variant: 'danger'
                })
            })
    }

    return (
    <Modal show={show} onHide={handleClose}>
        <Modal.Header closeButton />
        <Modal.Body>
            <LabelForm
                label={label}
                handleChange={onChange}
                handleSubmit={onSubmit}
                heading={'Edit Label'}
            />
        </Modal.Body>
    </Modal>
    )
}

export default EditLabelModal

LabelForm

import { Container, Form, Button } from 'react-bootstrap'

const LabelForm = (props) => {
    const { user, label, handleSubmit, handleChange, heading } = props
    console.log('labelform label', label)

    return (
        <Container className="justify-content-center">
            <h3>{heading}</h3>
            <Form onSubmit={handleSubmit}>
                <Form.Group className="m-2">
                    <Form.Label>Name:</Form.Label>
                    <Form.Control 
                        placeholder="What is the name of the label"
                        name="name"
                        id="name"
                        defaultValue={label.name}
                        onChange={handleChange}
                    />
                </Form.Group>
                <Form.Group className="m-2">
                    <Form.Label>Color:</Form.Label>
                    <Form.Control 
                        type="color"
                        name="color"
                        id="type"
                        defaultValue={label.color}
                        onChange={handleChange}
                    />
                </Form.Group>
                <Button type="submit" className="m-2">Submit</Button>
            </Form>
        </Container>
    )
}

export default LabelForm

What is your best guess as to the source of the problem? I really really can't understand

What things have you already tried to solve the problem? everything...every version of useEffect and combination of dependencies.

Additional context Add any other context about the problem here. I would love to get help early because we are behind where we planned to be!

Paste a link to your repository here

asands94 commented 1 year ago

Where are you getting labels from (I see it passed into props in your LabelIndex, but where LabelIndex being rendered)? Is it from your backend and you're trying to render labels on the front in the index page, then pass it to edit in order to update it?

estebbins commented 1 year ago
import { useState, useEffect } from 'react'
import { Button } from 'react-bootstrap'

import LabelsIndex from '../Labels/LabelsIndex'
import NewLabelModal from '../Labels/NewLabelModal'

const LabelsSidebar = (props) => {
    const { user, msgAlert, labels, triggerRefresh, labelsError } = props

    const [modalShow, setModalShow] = useState(false)

    return (
        <div className="container-sm">
            <LabelsIndex
                user={user}
                msgAlert={msgAlert}
                labels={labels}
                labelsError={labelsError}
                triggerRefresh={triggerRefresh}
            />
            <Button className="m-2" onClick={()=>setModalShow(true)}>Create New Label</Button>
            <NewLabelModal 
                user={user}
                show={modalShow}
                msgAlert={msgAlert}
                handleClose={()=>setModalShow(false)}
                triggerRefresh={triggerRefresh}
            />
        </div>
    )
}

export default LabelsSidebar
asands94 commented 1 year ago

What file is labels originally coming from?

estebbins commented 1 year ago

Sorry, they are from our home.js file which runs the API call to our backend. Everything with labels flowing fine until setState in EditLabelModal.

import { useState, useEffect } from 'react'
import Container from 'react-bootstrap/Container'
import Button from 'react-bootstrap/Button'
import Row from 'react-bootstrap/Row'
import Col from 'react-bootstrap/Col'
import FilesContainer from './shared/FilesContainer.js'
import LabelsSidebar from './shared/LabelsSidebar'
import { getAllFiles } from '../api/files'
import { getAllLabels } from '../api/labels'
import NewFileModal from './files/NewFileModal'

import messages from '../components/shared/AutoDismissAlert/messages'

const Home = (props) => {
    console.log('props in home', props)

    const { msgAlert, user } = props

    const [files, setFiles] = useState(null)
    const [filesError, setFilesError] = useState(false)

    const [labels, setLabels] = useState(null)
    const [labelsError, setLabelsError] = useState(false)

    const [newFileModalShow, setNewFileModalShow] = useState(false)

    const [updated, setUpdated] = useState(false)

    useEffect(() => {
        getAllFiles(user)
            .then(res => setFiles(res.data.files))
            .catch(err => {
                msgAlert({
                    heading: 'Error getting files',
                    message: 'failed to get files',
                    variant: 'danger'
                })
                setFilesError(true)
            })
    }, [updated])

    useEffect(() => {
        getAllLabels(user)
            .then(res => setLabels(res.data.labels))
            .catch(err => {
                msgAlert({
                    heading: 'Error getting labels',
                    // ! message: messages.getLabelsFailure
                    message: 'Sorry about your labels',
                    variant: 'danger'
                })
                setLabelsError(true)
            })
    }, [updated])

    return (
        <>
            <Container fluid className="m-2">
                <Row>
                    <Col md={2} >
                        <p>Labels</p>
                        <LabelsSidebar msgAlert={msgAlert} user={user} labels={labels} labelsError={labelsError} triggerRefresh={() => setUpdated(prev => !prev)}/>
                    </Col>
                    <Col md={10} >
                        <Row>
                        <Col md={12}>
                            <Container fluid>
                            <Button 
                                    className="m-2" variant="dark" onClick={() => setNewFileModalShow(true)}
                                >
                                    Hoist New File
                                </Button>
                            </Container>
                        </Col>
                        </Row>
                        <Row>
                            <FilesContainer msgAlert={msgAlert} user={user} files={files} filesError={filesError} labels={labels} />
                        </Row>
                    </Col>
                </Row>
            </ Container>
            <NewFileModal
                user={user}
                show={newFileModalShow}
                handleClose={() => setNewFileModalShow(false)}
                msgAlert={msgAlert}
            />
        </>
    )
}

export default Home
asands94 commented 1 year ago

Whats the difference here between your updateLabel useState and the regular label one? It looks like you're trying to pass the same information to different variables?

estebbins commented 1 year ago

The edit was to set the label inside of a useEffect and also change defaultValue in my label form to value.

    const { user, editLabel, show, handleClose, msgAlert, triggerRefresh } = props

    // console.log('props.label', props.label)
    const [label, setLabel] = useState({})
    console.log('basically props.label', editLabel)

    console.log('editcontmodal label', label)
    useEffect(() => {
        setLabel(editLabel)
        console.log('use effect edit label', editLabel)
    }, [editLabel])