Reactjs state from parent to child component returns undefined

Viewed 108

I am trying to solve this but I can't, I pass the state from a parent to child component like this:

Main.js

...
const [chatRooms, setChatRooms] =  useState([])
const [currentRoom, setCurrentRoom] =  useState({})
const prevRoom = useRef()

useEffect(()=>{
        const getRooms = async() =>{            
             const {data} = await axios.get('chat/rooms')            
             setChatRooms(data)
             setCurrentRoom(data[0])
        }
        getRooms()
    },[])

    useEffect(()=>{
        if (currentRoom !== prevRoom.current)
            prevRoom.current = currentRoom
        
        if (prevRoom.current?.id)
            disconnect(prevRoom.current.id)     

        connect()

    },[currentRoom])

return (
 
 <ChatSelect rooms={chatRooms} currentRoom={currentRoom.id} setCurrentRoom={setCurrentRoom} />  

)

ChatSelect.js

const ChatRoomSelection = ({rooms, currentRoom, setCurrentRoom})=>{   
    
    const handleChange = (e) =>{     
        setCurrentRoom(e.target.value)
        //here fails and the selected value can't be set properly in the select option
        console.log(currentRoom)
    }

    return (
        <div>
            <select name="rooms" value={currentRoom} onChange={(e)=>handleChange(e)}>                            
                {
                    rooms.map(room=>(
                        <option value={room.id} key={room.id}>{room.name}</option>
                    ))
                }
            </select>
        </div>
    )

}

When I select another chat room, the currentRoom returns the correct id the first time, but when I change it again it returns undefined, what is happening? Thank you.

1 Answers

From what I can parse though in your code it seems like currentRoom should be an entire room object, but in the select's onChange handler you are updating it to be a room id value.

I think you need to pass the entire room object as the option's value.

<select
  name="rooms"
  value={currentRoom.id}
  onChange={handleChange}
>                            
  {rooms.map(room => (
    <option value={room} key={room.id}>{room.name}</option>
  ))}
</select>

Alternatively you can keep currentRoom as strictly an id value instead of an object.

Main

...
const [currentRoom, setCurrentRoom] =  useState(null);
...

useEffect(()=>{
  const getRooms = async() =>{            
    const {data} = await axios.get('chat/rooms');         
    setChatRooms(data);
    setCurrentRoom(data[0].id); // <-- save room id
  }
  getRooms();
}, []);

...

return (
  <ChatSelect
    rooms={chatRooms}
    currentRoom={currentRoom} // <-- pass room value
    setCurrentRoom={setCurrentRoom}
 />
);

ChatSelect

<select
  name="rooms"
  value={currentRoom}
  onChange={handleChange}
>                            
  {rooms.map(room => (
    <option value={room.id} key={room.id}>{room.name}</option>
  ))}
</select>
Related