skip to Main Content

I know theres multiple questions along this topic on here, but I’ve incorporated what I’ve found and still getting no where. It should be straightforward, I have a component with a Select that the initial value is ”, then updated through state when data comes in (defaultPlan). The label for this selection gets rendered on the menu just fine. But when I change the selection, the renderValue does not update, instead I only see the same label from the defaultPlan, while the actual value is changing appropriately to the selected option. I’ve tried adding a key with state directly for the Select component in case it was an issue of not rerendering due to shallow comparison, but that did not change anything (also tried with a useEffect specifcally watching for the other state values to change). I tried calling my renderValue function under the handleChange function, but that did not work either- which makes sense since the event is a different object and does not have the full menu item option object to pass to it, but again, I’m out of ideas. Any suggestions are appreciated, just not seeing what I’m doing wrong.

Here’s the component:

const ClientGoalReport = () => {

    const { clientId } = useParams();

    const [ planId, setPlanId ] = useState()
    const [ planList, setPlanList ] = useState([])
    const [ defaultPlan, setDefaultPlan ] = useState('')
    const [ isStart, setIsStart ] = useState()
    const [ isEnd, setIsEnd ] = useState()
    const [ header, setHeader ] = useState()
    const [tableData, setTableData] = useState()
    const [hasData, setHasData] = useState('initial')
    const [renderKey, setRenderKey] = useState(0);

    const { data: plans } = useGetAllClientReportsQuery(clientId)
    

    useEffect(() => {
        if (plans) {
            let list = plans.map((plan, idx) => (
                { 
                  value: {start: plan.startDate, end: plan.endDate, planId: plan._id},
                  label: `${idx+1} ${plan.type} Report Date: ${new Date(plan.reportDate).toLocaleDateString()}, Start: ${new Date(plan.startDate).toLocaleDateString()}, End: ${new Date(plan.endDate).toLocaleDateString()} `
                }
                 )).sort((a, b) => a.startDate - b.startDate)
            // console.log("list: ", list)
            setPlanList(list);

            const def = list[list.length -1]
            setDefaultPlan(def)
        }
    }, [plans])

    const [pullData, { data, isSuccess }] = useGetGoalAttainDataMutation()

    const generatePlanOptions = () => {
        
        return planList.map((plan, idx) => {
    
            return (
              
               <MenuItem key={idx} value={plan.value}>
                {plan.label}
               </MenuItem>
            )
            })
      }

      const renderValue = (selected) => {
        if (!selected) return '';
        return selected.label;
      }

      const handlePlanChange = (event) => {
        // renderValue();
        setRenderKey((prevKey) => prevKey + 1);
        setPlanId(event.target.value.planId)
        setIsStart(event.target.value.start)
        setIsEnd(event.target.value.end)
      }

      useEffect(() => {
        //takes data and constructs table to display
        }
      
        }, [data, isSuccess, isStart, isEnd])

  return (
    <>
    <div display='flex'>
        <Box
            sx={{
            display: 'flex',
            flexDirection: 'row',
            p: 1,
            m: 1,
            borderRadius: 1,
            }}
        >
            <h1>Search by Service Plan</h1><br />
             <FormControl sx={{ m: 1, minWidth: 120 }}>
                <InputLabel id="plan-select-label">Plan</InputLabel>
                    <Select
                        labelId="plan-select-label"
                        label="Plan"
                        name='plan'
                        value={defaultPlan}
                        onChange={handlePlanChange}
                        autoWidth
                        key={renderKey}
                        renderValue={renderValue}
                        native={false}
                        displayEmpty={true}
                    >
                        {generatePlanOptions()}
                    </Select>
            </FormControl><br />
           
            <Button color='primary' variant='contained' onClick={() => pullData({clientId, isStart, isEnd, planId})}>    Run    </Button>
        </Box>
    </div>
    
    {displayReport}
    </>
  )
}

2

Answers


  1. Chosen as BEST ANSWER

    After Nazrul's answer and thinking it through, the issue I think comes mainly down to how I construct the menu options from the data and that my values are objects (which have the different fields needed to make the api call- its a mongodb aggregate and requires different values to set the table correctly). To make it work, I updated the handlePlanChange to run a match of the planList used to create the menu with the selected plan's id, then update the state which gets the renderValue to respond appropriately:

    (Below theres a minor change where I changed defaultPlan to isPlan just to be more succinct since its used beyond just setting the default option. I also removed the renderKey state and key prop, since that was not actually needed)

    const handlePlanChange = (event) => {
            const selectedPlan = event.target.value
    
            const match = planList.find(o => o.value.planId === selectedPlan.planId)
        
            setPlanId(selectedPlan.planId)
            setIsStart(selectedPlan.start)
            setIsEnd(selectedPlan.end)
    
            setIsPlan(match)
          }
    

  2. It could be the way you are updating the state for the selected plan. When the selection changes, you are updating the planId, isStart, and isEnd states based on the event.target.value, which corresponds to the selected value of the component. However, you are not updating the defaultPlan state, which is used as the value prop for the component.
    Try modifying your handlePlanChange function to update the defaultPlan state properly,

    const handlePlanChange = (event) => {
        const selectedPlan = event.target.value;
        setRenderKey((prevKey) => prevKey + 1);
        setPlanId(selectedPlan.planId);
        setIsStart(selectedPlan.start);
        setIsEnd(selectedPlan.end);
        setDefaultPlan(selectedPlan); // Update defaultPlan state
    }
    

    By updating the defaultPlan state with the selected plan, it should reflect the changes in the component.
    Also, make sure to update the value prop of the component to be planId instead of defaultPlan,

    <Select
        labelId="plan-select-label"
        label="Plan"
        name='plan'
        value={planId} // Update value prop to planId
        onChange={handlePlanChange}
        autoWidth
        key={renderKey}
        renderValue={renderValue}
        native={false}
        displayEmpty={true}
    >
        {generatePlanOptions()}
    </Select>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search