【问题标题】:Weird behavior of Redux thunk in a React Native appReact Native 应用程序中 Redux thunk 的奇怪行为
【发布时间】:2019-05-07 16:37:40
【问题描述】:

我最近注意到我的应用程序中 Redux 的一个非常奇怪的行为,我想与你分享。当我在设置中单击此 TouchableOpacity 以断开连接时,出现以下错误:

TypeError: 无法读取属性 first_name of null

来自 Homepage.js

所以我的代码正在为我不应该去的页面中的那个组件触发一个错误。

Homepage.js

<AppText textStyle={styles.title}>
  Welcome {userReducer.infos.first_name}
</AppText>

应该发生的工作流程是用户单击断开连接按钮,然后调用 tryLogout 函数,该函数触发类型为“LOGOUT”的操作。然后此操作设置为空用户相关数据和信息以及一些额外的布尔值。状态得到更新,然后应该重新渲染 UI 并调用 componentWillUpdate()。在那里,我检查我的状态以将用户重定向到登陆/未连接导航。

我尝试在我的 reducer 和我的代码处理中评论 infos: null 没有错误。

这个变量在我的应用程序中没有要求重定向到任何页面。

调试起来可能看起来很复杂,因为问题肯定比看起来更深。无论如何,也许有人已经遇到过类似的问题,所以我在这里为您提供尝试解决问题的潜在要素。

Settings.js

import { tryLogout } from '@actions/user'

const mapDispatchToProps = dispatch => ({
  tryLogout: () => dispatch(tryLogout()),
})

class Settings extends React.Component<Props, State> {  

  // What should normally happen
  componentDidUpdate(prevProps: Props) {
      const { userReducer, navigation } = this.props

      if (
        prevProps.userReducer.isSignedUp !== userReducer.isSignedUp ||
        prevProps.userReducer.isLoggedIn !== userReducer.isLoggedIn
      ) {
        if (!userReducer.isSignedUp && !userReducer.isLoggedIn) {
          navigation.navigate('Landing')
        }
      }
    }

  // Inside my render() method
  <AppTouchableOpacity
          onPress={() => tryLogout()}
          style={styles.touchableOpacity}
        >
          Disconnect
  </AppTouchableOpacity>
}

actions/user.js

export const tryLogout = (): Function => (dispatch: Function) => {
  const logout = () => ({
    type: LOGOUT,
  })

  dispatch(logout())
}

reducers/user.js

case LOGOUT:
  return {
    ...state,
    data: null,
    infos: null,
    isLoggedIn: false,
    isSignedUp: false,
  }

App.js(我正在使用 React Navigation)

const LandingScenes = {
  Welcome: { screen: WelcomeScreen },
  { /* Some other screens */ }
}

const LandingNavigator = createStackNavigator(LandingScenes, {
  initialRouteName: 'Welcome',
  defaultNavigationOptions: {
    header: null,
  },
})

const SecuredScenes = {
  Homepage: { screen: HomepageScreen },
  Settings: { screen: SettingsScreen },
  { /* Some other screens */ }
}
const SecuredNavigator = createStackNavigator(SecuredScenes, {
  initialRouteName: 'Homepage',
  defaultNavigationOptions: {
    header: null,
  },
})

export default createAppContainer(
  createSwitchNavigator(
    {
      Landing: LandingNavigator,
      Secured: SecuredNavigator,
    },
    {
      initialRouteName: 'Landing',
    }
  )
)

【问题讨论】:

    标签: javascript reactjs react-native redux react-navigation


    【解决方案1】:

    当 'infos' 的值为 null 时,听起来像是在尝试渲染。

    这是有道理的,因为主屏幕仍然存在于主内存中,在您的导航堆栈中,这是因为您在导航到设置时使用了“导航”方法。

    所以这是使用 react-navigation,而不是 redux 或 redux thunk 的结果。

    要在您的视图中处理这种错误情况,除非定义了 infos,否则您无法呈现文本。就像下面的例子,你当然可以显示一个加载器,或者如果 infos 是 undefined/null 的话,而不是什么都没有,甚至是默认消息。

    真的,这里的最终答案是重构您的导航。您可以查看使用不同的方法导航到设置页面,这会重置堆栈导航器,或者将其保留在视图中,两者都是理想的。

    比如看看replace方法,这个是用来重置导航栈的,甚至看看switch navigator,它只显示一个屏幕(其中一个屏幕可以是一个堆栈导航器,即多个屏幕)一次,在您的应用中创建上下文之间的分离。

    {userReducer.infos && (
         <AppText textStyle={styles.title}>
           Welcome {userReducer.infos.first_name}
         </AppText>
    )}
    

    【讨论】:

    • 这可能是一个修复,但我应该使用此代码离开设置而不是内部,为什么我的主页代码会被处理?是不是我误会了?
    • 当您使用堆栈导航器时,当“导航”到新页面时,新页面只会被放入堆栈中。 IE。前一个屏幕仍在内存中,只是不在堆栈顶部(导航器)。希望这有某种意义。
    • 作为测试看看发生了什么,在两个页面的 componentWillUnmount 方法中放置一个日志,并在它们之间导航,注意日志(或缺少)。查看文档了解堆栈导航器的生命周期 (reactnavigation.org/docs/en/…)
    • 你说得对,你知道任何可能更适合我的目的的替代方案还是我应该更新我的思维过程哈哈?
    • 更新思维过程。看看 switch navigator,我用它来在我的应用程序中保持上下文分离,例如公共(登录、注册等页面)和私有(主页等),并且这两个上下文都是切换导航器内的堆栈导航器。绝对值得一读您的用例 (IMO) PS 的切换导航器,更新了我的答案,使其更加清晰(昨晚喝了很多啤酒,仍在恢复中!)。
    【解决方案2】:

    如果我理解正确,问题是在用户注销时不会加载Homepage 组件,而是在infos 上抛出null 错误。由于您使用的是堆栈导航器,因此您的主页组件很可能实际上仍安装在堆栈中。您需要处理 Homepage 中的 null 案例,或者在导航到 Settings 期间将其从堆栈中删除。

    您可以在此处的文档中找到有关 react-navigation 生命周期的更多详细信息:Navigation lifecycle - Example scenario,重要部分在这里:

    我们从 HomeScreen 开始并导航到 DetailsS​​creen。然后我们使用标签栏切换到 SettingsScreen 并导航到 ProfileScreen。完成这一系列操作后,所有 4 个屏幕都已安装

    【讨论】:

    • 我知道了,谢谢你的帮助!那么这是我的用例的推荐方法吗?我不认为堆栈中的那些屏幕仍然“活跃”。
    猜你喜欢
    • 2020-06-19
    • 2016-12-11
    • 2021-05-05
    • 2019-01-30
    • 1970-01-01
    • 1970-01-01
    • 2021-07-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多