프로그래밍 언어/HTML,CSS,JS

React.js에서 debounce 수행

Rateye 2021. 7. 15. 10:24
728x90
반응형

 

질문 : React.js에서 디 바운스 수행

React.js에서 디 바운스를 어떻게 수행합니까?

handleOnChange를 디 바운스하고 싶습니다.

debounce(this.handleOnChange, 200) 시도했지만 작동하지 않습니다.

function debounce(fn, delay) {
  var timer = null;
  return function() {
    var context = this,
      args = arguments;
    clearTimeout(timer);
    timer = setTimeout(function() {
      fn.apply(context, args);
    }, delay);
  };
}

var SearchBox = React.createClass({
  render: function() {
    return <input type="search" name="p" onChange={this.handleOnChange} />;
  },

  handleOnChange: function(event) {
    // make ajax call
  }
});
답변

이것은 내가이 문제를 해결하는 방법의 가장 최신 버전입니다. 다음을 사용합니다.

이것은 초기 배선이지만 기본 블록을 직접 구성하고 있으며 한 번만 수행하면되는 사용자 지정 후크를 만들 수 있습니다.

// Generic reusable hook
const useDebouncedSearch = (searchFunction) => {

  // Handle the input text state
  const [inputText, setInputText] = useState('');

  // Debounce the original search async function
  const debouncedSearchFunction = useConstant(() =>
    AwesomeDebouncePromise(searchFunction, 300)
  );

  // The async callback is run each time the text changes,
  // but as the search function is debounced, it does not
  // fire a new request on each keystroke
  const searchResults = useAsync(
    async () => {
      if (inputText.length === 0) {
        return [];
      } else {
        return debouncedSearchFunction(inputText);
      }
    },
    [debouncedSearchFunction, inputText]
  );

  // Return everything needed for the hook consumer
  return {
    inputText,
    setInputText,
    searchResults,
  };
};

그런 다음 후크를 사용할 수 있습니다.

const useSearchStarwarsHero = () => useDebouncedSearch(text => searchStarwarsHeroAsync(text))

const SearchStarwarsHeroExample = () => {
  const { inputText, setInputText, searchResults } = useSearchStarwarsHero();
  return (
    <div>
      <input value={inputText} onChange={e => setInputText(e.target.value)} />
      <div>
        {searchResults.loading && <div>...</div>}
        {searchResults.error && <div>Error: {search.error.message}</div>}
        {searchResults.result && (
          <div>
            <div>Results: {search.result.length}</div>
            <ul>
              {searchResults.result.map(hero => (
                <li key={hero.name}>{hero.name}</li>
              ))}
            </ul>
          </div>
        )}
      </div>
    </div>
  );
};

여기서 실행되는이 예제를 찾을 수 있으며 자세한 내용은 react-async-hook 문서를 읽어야합니다.

백엔드가 쓸모없는 요청으로 넘쳐나는 것을 피하기 위해 종종 API 호출을 디 바운스하려고합니다.

2018 년에는 콜백 (Lodash / Underscore) 작업이 나쁘고 오류가 발생하기 쉽습니다. 임의의 순서로 해결되는 API 호출로 인해 상용구 및 동시성 문제가 발생하기 쉽습니다.

나는 당신의 고통을 해결하기 위해 React를 염두에두고 작은 라이브러리를 만들었습니다 : awesome-debounce-promise .

이것은 그것보다 더 복잡해서는 안됩니다 :

const searchAPI = text => fetch('/search?text=' + encodeURIComponent(text));

const searchAPIDebounced = AwesomeDebouncePromise(searchAPI, 500);

class SearchInputAndResults extends React.Component {
  state = {
    text: '',
    results: null,
  };

  handleTextChange = async text => {
    this.setState({ text, results: null });
    const result = await searchAPIDebounced(text);
    this.setState({ result });
  };
}

디 바운스 된 기능은 다음을 보장합니다.

  • API 호출이 취소됩니다.
  • 디 바운스 된 함수는 항상 약속을 반환합니다.
  • 마지막 호출의 반환 된 약속 만 해결됩니다.
  • 단일 this.setState({ result }); API 호출마다 발생합니다.

결국 구성 요소가 마운트 해제되면 다른 트릭을 추가 할 수 있습니다.

componentWillUnmount() {
  this.setState = () => {};
}

Observable (RxJS)도 입력 디 바운싱에 적합 할 수 있지만 올바르게 배우고 사용하기 어려울 수있는 더 강력한 추상화입니다.

여기서 중요한 부분은 구성 요소 인스턴스 당 단일 디 바운스 (또는 조절) 함수를 만드는 것 입니다. 매번 디 바운스 (또는 스로틀) 기능을 다시 생성하고 싶지 않으며 여러 인스턴스가 동일한 디 바운스 된 기능을 공유하는 것을 원하지 않습니다.

