0

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} /> ... 
5
  • So you want to run it once on load so the table gets populated? Commented Dec 20, 2022 at 20:13
  • i only want to run the search which then populates the table if the user types an input and then clicks the search button. Commented Dec 20, 2022 at 20:39
  • 1
    This part of the code is strange: getSearchResults(props.config, searchTerm, documentationIndexState, dispatch).then(async searchResults =>. It is weird to call a plain function and pass dispatch as an argument. Probably that should be a thunk that you dispatch. redux.js.org/usage/writing-logic-thunks Commented Dec 20, 2022 at 21:21
  • Your useEffect definitely has some missing dependencies like documentationIndexState and props.config, but just adding those as dependencies will create other problems. Commented Dec 20, 2022 at 21:25
  • Consider having a useCallback that runs the search and calls dispatch. It should be your onClick. Commented Dec 20, 2022 at 22:50

3 Answers 3

1

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>

Sign up to request clarification or add additional context in comments.

1 Comment

this solution did not work, but this does make sense (i think the code is a bit convoluted further down the line)
0

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 

Comments

0

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.