skip to Main Content

In my react.js component, input field is lose focus whenever a character is typed and need to click on the input field again to type or edit the next character. Why’s this happening?

Here is my code :

// State to store DataSource
  const [dataSource, setDataSource] = useState<any>(data);

  const handleOnchange = (event: any, props: any) => {
    const newData = [...dataSource];
    const itemIndex = newData.findIndex(
      (item) => item.OrderID === props.OrderID
    );
    newData[itemIndex].Freight = event.target.value;
    setDataSource(newData);
  };

  // Custom Grid Component
  const gridTemplate = (props: any) => {
    const val = props.Freight;
    return (
      <div>
        <input value={val} onChange={(event) => handleOnchange(event, props)} />
      </div>
    );
  };

I’ve already tried changing onChange to onBlur, but no help!

Thanks

3

Answers


  1. If I understand correctly gridTemplate is a component created inside another component.

    The rule is: never ever create component inside another component if it is not necessary to do that. If it is required to do that, use useCallback. Move the inner component gridTemplate outside of your component and pass the things it require as props

    On each render it gets new reference and React thinks it is new component and unmounts the previuos one and mounts the new one

    Login or Signup to reply.
  2. If the value prop is constantly updated with each keystroke, it causes the input field to lose focus because the component is being re-rendered.

    You need to separate the value of the input field from the state and only update the state when necessary.

    Login or Signup to reply.
  3. By looking at the Stackblitz you shared it seems like you’re not integrating Syncfusion right, they don’t allow you to have controlled inputs in their templates because of their internal rendering logic.

    Instead you should setup an event listener using a reference to the grid to listen to changes (keyup) on grid elements and retrieve the changes (input value). Since the input will be uncontrolled (you’re only passing a defaultValue and you don’t control what its current value will be) you won’t have to update its value since it will be updated already (last thing the user typed).

    I adapted the following code from their docs on edition to give you an idea on how to set it up:

    function App() {
        const gridRef = React.useRef<any>() // Keep a reference to the grid, we'll use it in the created function.
        
        const gridTemplate = (props: any) => { // Similar gridTemplate function but just sets a default value and doesn't attach a React event handler, that will be handled on grid creation. 
            return (<div>
          <input id={props.OrderID} defaultValue={props.Freight} className='custemp' type='text'/>
        </div>);
        };
    
        const created = (args: any) => { // This function will be run by Syncfusion on creation
            grid.current.element.addEventListener('keyup', function (e: any) {
                if (e.target.classList.contains('custemp')) { // Based on condition, you can find whether the target is an input element or not.
                    let row = parentsUntil(e.target, 'e-row');
                    let rowIndex = row.rowIndex; // Get the row index.
                    let uid = row.getAttribute('data-uid');
                    let grid = document.getElementsByClassName('e-grid')[0].ej2_instances[0];
                    let rowData = grid.getRowObjectFromUID(uid).data; // Get the row data.
                    rowData.Freight = e.target.value; // Update the new value for the corresponding column.
                    grid.current.updateRow(rowIndex, rowData); // Update the modified value in the row data.
                }
            });
        };
        return <GridComponent dataSource={data} ref={g => gridRef.current = g} height={315} created={created}>
        <ColumnsDirective>
          <ColumnDirective field='OrderID' headerText='Order ID' width='120' textAlign="Right" isPrimaryKey={true}/>
          <ColumnDirective field='OrderDate' headerText='Order Date' width='130' textAlign="Right" format='yMd'/>
          <ColumnDirective field='ShipCountry' headerText='Ship Country' width='140'/>
          <ColumnDirective field='Freight' headerText='Receipt Amount' width='140' template={gridTemplate}/>
        </ColumnsDirective>
      </GridComponent>;
    }
    

    The code was originally written in plain Javascript.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search