Edit: I didn't provide all pieces of code to keep this post from being extremely long, but please do let me know what other info/code snippets I need to provide to give context.
I'm a React / Redux beginner attempting to use Redux to store certain state variables as the user navigates from a SearchForm component to a ResultsTable component- Both of these components are wrapped in a ParentContainer component. I'm finding that my Redux store is reset every time I update my ParentContainer to re-render a child component.
My render function for ParentContainer looks likes this:
if (this.state.currentPage === "search"){
content = <ResultsTable searchResults={this.props.searchResults}/>
} else if (this.state.currentPage === "search_form"){
content = <SearchForm/>}
return(
<div>
<Header/>
{content}
<FooterPanel/>
</div>
);
Essentially, I'm using some conditional logic to pick which component to render between my Header and Footer components. My search form has a text input and radio buttons to determine what type of search to perform:
<form id="search-form" className="form" action="/auth/search" method="post">
<input type="text" id="search" className="text-input" name="search" placeholder="search stuff here"/>
<div className="radio">
<label>
<input type="radio" name="searchType" value="first"
checked={this.state.selectedOption === 'first'}
onChange={this.handleOptionChange} />
First Search Type
</label>
</div>
<div className="radio">
<label>
<input type="radio" name="searchType" value="second"
checked={this.state.selectedOption === 'second'}
onChange={this.handleOptionChange} />
Second Type of Search
</label>
</div>
<div>
<button type="submit" onClick={this.handleSearchClick} className="button">Search</button>
</div>
</form>
I've also connected my SearchForm, ParentContainer, and Header with my Redux store:
const mapStateToProps = (state)=> {
return {
searchResults: state.searchResults,
searchType: state.searchType
}
}
export default connect(mapStateToProps)(SearchForm);
My configureStore.js:
export default () => {
const store = createStore(
combineReducers({
searchResults: SearchResultReducer,
searchType: searchTypeReducer,
})
);
return store;
}
The issue I'm encountering is that my searchType state variable does not persist when I transition from SearchForm to ResultsTable. I need that variable to determine what type of output (a chart, table, etc.) to render.
When I click between my different radio buttons on SearchForm, I see that my store state is indeed being updated (using Chrome developer tools console):
searchResults:[]
searchType: {searchType: "first", searchText: "DefaultText"}
I'm using a handleSearchClick() handler for my onClick button event:
handleSearchClick(event){
console.log("Search Button clicked")
this.setState(()=>{
return{
loading: true,
selectedOption: this.state.selectedOption
}
})
this.props.dispatch(setSearchType(this.state.selectedOption));
}
However, once I click the search button, get my results from the backend, and render ResultsTable, my state is once again reset to DefaultType
:
searchResults:[...results]
searchType: {searchType: "DefaultType", searchText: "DefaultText"}
I am almost certain it has to do with these two outputs in my Developer console:
Inside search result reducer
search-results.js?337d:9 {type: "@@redux/INIT"}type: "@@redux/INIT"__proto__: Object
search-results.js?337d:25 DEFAULT CALLED
search-results.js?337d:8 Inside search result reducer
search-results.js?337d:9 {type: "@@redux/PROBE_UNKNOWN_ACTION_5.z.q.e.6.d"}type: "@@redux/PROBE_UNKNOWN_ACTION_5.z.q.e.6.d"__proto__: Object
search-results.js?337d:25 DEFAULT CALLED
search-type.js?0d78:8 Inside search type reducer...
search-type.js?0d78:9 {type: "@@redux/INIT"}
search-type.js?0d78:8 Inside search type reducer...
search-type.js?0d78:9 {type: "@@redux/PROBE_UNKNOWN_ACTION_s.n.0.x.n.k"}
It looks like Redux is recreating my store every time I update my ParentContainer. This StackOverflow post says that Redux store will reset when a page is reloaded, but I'm not reloading a page- I'm only re-rendering a child component within ParentContainer. Moreover, my searchTypeReducer should be returning the default state object, which should contain the selected radio button value from SearchForm:
const searchTypeReducer = (state = searchTypeDefaultState, action) => {
console.log("Inside search type reducer...")
console.log(action)
switch(action.type){
case 'SET_SEARCH_TYPE':
console.log("SEARCH TYPE SETTING")
return {
...state,
searchType: action.searchType
};
case 'SET_SEARCH_TEXT':
console.log("SEARCH TEXT SETTING");
return {
...state,
searchText: action.searchType
}
default: // Redux upon initialization of the store should go here! But my state is already defined!
console.log("Search type default called!")
return state;
}
}
I'm rendering my Provider within my app.js file:
const jsx = (
<Provider store={store}>
<AppRouter/>
</Provider>
)
ReactDOM.render(jsx, document.getElementById('parentContainer'));
I have componentDidMount
and componentDidUpdate
for my ParentContainer
, although please note that a lot of the code is debugging console.log()
statements as I was trying to figure out what was going on:
componentDidUpdate(prevProps,prevState){
console.log("COMPONENT UPDATED");
console.log("THIS IS MY CURRENT STATE")
console.log(store.getState());
}
componentDidMount(){
console.log("Parent Container was loaded.");
// I added this sessionStorage item in later as a workaround for now
var searchType = sessionStorage.getItem("searchType")
console.log("Parent container props: ", this.props);
let jsonResults = this.processSearchResults(searchResults);
console.log("Current searchResults: ", jsonResults)
var arrayResults = this.createSearchResultArray(jsonResults)
console.log("Inside parent container, checking props!")
console.log(this.props)
for (var result in arrayResults){
switch(searchType){
case "first":
this.props.dispatch(addFirst({...arrayResults[result]}));
case "second":
this.props.dispatch(addSecond({...arrayResults[result]}))
}
}
console.log(this.props);
}
Is there any way to suppress Redux from resetting my store when I re-render my ParentContainer?
Or is the best technique here to use Local Storage?
Second edit:
I also solved this problem extremely easily by simply storing my selected radio button option in local storage:
handleSearchClick(event){
console.log("Search Button clicked")
localStorage.setItem("searchType", this.state.selectedOption);
}
And then calling localStorage.getItem("searchType")
from my ResultsTable component class.
But I'd still love to understand if conceptually there is a way to do this in Redux.