0

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.

Yu Chen
  • 6,540
  • 6
  • 51
  • 86
  • Where are you rendering your `Provider` component that you pass your store to? https://github.com/reactjs/react-redux/blob/master/docs/api.md#provider-store – taylorc93 Feb 21 '18 at 17:31
  • Alternatively, if you can make this code public, a repo to explore would be super helpful – taylorc93 Feb 21 '18 at 17:33
  • @taylorc93 just updated my post to include my `Provider` component code- it's inside my `app.js`. Unfortunately, I can't make this fully public :(, so I'm only limited to sharing bits and pieces. – Yu Chen Feb 21 '18 at 17:39
  • Hmmm, okay. My first thought was that you might have been rerendering the `Provider` (not even sure that's possible but who knows...) but that looks fine. Could you post the full render function for your `ParentContainer`? I only need to see the logic before the return statement, so you can omit the contents of the return for brevity – taylorc93 Feb 21 '18 at 17:47
  • Also, do you have any lifecycle methods on `ParentContainer`? – taylorc93 Feb 21 '18 at 17:47
  • Are you using `Proptypes` in the page where you access ? – Viswanath Lekshmanan Feb 21 '18 at 17:47
  • @taylorc93 I have two lifecycle components on my `ParentContainer`- `componentDidMount` and `componentDidUpdate` (I updated them in the post). And my full `render()` function within `ParentContainer` is literally just what I posted above (this `if` conditional statement and then the `return` value. – Yu Chen Feb 21 '18 at 18:00
  • @ViswanathLekshmanan No. I'm not super familiar with Redux so I did not use `Proptypes`. – Yu Chen Feb 21 '18 at 18:01
  • @YuChen you have to import the `Proptypes` inorder to access the props in the new page. Go through the https://stackoverflow.com/questions/40228481/proptypes-in-react-redux – Viswanath Lekshmanan Feb 21 '18 at 18:06
  • @ViswanathLekshmanan okay. I'll need to look into `Proptypes` further. I thought they only really functioned as a type-checking mechanism. – Yu Chen Feb 21 '18 at 19:12

0 Answers0