3

I am trying to capture the moment when the user stops typing in the controlled input. It happens so smooth inside the uncontrolled component.

When I have tried with setTimeout, only the last character came as an input rest all were not inputted. I am not sure why it happened

import React, { Component } from "react";
import ReactDOM from "react-dom";
import {connect} from 'react-redux';

import "./styles.css";

class Main extends Component{
  state={}

  timeout = null;

  onChange = e => {
    this.props.handleInputChange(e.target.value);
  }

  render(){
    return (
      <div className="Main">
        <input type='text' value={this.props.val} onChange={this.onChange}/>
      </div>
    );
  }
}

const mapStateToProps = state => {
  val: state.reducer.val
}

const mapDispatchToProps = dispatch => {
  handleInputChange: (val)=>dispatch(reducer.changeInput(val))
}

connect(mapStateToProps,mapDispatchToProps)(Main);

when User stops typing, it should dispatch changeInput action

vam
  • 492
  • 7
  • 17
  • provide your code attempt to solve the issue, we can take a look and see what's wrong with it – Federkun Aug 18 '19 at 17:37
  • Well, I have got up to this point! I am trying to dispatch `CHANGE_INPUT` action as soon as the user stops typing. https://codesandbox.io/s/redux-example-ii9tx – vam Aug 18 '19 at 18:00
  • Please take a look at the above link – vam Aug 18 '19 at 18:01

1 Answers1

11

You can do that with something like this:


const App = () => {
  const [value, setValue] = React.useState('')

  React.useEffect(() => {
    const timeout = setTimeout(() => {
      store.dispatch({ type: "CHANGE_INPUT", val: value });
    }, 2000)

    // if this effect run again, because `value` changed, we remove the previous timeout
    return () => clearTimeout(timeout)
  }, [value])

  return (
    <input
      type="text"
      value={value}
      onChange={(e) => setValue(e.target.value)}
    />
  )
}

Everytime the value state change, the useEffect function will run. A timeout will start, that can be cancelled if the value change again before the setTimeout function is executed ( after 2 seconds in my example ).

Federkun
  • 36,084
  • 8
  • 78
  • 90
  • Can you please elaborate on the differences between my code and your code? Are they both not one and the same except that the code you gave is written in React hooks? – vam Aug 18 '19 at 18:19
  • Your example throw a `TypeError`, so I cannot really compare. I was hoping to get the version where you had the "only the last character came as an input rest"-problem. – Federkun Aug 18 '19 at 18:22
  • I am confused with the `value`. If I receive value inside input from the reducer props, how will the code change? I mean `const App = (value) => ...` – vam Aug 18 '19 at 18:34
  • `const App = ({ valueFromRedux }) => { const [value, setValue] = React.useState(valueFromRedux')`, rest is the same. – Federkun Aug 18 '19 at 18:40
  • I have tried this, it works but my previous functionality breaks! https://stackoverflow.com/questions/57543914/set-input-values-on-receiving-changed-prop-from-redux?noredirect=1#comment101551331_57543914 – vam Aug 18 '19 at 18:52
  • another code sandbox that replicate the new issue will help me; you can also open another question for that – Federkun Aug 18 '19 at 18:55
  • @Fedurkun, please check the code sandbox. As soon as the user stops typing I am trying to update the input value in reducer state. But only the last character is getting into the input box. I am not sure, why setTimeout is blocking it. https://codesandbox.io/s/react-redux-input-example-45y2d – vam Aug 19 '19 at 07:27
  • This is much more clear sandbox I have got up to. Please look into this! https://codesandbox.io/s/update-the-input-when-user-stops-typing-reactredux-45y2d – vam Aug 19 '19 at 13:08
  • 1
    https://codesandbox.io/s/update-the-input-when-user-stops-typing-reactredux-d037g – Federkun Aug 19 '19 at 13:24
  • may I know the reason why you have to change the props to state? – vam Aug 19 '19 at 15:34
  • 1
    you have two state there: the one that live in redux (and is updated every 500ms), and the one that's local (and that should be updated instantaneously). You want to display the instant one in the textbox, because you don't want to wait 500ms after each key press for see the result, and then every 500ms keep it in sync with the one in redux. – Federkun Aug 19 '19 at 15:47
  • That sounds reasonable! However, if I ever want to set the value of the input to a different value when some actions are dispatched like undo(`ctrl+z`), what is the best possible ways to sync up the props to state? – vam Aug 20 '19 at 03:10
  • Awesome, cool! I have used `componentWillRecieveProps` but keeping in mind that it will be deprecated from v17, I will move my logic to `componentDidMount`. Thanks Federkun!!!! :) – vam Aug 20 '19 at 04:15