I am trying out the new React Hooks, and I am a little stuck as the UI is not updating when the local state is updated. Here is my code,
import React, { useState, useEffect } from 'react';
import Post from './Post'
import PostForm from './PostForm';
import axios from 'axios';
function PostsList() {
const [posts, setPosts] = useState([]);
// setting up the local state using useEffect as an alternative to CDM
useEffect(() => {
axios.get('...')
.then(res => {
// the resposne is an array of objects
setPosts(res.data)
})
})
const handleSubmit = (data) => {
// the data I am getting here is an object with an identical format to the objects in the posts array
axios.post('...', data)
.then(res => {
// logging the data to validate its format. works fine so far..
console.log(res.data);
// the issue is down here
setPosts([
...posts,
res.data
])
})
.catch(err => console.log(err))
}
return (
<div>
<PostForm handleSubmit={handleSubmit} />
<h3>current posts</h3>
{ posts.map(post => (
<Post key={post.id} post={post} />
)) }
</div>
)
}
I am trying out the new React Hooks, and I am a little stuck as the UI is not updating when the local state is updated. Here is my code,
import React, { useState, useEffect } from 'react';
import Post from './Post'
import PostForm from './PostForm';
import axios from 'axios';
function PostsList() {
const [posts, setPosts] = useState([]);
// setting up the local state using useEffect as an alternative to CDM
useEffect(() => {
axios.get('...')
.then(res => {
// the resposne is an array of objects
setPosts(res.data)
})
})
const handleSubmit = (data) => {
// the data I am getting here is an object with an identical format to the objects in the posts array
axios.post('...', data)
.then(res => {
// logging the data to validate its format. works fine so far..
console.log(res.data);
// the issue is down here
setPosts([
...posts,
res.data
])
})
.catch(err => console.log(err))
}
return (
<div>
<PostForm handleSubmit={handleSubmit} />
<h3>current posts</h3>
{ posts.map(post => (
<Post key={post.id} post={post} />
)) }
</div>
)
}
when I submit the form, the UI flickers for a split second and then renders the current state without the new update, it seems that something is preventing it from re-rendering the new state. If more code/clarification is needed please leave a ment below. thanks in advance.
Share Improve this question edited Feb 2, 2019 at 17:12 MoSwilam asked Feb 2, 2019 at 17:06 MoSwilamMoSwilam 9442 gold badges11 silver badges28 bronze badges 4-
1
actually since you don't pass second argument into
useEffect
it acts as cDM + cDU so it's called on each render. assume it's about race conditions between adding new and loading from server actual list. are you sure for second time you click submit previously added post is not loaded alongside others? – skyboyer Commented Feb 2, 2019 at 17:16 -
actually that makes a lot of sense, so I guess the reason it flickers after submitting the form is the time it gets updated by the
handleSubmit()
and sinceuseEffect()
rerenders the dom, so it renders the old posts ing from the server.. so the question now is how to prevent that from happening, in other words, how to set the local state as we used to do usingcDM()
and preventcDU()
from running when the state is updated ? – MoSwilam Commented Feb 2, 2019 at 17:25 -
1
Alright I got it, I simply added an empty array right after the closing tag of the callback function passed to the
useEffect()
, this made ponent renders only one time as opposed to every time the state gets updated. thanks man :) – MoSwilam Commented Feb 2, 2019 at 17:41 - 1 np. may you create short answer/accept it with highlighting this thing? it'd be more clear for whoever find this question – skyboyer Commented Feb 2, 2019 at 17:43
1 Answer
Reset to default 5alright, problem solved with the helpful hint from @skyboyer,
so what happened initially is, the useEffect()
acts like ponentDidMount()
& ponentDidUpdate()
at the same time, that means whenever there is an update to the state, the useEffect()
gets invoked, which means resetting the state with the initial data ing from the server.
to fix the issue I needed to make the useEffect()
renders the ponent only one time when it's created/rendered as opposed to rendering it every time there is an update to the state. and this is done by adding an empty array as a second argument to the useEffect()
function. as shown below.
useEffect(() => {
axios.get('...')
.then(res => {
setPosts(res.data)
})
}, [])
thanks :)