Search code examples
reactjsmaterial-uireact-hooksreact-statematerial-table

Change checked state of a material-ui switch onChange


I have implemented a material-ui table with a column that renders material-ui switch component for each of the table rows. I'm able to successfully pass data for the switches using table data (rowData arg), which you can see below. Since each material-ui element maintains its own state, I assume that setting 'checked' this way sets the states as well. I also have a handleChange method to change the state onChange. I however can't see the switch happening in the UI.

  const [switchState, setswitchState] = useState({});
 
  const handleChange = (evt: React.ChangeEvent<HTMLInputElement>) => {
    setswitchState({ ...switchState, [evt.target.name]: evt.target.checked });
  };

  <MaterialTable
    columns={[
      {
        title: "Name",
        field: "DisplayName",
      },
      {
        title: "Switch Control",
        field: "checked",
        render: (rowData) =>
        <Typography component="div">
          <Grid component="label" container alignItems="center" spacing={1}>
            <Grid item>On</Grid>
            <Grid item>
              <AntSwitch
                name="cb"
                onChange={handleChange}
                checked={rowData.checked}/>
            </Grid>
            <Grid item>off</Grid>
          </Grid>
        </Typography>
      }
    ]}
    data={data}
    options={{
      search: false,
      paging: false,
    }}
  />

I also tried setting the state dynamically on render of each row/switch as,

const dyCheckState = (rd: any) => {
  setswitchState({ ...switchState, [rd.name]: rd.checked});
  return rd.checked;
};

<AntSwitch
   name={rowData.DisplayName}
   onChange={handleChange}
   checked={dyCheckState(rowData)}
/>

Any help is much appreciated! Thanks!


Solution

  • You should try using rowData in state itself and not mutate it directly.

    Please follow the below given example

     const [rowDataState, setRowDataState] = useState(rowData);
    
    
     // Then use rowDataState in here something like this
    
     <AntSwitch
        name={rowDataState.DisplayName}
        onChange={(evt)=>{
          setswitchState({ ...switchState, [evt.target.name]: evt.target.checked 
          });
          setRowDataState({ ...rowDataState, checked: evt.target.checked }); 
        }}
        checked={rowDataState.checked}
      />
    

    Also, I would recommend moving these both into a different handler function in the component and then pass it as an onChangeHandler to the AntSwitch.