programing

리액트 기능 컴포넌트의 lodash debouncomponent

instargram 2023. 3. 18. 08:17
반응형

리액트 기능 컴포넌트의 lodash debouncomponent

React Table 컴포넌트 주위에 구축되어 있는 기능 컴포넌트는 서버 측 페이지 설정 및 검색에 Apollo GraphQL 클라이언트를 사용합니다.검색 디버깅을 구현하여 사용자가 해당 값을 입력하지 않게 되면 서버에 대해 하나의 쿼리만 실행되도록 하려고 합니다.lodash debounce멋진 debounce 솔루션을 시도했지만 검색 필드에 입력된 모든 문자에 대해 서버에 대한 쿼리가 실행됩니다.

내 컴포넌트는 다음과 같습니다(관련없는 정보가 수정되었습니다).

import React, {useEffect, useState} from 'react';
import ReactTable from "react-table";
import _ from 'lodash';
import classnames from 'classnames';
import "react-table/react-table.css";
import PaginationComponent from "./PaginationComponent";
import LoadingComponent from "./LoadingComponent";
import {Button, Icon} from "../../elements";
import PropTypes from 'prop-types';
import Card from "../card/Card";
import './data-table.css';

import debounce from 'lodash/debounce';

function DataTable(props) {
    const [searchText, setSearchText] = useState('');
     const [showSearchBar, setShowSearchBar] = useState(false);

    const handleFilterChange = (e) => {
        let searchText = e.target.value;
        setSearchText(searchText);
        if (searchText) {
            debounceLoadData({
                columns: searchableColumns,
                value: searchText
            });
        }
    };

    const loadData = (filter) => {
        // grab one extra record to see if we need a 'next' button
        const limit = pageSize + 1;
        const offset = pageSize * page;

        if (props.loadData) {
            props.loadData({
                variables: {
                    hideLoader: true,
                    opts: {
                        offset,
                        limit,
                        orderBy,
                        filter,
                        includeCnt: props.totalCnt > 0
                    }
                },
                updateQuery: (prev, {fetchMoreResult}) => {
                    if (!fetchMoreResult) return prev;
                    return Object.assign({}, prev, {
                        [props.propName]: [...fetchMoreResult[props.propName]]
                    });
                }
            }).catch(function (error) {
                console.error(error);
            })
        }
    };

    const debounceLoadData = debounce((filter) => {
        loadData(filter);
    }, 1000);

    return (
        <div>
            <Card style={{
                border: props.noCardBorder ? 'none' : ''
            }}>
                {showSearchBar ? (
                        <span className="card-header-icon"><Icon className='magnify'/></span>
                        <input
                            autoFocus={true}
                            type="text"
                            className="form-control"
                            onChange={handleFilterChange}
                            value={searchText}
                        />
                        <a href="javascript:void(0)"><Icon className='close' clickable
                                                           onClick={() => {
                                                               setShowSearchBar(false);
                                                               setSearchText('');
                                                           }}/></a>
                ) : (
                        <div>
                           {visibleData.length > 0 && (
                                <li className="icon-action"><a 
href="javascript:void(0)"><Icon className='magnify' onClick= {() => {
    setShowSearchBar(true);
    setSearchText('');
}}/></a>
                                </li>
                            )}
                        </div>
                    )
                )}
                <Card.Body className='flush'>
                    <ReactTable
                        columns={columns}
                        data={visibleData}
                    />
                </Card.Body>
            </Card>
        </div>
    );
}

export default DataTable

...그 결과는 다음과 같습니다.link

debounceLoadData모든 렌더링의 새로운 기능이 됩니다.후크를 사용하여 렌더링 간에 동일한 기능이 유지되고 예상대로 작동하는지 확인할 수 있습니다.

useCallback(debounce(loadData, 1000), []);

const { useState, useCallback } = React;
const { debounce } = _;

function App() {
  const [filter, setFilter] = useState("");
  const debounceLoadData = useCallback(debounce(console.log, 1000), []);

  function handleFilterChange(event) {
    const { value } = event.target;

    setFilter(value);
    debounceLoadData(value);
  }

  return <input value={filter} onChange={handleFilterChange} />;
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>

Tholle의 답변에 추가: 후크를 최대한 활용하고 싶다면useEffect훅을 사용하여 필터의 변경을 감시하고debouncedLoadData기능을 수행합니다.

const { useState, useCallback, useEffect } = React;
const { debounce } = _;

function App() {
  const [filter, setFilter] = useState("");
  const debounceLoadData = useCallback(debounce(fetchData, 1000), []);

  useEffect(() => {
    debounceLoadData(filter);
  }, [filter]);

  function fetchData(filter) {
    console.log(filter);
  }

  return <input value={filter} onChange={event => setFilter(event.target.value)} />;
}

ReactDOM.render(<App />, document.getElementById("root"));

렌더링 간에 디버깅된 함수를 기억해야 합니다.

단, 사용해서는 안 됩니다.useCallback디버깅된(또는 스로틀된) 기능을 기억하기 위해 사용합니다. useCallback인라인 기능용으로 설계되어 있습니다.

대신 사용useMemo렌더링 간에 디버깅된 기능을 기억하려면:

useMemo(() => debounce(loadData, 1000), []);

이 게시물이 해결책을 찾으시길 바랍니다.

외부 라이브러리를 사용할 필요가 없습니다.자신의 커스텀 훅을 작성할 수 있습니다.다음 절차를 따릅니다.

스텝 (1):- 디버깅의 커스텀훅을 만듭니다.

  
import { useEffect ,useState} from 'react';


export const  UseDebounce = (value,delay)=>{

  const [debouncedValue,setDebouncedValue]= useState();

useEffect(()=>{
let timer = setTimeout(()=>setDebouncedValue(value),delay)


return ()=> clearTimeout(timer);

},[value])

return debouncedValue
}

스텝 (2) :- 스로틀을 추가할 파일을 만듭니다.

import React from 'react'
import { useEffect } from 'react';
import { useState } from 'react';
import {UseDebounce} from "./UseDebounce";



function Test() {
    const [input, setInput] = useState("");
     const debouncedValue = UseDebounce(input,1000);
  
    
    const handleChange = (e)=>{
        setInput(e.target.value)
    }

    useEffect(()=>{
        UseDebounce&& console.log("UseDebounce",UseDebounce)
    },[UseDebounce])
    


  return (
    <div>
    <input type="text" onChange={handleChange} value={input}/>
    {UseDebounce}
    </div>
  )
}

export default Test;

메모:- 이 파일을 테스트하려면 먼저 리액트 앱을 만든 후 내 파일을 받아들입니다.

이 솔루션이 가치 있기를 바랍니다.

언급URL : https://stackoverflow.com/questions/55616536/lodash-debounce-in-react-functional-component-not-working

반응형