Reputation: 31
I have a react component written in typescript that has an input field and a button. The user can type an input and after pressing the button, a table will be populated with the relevant results. I use React.useEffect() to only run the search code if the searchTerm has changed. Running the code inside useEffect() will populate the table rows which then get stored for display in the able component.
export const SearchWindow: React.FC<Props> = props => {
const [searchInput, setSearchInput] = React.useState(''); // text value inside input box
const [searchTerm, setSearchTerm] = React.useState(''); // term to search for (set once search clicked)
const handleSearchInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setSearchInput(event.target.value);
};
React.useEffect(() => {
if (searchTerm.length > 0) {
getSearchResults(props.config, searchTerm).then(async searchResults => {
const rows = searchResults.map(result => {
return {
cells: {
text: result.text,
},
};
});
store.dispatch(setSearchResults(rows));
});
}
}, [searchTerm]); // Only run search if searchTerm changes
// on 1st search, prints blank until another character is typed
console.log(store.getState().documentationIndex.searchResults);
return (
<form>
<input
type='search'
placeholder='Enter Search Term'
onChange={handleSearchInputChange}
value={searchInput}
/>
<<button onClick={() => setSearchTerm(searchInput)}>Search</button>
</form>
<Table
...
...
rows={store.getState().documentationIndex.searchResults}
/>
);
};
// -------------- store code ----------------------------
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
// Reducer
export interface DocumentationIndexState {
searchResults: DataTableRow<TableSchema>[];
}
const initialState: DocumentationIndexState = {
searchResults: [],
};
const store = createSlice({
name: 'documentationIndex',
initialState,
reducers: {
setSearchResults: (state, action: PayloadAction<DataTableRow<TableSchema>[]>) => {
state.searchResults = action.payload;
},
},
});
export default store.reducer;
export const {
setSearchResults,
} = store.actions;
The code behaves as expected except for on the first search. Take the following sequence:
When I print
console.log(store.getState().documentationIndex.searchResults);
right before the return(.... that renders the component, the results are blank after the first search. When I type one more character, the results populate.
I'm at the end of my wits as to why this is happening so any help would be appreciated!
Upvotes: 0
Views: 505
Reputation: 44086
Never use store.getState
in a React component. Use useSelector
const searchResults = useSelector(state => state.documentationIndex.searchResults)
Otherwise your component will not update when the state updates.
Upvotes: 1