Wednesday, 18 January 2023

setState(prev) returning previous state in reverse order than expected when referencing another useState var in a useEffect

I'm creating a simulated chat experience where at obj4, the user has a button to click to initiate their session.

Everything works fine showing messages 1-4 but when messages.length === 4 and I check initiated === true, weird stuff starts happening: prev, which usually returns the messages in the correct order, now returns the messages in the reverse order. And calling .reverse() or setting prev to a new variable and then calling reverse() doesn't work either.

The whole order of messages breaks when I check if (initiated === true) but if I don't, everything renders in the order I expect.

Any idea what's happening here?

import { useState, useEffect } from "react"

const chattest = () => {

    const [messages, setMessages] = useState([])
    const [initiated, setInitiated] = useState(false)

    const obj1 = {
        type: 'text',
        text: '1',
        action: function() {}
    }

    const obj2 = {
        type: 'text',
        text: '2',
        action: function() {}
    }

    const obj3 = {
        type: 'text',
        text: '3',
        action: function() {}
    }

    const obj4 = {
        type: 'button',
        text: initiated ? 'Initiated!' : 'Initiate',
        state: initiated,
        action: function() {
            console.log('setting initiated')
            setInitiated(true)
        }
    }

    const obj5 = {
        type: 'text',
        text: 'initiated set!',
        action: function() {}
    }

    useEffect(() => {
        switch(messages.length) {
            case 0:
                setMessages([obj1])
            case 1:
                setMessages((prev) => [...prev, obj2])
            case 2:
                setMessages((prev) => [...prev, obj3])
            case 3:
                setMessages((prev) => [...prev, obj4])
            case 4:
                if (initiated) { // behavior changes here if I use this line 

                    setMessages((prev) => {
                        console.log('prev', prev)
                        console.log('prev reversed', prev.reverse()) // this doesnt work
                        return [...prev, obj5]
                    })
                }
            default:
                break
        }
    }, [messages, initiated])

    return (
        <div className="flex flex-col-reverse border border-solid border-black-500 w-[50%] mx-auto h-screen text-black">
            {
                messages.reverse().map((message, index) => {
                    const { type, text, state, action } = message
                   return <div key={index}>
                        <ChatFactory type={type} state={state} _text={text} action={action} />
                    </div>
                })
            }
        </div>
    )
}

export default chattest

const ChatFactory = ({type,_text, state,action}) => {
    return (
        type === 'text'
        ? (
            <p>{_text}</p>
        )
        : (
            <button onClick={action}>
               { _text}
            </button>
        )
    )
}


from setState(prev) returning previous state in reverse order than expected when referencing another useState var in a useEffect

No comments:

Post a Comment