reactjsreact-hooksmaterial-uiemotion

Material UI ES6 Custom Styled Text Field cursor loses focus with onChange event


I am facing issue when customizing MUI component with styled library. The text field loses focus on typing my character in it. It works fine if I am using inline sx based styling. Perhaps I am calling it incorrectly. Any help will be highly appreciated.

Simple form page:

const initialValues = {
    vehicle: "",
    mobile: "",
    email: "",
    name: "",
    address: "",
    alt_mobile: "",
  };
  
  const { values, setValues, handleChange } = useForm(initialValues);

  return (
    <Box border={1}>
      <Grid container>
        <Grid item xs={6}>
          <StyledField
            value={values.vehicle}
            onChange={handleChange}
            variant="outlined"
            label="Vehicle No"
            name="vehicle"
            key="vehicle"
          />
        </Grid>
      </Grid>
    </Box>
  );

useform.js

import { React, useState } from 'react'

export function useForm(initialValues) {

    const [values, setvalues] = useState(initialValues);

    const handleChange = e => {
        const { name, value } = e.target
        setvalues({
            ...values,
            [name]: value
        })
    }

  return {
    values,
    setvalues,
    handleChange,
  }
}

finally my custom text field component:

export default function CustomField(props) {

  const SyledField = styled(TextField)(({ theme }) => ({
    width: "70%",
    margin: theme.spacing(1),
  })); 

  const { name, label, value, onChange, ...others } = props

  return (
    <SyledField
      variant="outlined"
      label={label}
      name={name}
      onChange={onChange}
      value={value}
      {...others}
    />
  );
}

If I change the custom custom to use sx based styling, it works fine:

export default function CustomField(props) {

  const { name, label, value, onChange, ...others } = props

  return (
    <TextField
      sx={{ width: "70%", margin: "8px" }}
      variant="outlined"
      label={label}
      name={name}
      onChange={onChange}
      value={value}
      {...others}
    />
  );
}

I have gone through many forums and tried using keys, calling JSX as function but it does not seem to help. It seems React is re-loading the component each time onChange event triggered. Any suggestion?


Solution

  • The styled function generates a new component whenever called. When you call it inside CustomField, it generates a new component on each render. Move it out of CustomField.

    const SyledField = styled(TextField)(({ theme }) => ({
      width: "70%",
      margin: theme.spacing(1),
    })); 
    
    export default function CustomField(props) {
      const { name, label, value, onChange, ...others } = props
    
      return (
        <SyledField
          variant="outlined"
          label={label}
          name={name}
          onChange={onChange}
          value={value}
          {...others}
        />
      );
    }