Reputation: 178
Hello I have a component as follows I'm using usestate hook to initialize the myFeeds variabele to the feeds array and I'm running an effect to add any data from server (socket.io) However when I'm console logging the result myFeeds is giving me an empty array what could be the possible reasons?
const Dashboard = ({feeds}) => {
useEffect(() => {
getFeeds(); // this fetches feeds array
}, []);
const [myFeeds, setMyFeeds] = useState(feeds);
// useEffect hook to get real time messages and add it to feed
useEffect(() => {
let mount = true;
io.on('created' (data) => {
if(mount) {
data && setMyFeeds([...feeds, data]);
}
}
}, [])
console.log(feeds); // gives array of objects
console.log(myFeeds); // giving empty array
return(
<FeedBody body={myFeeds} />
);
}
// mapstatetoprops here
getFeeds is an action creator which is as follows
export const getFeeds = () => async dispatch => {
const res = await axios.get('/feeds');
// dispatch type get feeds here set payload to result of above operation
}
Upvotes: 0
Views: 122
Reputation: 1074138
I don't know if it's the problem, but the way you're taking the feeds
prop and turning it into the myFeeds
state is definitely problematic, in a couple of ways:
Your component won't see updates to its feeds
prop if the parent calls it again with a new value. Remember that the value you pass into useState
is only used when your component is first created, it's not used on subsequent calls to your component function (the current state of your component is used instead).
The feeds
you're using in your io.on
callback may be stale, because you have an empty dependencies array in your useEffect
call; by the time io.on
calls your callback, your component function may have been called with an updated feeds
(which you would see in your console.log
) but the one used with setMyData
will be stale (the original one closed over by the callback when it was created during the first call to your component function).
Here's what I'm referring to in #2:
useEffect(() => {
let mount = true;
io.on('created' (data) => {
if(mount) {
data && setMyFeeds([...feeds, data]);
// −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−^^^^−−−−−−−−−−−− may be stale!
}
}
}, [])
You probably want to move the io.on
call out of this component and put it in the parent, and have the parent re-render this component when feeds
changes.
If you decide not to do that, the minimum change you need to make is to not use that stale feeds
parameter value. Instead, use the callback form:
useEffect(() => {
let mount = true;
io.on('created' (data) => {
if(mount) {
data && setMyFeeds(myFeeds => [...myFeeds, data]);
// −−−−−−−−−−−−−−−−−−−−−−−−−−−−^^^^^^^^−−−−−−−^^^^^^^−−−−−−−−−−−− up to date
}
}
}, [])
But again, your component will miss an updates to feeds
that the arent sends it.
This note in the documentation about copying props to state when using hooks may be a useful read.
Upvotes: 1