정말 관련이 아니에요 나는이 대답에 디 바운싱 기능을 정의하고 있지 않다, 그러나이 대답은 완벽하게 잘 작동합니다 _.debounce 밑줄 또는 lodash의,뿐만 아니라 사용자가 제공 한 디 바운싱 기능.

디 바운스 된 함수는 상태 저장이므로 구성 요소 인스턴스 당 하나의 디 바운스 된 함수 를 만들어야합니다.

ES6 (클래스 속성) : 권장

class SearchBox extends React.Component {
    method = debounce(() => { 
      ...
    });
}

ES6 (클래스 생성자)

class SearchBox extends React.Component {
    constructor(props) {
        super(props);
        this.method = debounce(this.method.bind(this),1000);
    }
    method() { ... }
}

ES5

var SearchBox = React.createClass({
    method: function() {...},
    componentWillMount: function() {
       this.method = debounce(this.method.bind(this),100);
    },
});

JsFiddle 참조 : 3 개의 인스턴스가 인스턴스 당 1 개의 로그 항목을 생성합니다 (전역 적으로 3 개를 생성 함).

var SearchBox = React.createClass({
  method: function() {...},
  debouncedMethod: debounce(this.method, 100);
});

작동하지 않습니다. 클래스 설명 객체 생성 중에 this 자체적으로 생성 된 객체가 아니기 때문입니다. this.method this 컨텍스트가 객체 자체가 아니기 때문에 예상 한 것을 반환하지 않습니다 (실제로 실제로 존재하지 않는 BTW는 방금 생성됨).

var SearchBox = React.createClass({
  method: function() {...},
  debouncedMethod: function() {
      var debounced = debounce(this.method,100);
      debounced();
  },
});

this.method 를 호출하는 디 바운스 된 함수를 효과적으로 생성하고 있습니다. 문제는 모든 debouncedMethod 호출에서 다시 생성하므로 새로 생성 된 debounce 함수는 이전 호출에 대해 아무것도 알지 못합니다! 시간이 지남에 따라 동일한 디 바운스 된 함수를 재사용해야합니다. 그렇지 않으면 디 바운싱이 발생하지 않습니다.

var SearchBox = React.createClass({
  debouncedMethod: debounce(function () {...},100),
});

이것은 여기서 약간 까다 롭습니다.

클래스의 마운트 된 모든 인스턴스는 동일한 디 바운스 된 기능을 공유하며 대부분의 경우 이것이 원하는 것이 아닙니다!. JsFiddle 참조 : 3 개의 인스턴스가 전 세계적으로 1 개의 로그 항목 만 생성합니다.

각 구성 요소 인스턴스에서 공유하는 클래스 수준의 단일 디 바운스 함수가 아닌 각 구성 요소 인스턴스에 대해 디 바운스 된 함수를 만들어야합니다.

이것은 우리가 종종 DOM 이벤트를 디 바운스하거나 스로틀하기를 원하기 때문에 관련됩니다.

React에서는 콜백에서 수신하는 이벤트 객체 (예 : SyntheticEvent )가 풀링됩니다 (이제 문서화 됨 ). 즉, 이벤트 콜백이 호출 된 후 수신 한 SyntheticEvent가 GC 압력을 줄이기 위해 빈 속성으로 풀에 다시 배치됩니다.

따라서 SyntheticEvent 속성에 비동기식으로 원래 콜백에 액세스하면 (조절 / 디 바운스의 경우처럼) 액세스 한 속성이 지워질 수 있습니다. 이벤트를 풀에 다시 넣지 않으려면 persist() 메서드를 사용할 수 있습니다.

onClick = e => {
  alert(`sync -> hasNativeEvent=${!!e.nativeEvent}`);
  setTimeout(() => {
    alert(`async -> hasNativeEvent=${!!e.nativeEvent}`);
  }, 0);
};

두 번째 (비동기)는 이벤트 속성이 정리 hasNativeEvent=false

onClick = e => {
  e.persist();
  alert(`sync -> hasNativeEvent=${!!e.nativeEvent}`);
  setTimeout(() => {
    alert(`async -> hasNativeEvent=${!!e.nativeEvent}`);
  }, 0);
};

제 2 회 (비동기)가 인쇄됩니다 hasNativeEvent=true 때문에이 persist 하면 풀의 이벤트 등을 넣어 피할 수 있습니다.

다음 두 가지 동작을 테스트 할 수 있습니다. JsFiddle

스로틀 / 디 바운스 함수와 함께 persist() 를 사용하는 예제에 대한 Julen의 답변 을 읽으십시오.

출처 : https://stackoverflow.com/questions/23123138/perform-debounce-in-react-js
728x90
반응형