0

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.

TMA
  • 1,419
  • 2
  • 22
  • 49
  • State updates are async. The current state value is always the value the component was rendered with. It will not immediately reflect updates until the next render. Therefore your `console.log(chatToken)` will always only log the current value, not the updated value. – trixn Mar 29 '21 at 09:53
  • So I need to use that value into another hook or something ? – TMA Mar 29 '21 at 09:54
  • No you are just not logging the new value but the old one. The update should work though. – trixn Mar 29 '21 at 09:55
  • can you do console.log(response) in your useEffect hook, to see if you are getting the response – crispengari Mar 29 '21 at 09:55
  • Yes I am already getting the `console.log(response.data.token)` into `useEffect` hook – TMA Mar 29 '21 at 09:57
  • @trixn , Ultimately I would like to get that state value for this `await client.connectUser({ id: userName }, chatToken);` method. But due to null value it is throwing the error of `null` value. – TMA Mar 29 '21 at 09:59
  • 1
    Then either use `response.data.token` or wrap that in another effect that has `chatToken` as a dependency. – trixn Mar 29 '21 at 10:00
  • Thx, your suggestion works !!! – TMA Mar 29 '21 at 10:07

1 Answers1

1

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

Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400