简体   繁体   中英

React Native - Redux : Multiple instances of same state in app

I am a newbie in React Native. I am using redux architecture for my react native app however I am facing a problem due to global store state of redux .

Suppose for example, While going forward in the app I am navigating like below. 在此输入图像描述

While back navigating,

在此输入图像描述

According to redux architecture , It is changing the state of every instance of the page present in the navigation stack with the latest state in the store.

Here is the code for the above example,

Page.js [Component]

class Page extends Component{

    componentWillMount(){

    }

    render(){
        var {image,apiCall} = this.props;

        return (
        <View>
            <Image Source={{uri:image}} style={{// style for the image}}>
        </View> 
    )}

    componentDidMount(){
        this.props.apiCall(this.props.route.data.link);   // this.props.route.data.link -> this is just a link for                                                  // the apiCall
    }

    componentWillReceiveProps(){

    }

    shouldComponentUpdate(nextProps, nextState){
        if(this.props.image==nextProps.image){
          return false;
        }
        return true;
    }

    componentWillUpdate(){

    }

    componentDidUpdate(){

    }

    componentWillUnmount(){

    }
}

   const mapStateToProps = (state) => {
     return {
     image: state.PageDataReducer.image
     };
   };

   const mapDispatchToProps = (dispatch) => {
     return {
       apiCall: (link) => {
         dispatch(fetchProduct(link));  // fetchProduct() -> is a function which fetches the product from the                                  // network and dispatches the action.
       },
     };
   };

export default connect(mapStateToProps,mapDispatchToProps)(Page);

fetchProduct() [A function to fetch product]

export function fetchProduct(link) {
  return function(dispatch){
    // fetches the product over network
    dispatch(fetchedProduct(productLink));
  }
}

fetchedProduct [Action]

export const fetchedProduct = (productLink) => {  
  return {
    type: FETCHED_PRODUCT,
    image: image
  };
};

PageDataReducer [Reducer]

export default function PageDataReducer(state = initialState, action) {

   switch (action.type) {

    case FETCHED_PRODUCT:
    var newState = {
      ...state,
      image: action.image
    };
      return newState;

    default:
      return state;
    }
}

My observation : Whenever same page occurs in the navigation and the state in the store of that page gets change then it calls mapStateToProps() of that page the number of times that the page is in the navigation stack . And hence that number of times it loops through the lifecycle methods of that page to change the state according to latest state.
In this example , when I click on the banana in the drawer, it changes the state from mango to banana in the store and mapStateToProps() gets called 3 times (because that page is present 3 times in the navigation stack) and hence all the lifecycle methods of react from componentWillReceiveProps() to componentDidUpdate() gets called 3 times just to change the state of that page according to the latest state .

What I want : I want the different state of the page in the navigation, So that while going back I can see all the different products I have visited.

The problem is obvious according to redux architecture but I am not getting the trick to solve it. Any help or any other work around to achieve my goal would be greatly appreciated.

You should decouple storage of your domain data, such as data about apple, mango, and banana, from storage of your UI state, such as which item is currently selected. In the domain data part you would store all the items that have once been loaded (you may want to later add some garbage collection policy such as least recently used lists to save some memory).

The view components would then connect to both parts of the app state tree: to the UI part to get what is currently selected, and to the domain part to get the details about the selected item.

In your mapStateToProps function first extract the current selection, this has to be an identifier. You may also extract it from somewhere else, eg from the component props (the second argument to mapStateToProps). Then you use that extracted identifier to get the already loaded data from the domain data store. If the data that is selected is not in the store (eg when the user visits the page for the first time, or it has already been garbage-collected), you put empty value into props, and this would mean to componentDidMount or componentWillReceiveProps hooks that they have to make a data load request (it may be implemented as a dispatch of an action that signals the data demand to a saga or a thunk, depending on what you use for managing data loading), while this is happening the render would return some "loading..." stub. When the request finishes, another dispatch would update the domain data store update, which would trigger connect to make another mapStateToProps call, and this would result in discovering that the selected data is already in the store, so no new data load request will be made, and the render will have enough data for display.

What you are trying to do cannot be done with Redux only.

You need to historize in the browser or the app your changes as navigation changes. HistoryJS is used to do that. This module is used by react-router to offers a good UX in web navigation.

So either use react-router to declare different pages ( one for each fruit) or at least use HistoryJS to save navigation state programatically.

I dont know how react-router reacts on native apps, so have a look at React Native Router . It presents a way to handle navigation with Redux on native app .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM