Onchange event is called late as i quickly remove inputs in react

时间:2018-06-04 17:30:12

标签: javascript reactjs api

I have created this simple lorem ipsum generator, it works fine but when i input a number in it and quickly remove that number, there is still some output displayed, note that this does not happen when i remove number slowly

Generator.js

    import React,{Component} from 'react';
import Output from './Output.js';

class Generator extends Component{

    state = {
        sentence: 0,
        para: 0,
        outputsentence:'',
        outputpara:'',
    }

    sentenceHandler = async (e) => {
        await this.setState({sentence: e.target.value});
        if(this.state.sentence === '0' || this.state.sentence === '')
        {
            this.setState({outputsentence:''});
        }
        else{
            try{

                let sentence = await fetch(`https://baconipsum.com/api/?type=all-meat&sentences=${this.state.sentence}&start-with-lorem=1`);            
                sentence = await sentence.json();

                this.setState({outputsentence:sentence});

            } catch(e)
            {
                console.log(e);
            }
        }

    }


    paraHandler = async (e) => {
            await this.setState({para: e.target.value});
            if(this.state.para === '0' || this.state.para === '')
            {
                this.setState({outputpara:''});
            }
            else{
            try{
                console.log(e.target.value);

                let paragraph = await fetch(`https://baconipsum.com/api/?type=all-meat&paras=${this.state.para}&start-with-lorem=1`);            
                paragraph = await paragraph.json();

                this.setState({outputpara:paragraph});

            } catch(e)
            {
                console.log(e);
            }
        }
    }




    render()
    {

        return(
            <div className='tc'>
                <h3>Number of sentences : </h3>
                <input type="number" onChange={this.sentenceHandler}/>
                <Output op={this.state.outputsentence} />
                <h3>Number of paras : </h3>
                <input type="number" onChange={this.paraHandler}/>
                <Output op={this.state.outputpara} />

            </div>
        )
    }
}

export default Generator;

Output.js

    import React from 'react';

const Output = ({op}) => {

    return(
        <div className='tc'>
            <p>
                {op}
            </p>     
        </div>
    )
}

export default Output;

It works fine but suppose i enter a number 12 and quickly remove it using backspaces then still it shows 1 line or para and this does not happen if i remove it one letter that is first 2 then 1 slowly.

see it on https://wizardly-torvalds-092022.netlify.com/

1 个答案:

答案 0 :(得分:1)

You have race conditions. Because the asynchronous fetch/display operation has no cancellation mechanism in place, nothing's going to stop the operation from completing after you start another operation (by changing the output to something else).

There are probably some good libraries to deal with this cleanly, but here's how you could go about doing it manually. You'll need the concept of a "request ID" so you know whether the currently-running operation is the latest request versus something you should cancel.

class Generator extends Component {
  state = {
    sentence: 0,
    outputsentence: '',
    currentSentenceRequestId: null,

    para: 0,
    outputpara:'',
    currentParaRequestId: null,
  }

  sentenceHandler = async (e) => {
    var requestId = this.state.currentSentenceRequestId++;

    await this.setState({
      sentence: e.target.value,
      currentSentenceRequestId: requestId
    });

    if(this.state.sentence === '0' || this.state.sentence === '') {
      this.setState({ outputsentence: '' });
    } else{
      try {
        let sentence = await fetch(`https://baconipsum.com/api/?type=all-meat&sentences=${this.state.sentence}&start-with-lorem=1`);            
        sentence = await sentence.json();

        // Ignore if a newer request has come in
        if (this.state.currentSentenceRequestId !== requestId) {
          return;
        }

        this.setState({ 
          outputsentence: sentence
        });
      } catch(e) {
        console.log(e);
      } finally {
        this.setState({ 
          currentSentenceRequestId: null
        });
      }
    }
  }

  // ...
}