【问题标题】:How to fix RN app resetting on change of StateContext using dispatcher in combination with react-native-router-flux如何使用调度程序结合 react-native-router-flux 修复 RN 应用程序在 StateContext 更改时重置
【发布时间】:2019-08-29 21:52:30
【问题描述】:

在我的工作中,我们正在使用 Expo 创建一个 RN 应用程序,我们目前使用 react-navigation 来满足我们的路由需求。我们目前正在尝试迁移到使用 react-native-router-flux,因为它允许 uriPrefix => app Deep Linking 开箱即用,并且似乎是满足我们公司需求的整体更好的解决方案。我们已经查看了 react-native-router-flux repo 中的 Expo 示例代码并进行了相应的操作。

我们遇到的问题是任何时候全局状态更改(我们正在结合 Context API 和 React Hooks 来创建一个位于 App.js 之上的全局 StateProvider。请参阅:https://medium.com/simply/state-management-with-react-hooks-and-context-api-at-10-lines-of-code-baf6be8302c)使用调度程序操作,整个应用程序重置本身并将您带回初始主屏幕。在此之前,我们使用 npm reactn 来管理各种全局状态,因为我们想尝试避免繁重/乏味的 redux 设置。有没有其他人遇到过这样的问题,每次全局状态发生变化时,整个应用程序都会自行刷新(而不是进行 vDOM 比较并仅重新呈现已更改的内容)。使用 react-navigation 进行路由时,我们看不到这种行为。

  const defaultReducer = new Reducer(params);
  return (state, action) => {
    console.log(`reducer: ${action.type} ${action.routeName}`);
    return defaultReducer(state, action);
  };
};

const stateHandler = (prevState, newState, action) => {
  console.log('onStateChange: ACTION:', action);
};

const getSceneStyle = () => ({
  backgroundColor: '#F5FCFF',
  shadowOpacity: 1,
  shadowRadius: 3,
});

const drawerImg = () => {
  return (
    <Image
      source={require('../../assets/images/icon-img.png')}
      style={{
        height: 63,
        width: 63,
        marginLeft: 5,
        marginBottom: 5,
        marginTop: 5,
      }}
    />
  );
};

// on Android, the URI prefix typically contains a host in addition to scheme
const prefix = Platform.OS === 'android' ? 'myApp://myApp/' : 'myApp://';

const transitionConfig = () => ({
  screenInterpolator: StackViewStyleInterpolator.forFadeFromBottomAndroid,
});

export const AppNavigator = React.forwardRef(() => (
  <Router
    createReducer={reducerCreate}
    onStateChange={stateHandler}
    getSceneStyle={getSceneStyle}
    uriPrefix={prefix}
  >
    <Overlay key="overlay">
      <Modal key="modal" hideNavBar transitionConfig={transitionConfig}>
        <Lightbox key="lightbox">
          <Stack
            key="root"
            hideNavBar
            titleStyle={{ alignSelf: 'center' }}
            navigationBarStyle={{ backgroundColor: themeColor }}
          >
            <Drawer
              hideNavBar
              key="drawer"
              onExit={() => {
                console.log('Drawer closed');
              }}
              onEnter={() => {
                console.log('Drawer opened');
              }}
              // drawerImage={drawerImg}
              contentComponent={DrawerContent}
              drawerWidth={300}
            >
              <Scene hideNavBar>
                <Tabs key="tabbar" swipeEnabled>
                  <Scene
                    initial
                    key={`homeStack`}
                    title={`Home`}
                    icon={({ focused }) => (
                      <CustomIcon name="home" size={24} focused={focused} />
                    )}
                  >
                    <Scene key={`homeScreen`} component={HomeScreen} />
                  </Scene>
                  <Scene
                    key={`communityStack`}
                    title={`Communities`}
                    icon={({ focused }) => (
                      <CustomIcon name={`group`} size={24} focused={focused} />
                    )}
                  >
                    <Scene key={`communityList`} component={CommunityList} />
                    <Scene key={`communityFeed`} component={CommunityFeed} />
                  </Scene>
                  <Scene
                    key={`notificationStack`}
                    title={`Notifications`}
                    icon={({ focused }) => (
                      <CustomIcon
                        name={`notifications`}
                        size={24}
                        focused={focused}
                      />
                    )}
                  >
                    <Scene
                      key="notifications"
                      // component={Test}
                      component={NotificationsScreen}
                    />
                  </Scene>
                  <Scene
                    key={`profileStack`}
                    title={`Profile`}
                    icon={({ focused }) => (
                      <CustomIcon name={`profile`} size={20} focused={focused} />
                    )}
                  >
                    <Scene key="profile" component={OwnProfileScreen} />
                  </Scene>
                </Tabs>
              </Scene>
            </Drawer>
          </Stack>
        </Lightbox>
      </Modal>
    </Overlay>
  </Router>
));


// this is what the dispatcher action looks like in componentDidMount of one of the components. 

  componentDidMount = async () => {
    console.log(`mounting homescreen.js`);

    // this causes infinite refresh
    const [_, dispatch] = this.context;

    const storedKeys = await _getAllStoredKeys();
    if (!storedKeys.find(key => key === `currentUser`)) {
      console.log(`no currentUser in cache, redirecting to login`);
    } else {
      var res = await _getStoredItem(`currentUser`);
      dispatch({ type: SET_USER, setUser: res });
    }
  };

当按下选项卡以导航到与 homeStack 屏幕(初始路线)不同的屏幕时,我希望屏幕能够正确渲染和设置,实际发生的是屏幕已安装(通过 console.log() 确认在 componentDidMount()) 中,然后将用户返回到 homeStack 的初始场景。

【问题讨论】:

    标签: reactjs react-native expo react-native-router-flux react-context


    【解决方案1】:

    我们发现 router-flux 的最新 beta 版本 (v4.1.0-beta.x) 似乎不能很好地与 redux(或任何其他类型的状态管理)配合使用,因此决定降低看看这个工程师做了什么,通用链接和深度链接的不同路径:https://blog.bitsrc.io/how-to-react-native-web-app-a-happy-struggle-aea7906f4903

    【讨论】:

      猜你喜欢
      • 2015-11-22
      • 2017-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-26
      • 2017-08-26
      • 1970-01-01
      相关资源
      最近更新 更多