skip to Main Content
        import React, {useEffect, useState} from 'react'
        import axios from 'axios'
        import '../App.css'
        import { useNavigate } from 'react-router-dom'
        import { gettingData } from '../api/getUserData'
        import { handleLogout } from '../api/handleLogout'
        import { getGroundNear } from '../api/getGroundNearby'
        import { bookingSlot } from '../api/bookingSlot'
    
    
        const Dashboard = () => {
            const navigate = useNavigate()
            const [userData, setUser] = useState(undefined)
            const [groundData, setGroundData] = useState([])
            const [currentTime, setCurrentTime] = useState(Date.now())
            const [isOccupied, setIsOccupied] = useState(false)
    
    
        axios.defaults.withCredentials = true;
    
         useEffect(()=>{
          gettingData(setUser)
        },[])
      
        useEffect(()=>{
          console.log("usee 2")
          if(userData){
            console.log(userData)
            getGroundNear(userData.pincode, 0, 50000, setGroundData) 
          }
            
        },userData)
    
      
        const handleBooking = (slotId, groundId, userId) => {
          if(bookingSlot(slotId, groundId, userId)){
            setIsOccupied(true)
          }
    
        }
    
    
      return (
        <div>
          <button onClick={() => {handleLogout(navigate)}}>Logout</button>
          
          <div>
            <h3>Grounds</h3>
            {groundData && groundData.length &&
              groundData?.map((ground)=>{
                return(
                  <div id='cards'>
                    <img src={ground.photo} alt='ground'></img>
                    <h4>{ground.ground}</h4>
                    <span>Type: </span><span>{ground.type}</span><br/>
                    <span>{ground.discription}</span>
                    
                    <div className='timings'>
                      <div className='slots'>
                        {
                        ground?.slots?.map(slot => {
                          return (
                            <>


{/*I want this component to re-render whenver the button is clicked so that it has updated views of slot booking*/}

                          <div id='slot-id'>
                            {!slot.occupied ? (
                              <button onClick={() => handleBooking(slot._id, slot.ground_id, userData._id)}>{slot.time_start} - {slot.time_end}</button>
                            ) : (
                              <button id='occupied-slot' style={{border: '3px dotted red', cursor: 'not-allowed', backgroundColor: '#FF999C'}}>{slot.time_start} - {slot.time_end}</button>
                            )}
                          </div>
                        
                        </>
                      )
                    })}
                  </div>
                </div>
              </div>
            )
          })
        }

      </div>

    </div>    
  )
}

export default Dashboard

Challenge: Re-rendering slot-id Div on Button Click in React

I’m working on a React component that displays bookable slots. Each slot has a button, and I want the entire slot-id div to re-render whenever a button is clicked.

In the provided code, the button click triggers the handleBooking function, but it doesn’t directly cause the slot-id div to re-render. This means the visual appearance won’t change unless the data source (e.g., an API call) updates the slot.occupied property outside of this component.

Desired Behavior: We want the slot-id div to re-render immediately after the button click, even if the external data source hasn’t been updated yet. This will provide a more responsive user experience by instantly reflecting the button click visually

2

Answers


  1. You should create a separate component for the button, than you can just simply pass slot.occupied as a prop and let the deeper component apply the needed styling.

    Then wen the slot.occupied prop is changed, the deeper component will re-render.


    An example of the deeper component:

    const CustomButton = (props) => {
        return (props.slot.occupied)
           ? <button onClick={props.onClick}>{props.slot.time_start} - {props.slot.time_end}</button>
           : <button id='occupied-slot' style={{border: '3px dotted red', cursor: 'not-allowed', backgroundColor: '#FF999C'}}>{props.slot.time_start} - {props.slot.time_end}</button>
    }
    

    Which you can use in your map()

    ground?.slots?.map(slot => <CustomButton slot={slot} onClick={...} />)
    
    Login or Signup to reply.
  2. To ensure the slot-id div re-renders immediately after a booking button is clicked in your React component, you should update your component’s state in a way that triggers a re-render. This can be done by updating the groundData array in the state to reflect the changes made by the booking. Here’s how you can modify your handleBooking function and other relevant parts of your code:
    Step 1: Modify handleBooking

    Update the handleBooking function to mark a slot as occupied directly in the state. This change in state will cause React to re-render the component:

    const handleBooking = (slotId, groundId, userId) => {
      // Call the bookingSlot API and wait for its completion
      bookingSlot(slotId, groundId, userId).then((success) => {
        if (success) {
          // Update the groundData state to reflect the change
          const updatedGrounds = groundData.map(ground => {
            if (ground._id === groundId) {
              const updatedSlots = ground.slots.map(slot => {
                if (slot._id === slotId) {
                  return { ...slot, occupied: true }; // Mark the slot as occupied
                }
                return slot;
              });
              return { ...ground, slots: updatedSlots };
            }
            return ground;
          });
          setGroundData(updatedGrounds);
        }
      });
    };
    

    Step 2: Adjust API Call

    Ensure your bookingSlot function returns a promise that resolves to a boolean indicating whether the booking was successful. This allows the state update to happen only after confirming the booking:

    // Example of a modified bookingSlot function
    export const bookingSlot = async (slotId, groundId, userId) => {
      try {
        const response = await axios.post('/api/book-slot', { slotId, groundId, userId });
        return response.data.success; // Ensure this returns true/false based on success
      } catch (error) {
        console.error("Error booking slot:", error);
        return false;
      }
    };
    

    Step 3: Ensure Reactivity in the Render Method

    Ensure that the render method correctly uses the updated groundData from the state:

    return (
      <div>
        <button onClick={() => { handleLogout(navigate) }}>Logout</button>
        <div>
          <h3>Grounds</h3>
          {groundData && groundData.length > 0 && groundData.map((ground) => (
            <div key={ground._id} id="cards">
              <img src={ground.photo} alt="ground" />
              <h4>{ground.ground}</h4>
              <span>Type: </span><span>{ground.type}</span><br />
              <span>{ground.description}</span>
              
              <div className="timings">
                <div className="slots">
                  {ground.slots.map(slot => (
                    <div key={slot._id} id="slot-id">
                      {!slot.occupied ? (
                        <button onClick={() => handleBooking(slot._id, ground._id, userData._id)}>
                          {slot.time_start} - {slot.time_end}
                        </button>
                      ) : (
                        <button id="occupied-slot" style={{ border: '3px dotted red', cursor: 'not-allowed', backgroundColor: '#FF999C' }}>
                          {slot.time_start} - {slot.time_end}
                        </button>
                      )}
                    </div>
                  ))}
                </div>
              </div>
            </div>
          ))}
        </div>
      </div>
    );
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search