Search code examples
reactjsinputreact-hookscomponentsuse-state

React Input component it always comes one step behind


I ran into a small problem, can you help? I'm trying to make an input component, but when I enter something in the input, it always comes one step behind. is this a correct way? Or is there a certain way to make an input component?

This is Input.js

import React, { useState } from 'react';

function Input(props) {
  const [value, setValue] = useState('');
  const { type, className, placeholder } = props;

  let handleChange = (e) => {
    setValue(e.target.value);
    props.onChange(value);
  };

  return (
    <>
      <div className='input-group mb-3'>
        <input
          onChange={handleChange}
          type={type == null ? 'text' : type}
          value={value == null ? '' : value}
          className={className == null ? 'form-control' : className}
          placeholder={placeholder == null ? '' : placeholder}
        />
      </div>
    </>
  );
}

export default Input;

This is App.js

import React, { useState } from 'react';

import Input from './components/Input/Input';
function App(props) {
  const [d, setC] = useState([]);

  function onChangeValue(e) {
    setC(e);
    console.log(e);
  }

  return (
    <>
      <div className='container'>
        <div className='row'>
          <Input onChange={onChangeValue}></Input>
          <span>{d}</span>
        </div>
      </div>
    </>
  );
}

export default App;

Solution

  • It's because you set props.onChange by your component's state, which is only available on the next render

    Because Reactjs setState is batching and asynchronous, it will wait for the evenHanlder to be finished then update the state.

    If you want it to immediately reflect changes from the input, use value from the input itself like so:

    let handleChange = (e) => {
      setValue(e.target.value);
      props.onChange(e.target.value);  //<-- Use e.target.vale instead of value
    };
    

    Working Example:

    Edit bold-breeze-11w49