简体   繁体   中英

useEffect not tracking a useState dependency properly

I have a button and an input box where upon submitting the input, a search will be run on the searchTerm and a table of results is displayed. I put the searchTerm as a dependency inside useEffect() so that the search will only be run if the searchTerm changes. Since useEffect() gets run when the window is opened, I added a check to see if searchTerm > 0 so the search is not performed when the window is opened.

However by doing this, the table rows are not updated upon the first search but the second search . If I remove the if (searchTerm.length > 0) check, the table will populate as expected on first search (although it will run a search on the empty searchTerm right away which isn't ideal).

export const SearchWindow: React.FC<Props> = props => {

    const documentationIndexState = useSelector((store: StoreState) => store.documentationIndex);
    const dispatch = useDispatch();
    const [searchInput, setSearchInput] = React.useState(''); // value inside input box
    const [searchTerm, setSearchTerm] = React.useState(''); // term to search (set once search clicked)

    React.useEffect(() => {
        console.log('in useEffect with searchTerm len: ' + searchTerm.length);
        if (searchTerm.length > 0) {
            console.log('len > 0, running search');
            getSearchResults(props.config, searchTerm, documentationIndexState, dispatch).then(async searchResults => {
                const rows = searchResults.map(result => {
                    return {
                        cells: {
                            source: documentationIndexState.headerReference.find(x => x.id === result.id)!.source,
                        },
                    };
                });
                dispatch(setSearchResults(rows));
            });
        }
    }, [searchTerm]); // Only run search if searchTerm changes

    return (
        <div>
            <form>
                <input
                    placeholder='Enter Search Term'
                    onChange={e => setSearchInput(e.target.value)}
                    value={searchInput}
                />
                <button
                    onClick={e => {
                        e.preventDefault();
                        setSearchTerm(searchInput);
                    }}
                >
                    Search
                </button>
            </form>
        </div>
        <DataTable
            rows={documentationIndexState.searchResults}
        />
        ...

Is this what you're trying to achieve?

const [loaded, setLoaded] = React.useState(false);
React.useEffect(() => {
    if (!loaded) {
        setLoaded(true);
        return;
    }
    console.log('in useEffect with searchTerm len: ' + searchTerm.length);
    if (searchTerm.length > 0) {
        console.log('len > 0, running search');
        getSearchResults(props.config, searchTerm, documentationIndexState, dispatch).then(async searchResults => {
            const rows = searchResults.map(result => {
                return {
                    cells: {
                        source: documentationIndexState.headerReference.find(x => x.id === result.id)!.source,
                    },
                };
            });
            dispatch(setSearchResults(rows));
        });
    }
}, [searchTerm]); // Only run search if searchTerm changes & loaded is true

The callback for your search button should execute the search.

 function Form() { const [searchInput, setSearchInput] = React.useState(''); const runSearch = React.useCallback( () => { console.info('Searching', searchInput) }, [searchInput] ); return ( <form> <h1> The form. </h1> <input placeholder='Enter Search Term' onChange={e => setSearchInput(e.target;value)} /> <button type="button" onClick={runSearch} > Search </button> </form> ). } ReactDOM.createRoot( document.getElementById('app') ).render( React;createElement(Form) );
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script> <div id="app"> </div>

Ended up adding a if (searchTerm.length === 0) check to inside the getSearchResults() method and had it return [] if true instead of checking len before entering the search method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM