Home > Net >  React and redux not updating component until second re-render
React and redux not updating component until second re-render

Time:12-21

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:

  1. User inputs 'hello' into search input box and clicks 'Search' button.
  2. Search is run successfully but nothing is displayed in the Table component.
  3. User types any random character following 'hello' which already exists in the input box.
  4. Table component is updated with the search results for 'hello' successfully.
  5. User deletes 'hello' from input box and types in 'foobar' then presses 'Search' button.
  6. Search results for 'foobar' are displayed correctly

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!

CodePudding user response:

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.

  • Related