code.cycling
code.cycling

Reputation: 1274

React useState value incorrect on socket.on

I'm new to socket.io and I'm trying to implement a simple notification.

My problem is that I execute handleClick function to turn open to a true value and when socket.on run its reading incorrect/default value of the open.

Notification.js

const [open, setOpen] = useState(false);

const handleClick = (event) => {
    setAnchorEl(event.currentTarget);
    if (!open) {
        setOpen(true) // set open to true
    }
};

useEffect(() => {
    socket.on("notification", function (data) {
        console.log('SOCKET', open) // idk why this is reading false
    })
}, [])

EDIT

Here's my use-case handleClick func is where user load his/her notification that will set open to true and when socket run it will check if open is true and dispatch the new notification to existing notification array

const handleClick = (event) => {
    setAnchorEl(event.currentTarget);
    if (!open) {
        setOpen(true) // set open to true
        dispatch(getNotifications(params)) // load user notifications
    }
};

useEffect(() => {
    socket.on("notification", function (data) {
        console.log('SOCKET', open) // returning false always
        notificationData(data.data)
    })
}, [])

const notificationData = ({ sender, message, notif }) => {
    setNotifCounter(notifCounter => notifCounter + 1)
    setNotification(_.startCase(sender) + ' - ' + message, 'info')
    if (open) { // check if user already loaded his/her own notification
        dispatch(getNewNotif(notif)) // push to array to avoid duplicate
    }
}

Upvotes: 1

Views: 408

Answers (2)

Drew Reese
Drew Reese

Reputation: 202751

An effect with an empty dependency array ([]) will only run the effect once when the component mounts. Instead, add open to the dependency array so the effect is triggered on mount and on state update of open. The issue is that the current value of open is inclosed in the socket.on callback, so when state updates the callback needs to re-enclose open.

const [open, setOpen] = useState(false);

const handleClick = (event) => {
    setAnchorEl(event.currentTarget);
    if (!open) {
        setOpen(true) // set open to true
    }
};

useEffect(() => {
    socket.on("notification", function (data) {
        console.log('SOCKET', open);
    })
}, [open]) // <-- add open to effect dependency

or you can externally defines the callback

const [open, setOpen] = useState(false);

const handleClick = (event) => {
    setAnchorEl(event.currentTarget);
    if (!open) {
        setOpen(true) // set open to true
    }
};

const socketOnHandler = data => console.log('SOCKET', open);

useEffect(() => {
    socket.on("notification", socketOnHandler)  // <-- use callback
}, [])

Upvotes: 1

Brandon
Brandon

Reputation: 60

I am not sure this is the proper way. To make it work, when you put socket.on into useEffect without dependency, it looks resolve the issue.

useEffect(() => {
    socket.on("notification", function (data) {
        console.log('SOCKET', open) // idk why this is reading false
    })
});

One more time, I am not sure this way is the proper way.

Upvotes: 0

Related Questions