1

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;
  • Does this answer your question? [useState set method not reflecting change immediately](https://stackoverflow.com/questions/54069253/usestate-set-method-not-reflecting-change-immediately) – Emile Bergeron Sep 15 '21 at 14:10

2 Answers2

4

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

Ryan Le
  • 7,708
  • 1
  • 13
  • 23
  • thanks:) this will work but is this a correct way? Or is there a certain way to make an input component? – Okay Beydanol Sep 15 '21 at 14:17
  • 1
    In your case, this is the correct way, I'm not super sure about what are you trying to implement further on your component, but if it's a pure Input component, the onClick prop is passed straight to the parent without having its own state. – Ryan Le Sep 15 '21 at 14:19
  • 1
    Which mean that you don't need another state inside your `Input` component if you want it to be a purely Input component. Only a state on the parent component is all good. – Ryan Le Sep 15 '21 at 14:20
  • yea I want purely Input component if you have time can you show a example? – Okay Beydanol Sep 15 '21 at 14:25
  • Yes, I have updated it in the codesanbox. Pretty strange forward, you just need to remove all the handler and state in the child component. See if it fit your needs. – Ryan Le Sep 15 '21 at 14:30
  • I understand thanks a lot. 'Pretty strange forward' what do you mean by that my english little weak sorry :( – Okay Beydanol Sep 15 '21 at 14:38
  • Sorry, It was `straightforward` :D My English is even weaker – Ryan Le Sep 15 '21 at 14:39
0

you are trying to access value just before it actually set

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

The value setValue will not set the value immediately to the variable. it will only be set on the next render.

either you can do this

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

Or

(Best method)

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

So on every value change it will call your props function

sojin
  • 2,158
  • 1
  • 10
  • 18
  • this yellow errors what is at mean ? React Hook useEffect has a missing dependency: 'props'. Either include it or remove the dependency array. However, 'props' will change when *any* prop changes, so the preferred fix is to destructure the 'props' object outside of the useEffect call and refer to those specific props inside useEffect.eslintreact-hooks/exhaustive-deps – Okay Beydanol Sep 15 '21 at 14:18