Search code examples
reactjsreact-hooksuse-effect

ReactJS: useEffect not updating state value on API call


I would like to update the state value when on API success response. And based on the updated state value would like to perform the next process.

const App = () => {

    const [chatClient, setChatClient] = useState(null);
    const [channel, setChannel] = useState(null);
    const [chatToken, setChatToken] = useState(null);

    useEffect(() => {
        const initChat = async () => {
            const client = StreamChat.getInstance(process.env.API_KEY);
            await axios.get(`${process.env.API_URL}/generate_token?username=johndoe`, {
            })
                .then((response) => {
                    if (response && response.status === 200) {
                        const _token = response.data.token
                        setChatToken(_token)
                        console.log(chatToken); // returns null value
                    }
                })
            await client.disconnectUser()
            await client.connectUser({ id: userName }, chatToken); // Getting the chatToken value as null
            const _channel = await client.channel(process.env.TYPE, process.env.ROOM);
            setChatClient(client);
            setChannel(_channel)
        };

        initChat();
    }, []);

    return (
        <Chat client={chatClient} theme='livestream dark'>
            <Channel channel={channel}>
                ...
            </Channel>
        </Chat>
    );
};

export default App;

I am following this answer but still there is something missing that I can not figure out.


Solution

  • Since your useEffect is run only on the initial render, the chatToken inside the useEffect is still referencing the old value from the closure. The solution here would be to use the chatToken from api directly.

    useEffect(() => {
        const initChat = async () => {
            const client = StreamChat.getInstance(process.env.API_KEY);
            const token = await axios.get(`${process.env.API_URL}/generate_token?username=johndoe`, {
            })
                .then((response) => {
                    if (response && response.status === 200) {
                        const _token = response.data.token
                        setChatToken(_token)
                        return  _token;
                    }
                })
            await client.disconnectUser()
            await client.connectUser({ id: userName }, token);
            const _channel = await client.channel(process.env.TYPE, process.env.ROOM);
            setChatClient(client);
            setChannel(_channel)
        };
    
        initChat();
    }, []);
    

    Check this post on why state updates don't reflect after calling setState for more details:

    useState set method not reflecting change immediately