clusterBuddy
clusterBuddy

Reputation: 1554

React 16.8 hooks => how to properly inject an array of elements into the DOM

I'm using React's hooks (version 16.8.6) to inject an array of buttons with their respective index + value + onClick={}.

Basic code for brevity

function App() {
   const [rooms, setRoomArray] = useState([]);
   const roomArray = [
     'room1',
   'room2',
   'room3',
   'room4',
  ];
        
   const handleNewMessage = (room) => {
       setRoomArray(roomArray);
       roomSpawner(rooms);
   };
        
   const test = () =>{
       console.log('test here');
   }
        
   const roomSpawner = (rooms) =>{
        return rooms.map((value,index) => (
            <button onClick={test()} key={index}>{value}</button>
        ));
};

Everything works and displays properly, yet by console logging, I see that my console is going into a loop there is a loop and i'm trying to understand:

  1. Is this is a loop or is it react's regular polling/reactive behavior?
  2. Is this 'expensive' in terms of performance?
  3. Would it make sense to insert into test() a socket connection polling a remote server?
  4. Am I misusing the construct? If so please show me how to properly inject an array of elements.

Upvotes: 2

Views: 177

Answers (1)

cbdeveloper
cbdeveloper

Reputation: 31425

Q1: Is this is a loop or is it react's regular polling/reactive behavior?

Answer: As commenters have pointed out, the loop is being caused by onClick={test()}. The onClick prop expects a function, and not a function call, to attach as an event handler. What it you can do is something like this:

const test = (index) =>{
  console.log('I was called for room number: ' + index);
}

const roomSpawner = (rooms) =>{
  return rooms.map((value,index) => (
    <button onClick={() => test(index)} key={index}>{value}</button>
  ));

Q2: Is this 'expensive' in terms of performance?

Not at all. This is a perfect valid React implementation.

Q3: Would it make sense to insert into test() a socket connection polling a remote server?

I don't think so. You should insert your socket connection inside a useEffect() hook to be connected on mount. Something like this:

// INSIDE YOUR COMPONENT

useEffect(()=> {
  // CONNECT TO SOCKET
  // ON SOCKET MESSAGES, UPDATE SOME STATE WITH THE NEW ROOMS AND COMPONEN WILL RE-RENDER
  return () => {
    // DISCONNECT FROM SOCKET
  }
},[]); // WITH THIS EMPTY ARRAY, THIS EFFECT WILL RUN ON 1ST RENDER, AND IT WILL DISCONECT FROM YOUR SOCKET WHEN IT GETS DISMOUNTED

React DOCS on useEffect()

Q4: Am I misusing the construct? If so please show me how to properly inject an array of elements.

I think you're fine. Keep the array of rooms in a state variable using useState() and use stateWithArrayOfRooms.map() to generate your components (buttons, or whatever). Something like.

// INSIDE YOUR COMPONENT

const [roomsArray, setRoomsArray] = useState([]);

useEffect(()=>{
  // CONNECT TO YOUR SOCKET AND UPDATE roomsArray with new messages.
  // setRoomsArray('newRoomsArray from socket');
  return () => {
    // DISCONNECT FROM SOCKET
  }
},[]);

const roomItems = roomsArray.map((item, index) => 
  <RoomComponent key={index or some other unique id} onClick={()=>test(index)}/>
);

return (
  <RoomsContainer>
    {roomItems}
  </RoomsContainer>
);

Upvotes: 1

Related Questions