programing

입력하는 동안 ReactJs가 변경 시 지연

procenter 2023. 2. 11. 17:15
반응형

입력하는 동안 ReactJs가 변경 시 지연

사용자가 입력하는 문자열을 유지하기 위해 상태를 변경해야 합니다.그러나 사용자가 입력을 멈출 때까지 작업을 지연시키고 싶습니다.하지만 어떻게 둘 다 할 수 있는지 정확히 짚어낼 수가 없어요.

따라서 사용자가 입력을 중지하면 액션을 트리거하고 싶지만 그 전에는 트리거하지 않습니다.좋은 의견이라도 있나?

리액트 후크 및 기능 구성 요소 포함

하려면 , 「 」를 합니다.useState후크를 눌러 사용자가 입력하는 텍스트를 저장합니다.그런 다음 입력 값에 해당 상태를 지정합니다. 꼭 '나', '나'를 하세요.setState onChange이치노그렇지 않으면 입력 값은 변경되지 않습니다.

, 「」를 합니다.useEffectsetTimeout 「 」, 「 」를 합니다.useEffectuseEffect후크 및 의존관계 배열에 입력값과 함께 변수를 지정합니다.「 」에 .useEffect 사용해야 한다setTimeout원하는 지연 시간 후에 액션을 트리거합니다.,, 음, 음, 음, 음, 음, 음에 .useEffect는 타임아웃 세트를 클리어하는 정리 함수를 반환해야 합니다.이렇게 하면 더 이상 사용자와 관련이 없는 입력 값에 대한 작업이 수행되지 않습니다.

아래는 위의 단계를 사용하여 사용자가 입력하는 문자열을 표시하도록 하고 사용자가 입력을 멈춘 후 500ms 후에 완료된 문자열을 표시하는 앱의 간단한 예입니다.

function App() {
  const [query, setQuery] = useState("");
  const [displayMessage, setDisplayMessage] = useState("");

  useEffect(() => {
    const timeOutId = setTimeout(() => setDisplayMessage(query), 500);
    return () => clearTimeout(timeOutId);
  }, [query]);

  return (
    <>
      <input
        type="text"
        value={query}
        onChange={event => setQuery(event.target.value)}
      />
      <p>{displayMessage}</p>
    </>
  );
}

