I have an EditProfile functional component that initially loads perfect, but loses state whenever the user refreshes their page with the form open. Instead of pre-filling the inputs with the 'user' state/values, it now sets the inputs as blank, and the 'user' object from const [user, setUser] = useState({})
console.logs as an empty object.
Here is the EditProfile component:
import React, {useEffect, useState} from 'react'
import './EditProfile.css'
export default function EditProfile(props) {
const [user, setUser] = useState({})
let handleChange = (e) => {
setUser({...user, [e.target.name]: e.target.value})
}
let handleSubmit = async () => {
let body = {
_id: user._id,
email: user.email,
username: user.username,
shortDescription: user.shortDescription,
fullDescription: user.fullDescription,
paymentInfo: user.paymentInfo,
publisherAgreement: user.publisherAgreement
}
let options = {
method: 'PUT',
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(body)
}
await fetch('/api/users/editProfile', options)
.then(res => res.json())
.then(data => {
this.props.setUserInState(data)
})
}
useEffect(() => {
(async() => {
setUser(props.user)
})()
},[])
console.log('here is the user: ' + JSON.stringify(user))
return (
<form className='editProfileForm' onSubmit={handleSubmit}>
<input type='hidden' value={user._id}></input>
<input type='hidden' value={user.email}></input>
<div>
<h4>Edit Profile</h4>
<div className="form-group address-update">
<label className="inputUD"><span className="label"><b>Username</b></span></label>
<input type="text" className="form-control" name="username" onChange={handleChange} value={user.username}></input>
</div>
<div className="form-group address-update">
<label className="inputUD"><span className="label"><b>Email</b></span></label>
<input type="text" className="form-control" name="email" onChange={handleChange} value={user.email}></input>
</div>
{user.publisherAgreement &&
<div>
<div className="form-group">
<label className="inputUD"><span className="label"><b>Short Description</b></span></label>
<textarea type="text" className="form-control" name="shortDescription" onChange={handleChange} value={user.shortDescription}></textarea>
</div>
<div className="form-group">
<label className="inputUD"><span className="label"><b>Full Description</b></span></label>
<textarea type="text" className="form-control" name="fullDescription" onChange={handleChange} value={user.fullDescription}></textarea>
</div>
<div className="form-group address-update">
<label className="inputUD"><span className="label"><b>Fake Payment Info</b></span></label>
<input type="text" className="form-control" name="paymentInfo" onChange={handleChange} value={user.paymentInfo}></input>
</div>
</div>
}
<button type="submit" className="btn btn-success">Submit</button>
</div>
</form>
)
}
And here is the App.jsx component where it is called on (I cut out imports to save space):
state = {
user: false,
}
setUserInState = (incomingUserData) => {
console.log('incoming userdata: ' + JSON.stringify(incomingUserData))
this.setState({user: incomingUserData})
}
componentDidMount() {
let token = localStorage.getItem('token')
if (token) {
const payload = JSON.parse(atob(token.split('.')[1]))
if (payload.exp < Date.now() / 1000) {
localStorage.removeItem('token')
token = null
} else {
this.setState({ user: payload.user })
}
}
}
render() {
return (
<div className="App">
<Navbar user={this.state.user} setUserInState={this.setUserInState}/>
<Routes>
<Route path='/ideas/create' element={<NewIdea user={this.state.user} setUserInState={this.setUserInState}/>}/>
<Route path='/users/showProfile' element={<UserProfile user={this.state.user} setUserInState={this.setUserInState}/>}/>
<Route path='/users/editProfile' element={<EditProfile user={this.state.user} setUserInState={this.setUserInState}/>}/>
<Route path='/publishers/becomePublisher' element={<BecomePublisher user={this.state.user} setUserInState={this.setUserInState}/>} />
<Route path='/users/addSubscription'/>
<Route path='/users/removeSubscription'/>
<Route path='/publishers/show/:id' element={<PubProfile user={this.state.user}/>}/>
<Route path='/ideas/show/:id' element={<PubIdeas user={this.state.user}/>}/>
<Route path='/ideas/ideasFeed/:userId' element={<IdeasFeed user={this.state.user}/>}/>
<Route path='/discover/:id' element={<Discover user={this.state.user} setUserInState={this.setUserInState}/>}/>
<Route path='*' element={<Navigate to='/discover/:id' replace />}/>
</Routes>
</div>
)
}
}
The page is accessed via a "Link to" in the Navbar component.
While the form works fine as long as the user doesn't hit refresh, I need the form to be able to handle a refresh and still work.
EDIT/SOLUTION:
I simply passed props.user into the useEffect dependencies array like so:
useEffect(() => {
(async() => {
setUser(props.user)
})()
},[props.user])
The page now sets props into state after a page refresh, just like it does on the first render.
Also, inside my fetch call I switched this.props.setUserInState(data) to just setUser(data).