사용할 필요가 있는 사운드setTimeout사용자가 텍스트를 입력하는 즉시 타이머를 시작합니다.사용자가 다른 문자를 입력한 경우 타이머를 재시작합니다.타이머가 완료되기 전에 사용자가 다시 입력하지 않으면 체크박스를 전환하는 작업이 실행됩니다.

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      text: '',
      checked: false
    };
    this.timer = null;
  }
  
  componentDidUpdate (prevProps, prevState) {
    if(prevState.text !== this.state.text) {
      this.handleCheck();
    }
  }
  
  onChange = e => {
    this.setState({
      text: e.target.value
    });
  };
  
  handleCheck = () => {
    // Clears running timer and starts a new one each time the user types
    clearTimeout(this.timer);
    this.timer = setTimeout(() => {
      this.toggleCheck();
    }, 1000);
  }
  
  toggleCheck = () => {
    this.setState( prevState => ({ checked: !prevState.checked }));
  }
  
  render () {
    return (
      <div>
        <input value={this.state.text} onChange={this.onChange} placeholder="Start typing..." /><br/>
        <label>
          <input type="checkbox" checked={this.state.checked} onChange={this.toggleCheck} />
          Toggle checkbox after user stops typing for 1 second
        </label>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

중는 당신의 '자신에게'에게 '자신'은 '자신'입니다.onChange핸들러는 다음 두 가지 기능을 수행합니다.

  • 상태를 즉시 업데이트하는 기능
  • 디버깅된 함수

코드 예:

import debounce from 'lodash.debounce';

class Foo extends React.Component {
  constructor() {
    super()

    this.state = {
      value: ''
    }

    // Delay action 2 seconds
    this.onChangeDebounced = debounce(this.onChangeDebounced, 2000)
  }

  handleInputChange = (e: Event) => {
    // Immediately update the state
    this.setState({
      value: e.target.value
    })

    // Execute the debounced onChange method
    this.onChangeDebounced(e)
  }

  onChangeDebounced = (e: Event) => {
    // Delayed logic goes here
  }

  render() {
    return (
      <input onChange={this.handleInputChange} value={this.state.value} />
    )
  }
}

리액트 후크 및 기능 구성 요소 포함

const [timer, setTimer] = useState(null);

function changeDelay(change) {
    if (timer) {
      clearTimeout(timer);
      setTimer(null);
    }
    setTimer(
      setTimeout(() => {
        console.log(change);
      }, 3000)
    );
}

입력

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

리액트 훅 포함 - useRef

const timer = useRef(null)
    
useEffect(() => {
    
    clearTimeout(timer.current)
    timer.current = setTimeout(() => {
     // your logic
    },1000)
    
},[value])

첫 번째 경우를 제외한 모든 상태 업데이트를 호출합니다.

저도 같은 요.setTimeout하는 데 이 될 것 .ref「이것들」은 다음과 같습니다.

import React, {useState, useEffect, useRef} from "react";

const Search = () => {
    const filterRef = useRef(); // use ref to call the API call all time except first time
    const [serpQuery, setSerpQuery] = useState('');

    useEffect(() => {
        let delayTimeOutFunction;

        if(!filterRef.current) {
            filterRef.current = true;

        } else { // componentDidMount equivalent
            delayTimeOutFunction = setTimeout(() => {
                console.log('call api: ', serpQuery)
            }, 700); // denounce delay
        }
        return () => clearTimeout(delayTimeOutFunction);
    }, [serpQuery]);

    return (
      <input value={serpQuery} onChange={e => setSerpQuery(e.target.value)} />
    );
};

이 목적을 위해 특별히 커스텀훅을 작성하여 useState 훅과 같이 사용할 수 있습니다.이건 jnforja의 대답의 연장선상에 더 가깝습니다.

import { useEffect, useState } from "react";
const useDebounce = (initialValue = "", delay) => {
  const [actualValue, setActualValue] = useState(initialValue);
  const [debounceValue, setDebounceValue] = useState(initialValue);
  useEffect(() => {
    const debounceId = setTimeout(() => setDebounceValue(actualValue), delay);
    return () => clearTimeout(debounceId);
  }, [actualValue, delay]);
  return [debounceValue, setActualValue];
};

export default useDebounce;

지연값이 있는 useState 훅과 동일하게 사용합니다.

const [value, setValue] = useDebounce('',1000)

필요에 따라서, 이 문서를 참조해, 실장에 대해 설명할 수도 있습니다.

onChange 이벤트를 디바운스할 수 있습니다(사용자가 onChange 이벤트를 입력하면 실행되지 않습니다).

경고 - 렌더에 함수를 만드는 것은 잘못된 작업 방식입니다.나는 해결책을 설명하기 위해 그것을 했다.보다 안전한 해결책은 디버깅된 핸들러를 생성자에 작성하는 클래스 컴포넌트를 사용하는 것입니다.

class DebouncedInput extends React.Component {
  constructor() {
    super();

    // Creating the debouncedOnChange to avoid performance issues

    this._debouncedOnChange = _.debounce(
      this.props.onChange, 
      this.props.delay
    );
  }

  render () {
    const { onChange, delay, ...rest } = this.props;
    return (
      <input onChange={this._debouncedOnChange} {..rest} />
    )
  }
}

다음 예

function DebouncedInput (props) {
  const { onChange, delay = 300, ...rest } = props;
 
  
  return (
    <input 
      {...rest}
      onChange={ _.debounce(onChange, delay)}
    />
  )
}

function App() {
  return (
    <div>
      <DebouncedInput 
        type="text"
        placeholder="enter"
        delay={2000}
        onChange={() => console.log('changing')}
      />
    </div>
  )
}

ReactDOM.render(
  <App/>,
  document.querySelector('#app')
);
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.4.2/umd/react.production.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.4.2/umd/react-dom.production.min.js"></script>
</head>
<body>
 <div id="app"></div>
</body>
</html>

콜 변경 핸들러 함수의 지연에는 debounce 및 lodash 라이브러리의 throttle을 사용할 수 있습니다.다음 코드는 debounce를 기반으로 합니다.스로틀 기능에도 동일한 코드를 사용할 수 있습니다.데바운스: X밀리초 이후까지 함수 호출 지연 스로틀: X밀리초마다 최대 1회 함수를 호출합니다.

샘플 코드:

import React,{useEffect, useState, useMemo} from "react"
import debounce from "lodash.debounce";

export default function App() {
  const [search, setSearch] = useState("");
  const handleChangeSearch = ({ target }) => {
    setSearch(target.value);    
  };
  const debouncedChangeHandler = useMemo(
    () => debounce(handleChangeSearch, 500),
    []
  );

  useEffect(() => {
    return () => {
      debouncedChangeHandler.cancel();
    }
  }, []);

  return (
    <div className="App">      
      <label > Search:
      <input sx={{ display: { xs: "none", md: "block" } }}
        onChange={debouncedChangeHandler}
        name="search"
        type="text"
        placeholder="search..."
      />
      </label >
    </div>
  );
}

이 건에 대해 npm 패키지를 작성했습니다.제공된 훅을 사용하여 즉시값과 지연값을 모두 얻을 수 있습니다.

https://www.npmjs.com/package/use-delayed-search

언급URL : https://stackoverflow.com/questions/53071774/reactjs-delay-onchange-while-typing

반응형