【问题标题】:React Navigation - How to pass data across different screens in TabNavigator?React Navigation - 如何在 TabNavigator 中跨不同屏幕传递数据?
【发布时间】:2018-10-28 23:31:34
【问题描述】:

我有一个 TabNavigator,每个选项卡中都有一个 StackNavigator。在 StackNavigator 内部,我有屏幕。每个 Tab 中的屏幕不直接相互调用; TabNavigator 处理按下选项卡时的屏幕变化。

在第一个选项卡中,如果用户单击一个按钮,则会创建一些数据。如果用户随后导航到第二个选项卡,我想将此数据传递到第二个选项卡中的屏幕。

下面是代码演示:

import React from 'react';
import { Button, Text, View } from 'react-native';
import {
  createBottomTabNavigator,
  createStackNavigator,
} from 'react-navigation';


class HomeScreen extends React.Component {
  doIt = () => {
    this.props.navigation.setParams({results: ['one', 'two']});   // <--- set data when user clicks button.
  }

  render() {
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
        {/* other code from before here */}
        <Button
          title="Set Results"
          onPress={this.doIt}
        />
      </View>
    );
  }
}

class SettingsScreen extends React.Component {
  render() {

    console.log(this.props.navigation);  // <--- console out when user clicks on this tab

    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
        <Text>Settings</Text>
      </View>
    );
  }
}

const HomeStack = createStackNavigator({
  Home: HomeScreen,
});

const SettingsStack = createStackNavigator({
  Settings: SettingsScreen,
});

export default createBottomTabNavigator(
  {
    Home: HomeStack,
    Settings: SettingsStack,
  },
  {
  }
);

this.props.navigation.state.params 永远不会在第二个选项卡中获取数据results。它甚至没有密钥,所以如果我尝试访问this.props.navigation.state.params.results,它将是未定义的。

这很令人困惑,因为我认为 props.navigationpassed to all screens automatically

如何通过 TabNavigator 将数据从一个屏幕传递到另一个屏幕,只使用 react-navigation?我已经看到说要使用 Redux 的答案,但如果我只想在不同的反应导航器中跨屏幕保持一些状态,我不想导入另一个库。

【问题讨论】:

    标签: react-native react-navigation


    【解决方案1】:

    this.props.navigation.state.params 好像只能老一个参数?可能吗?试试这个:

        doIt = () => {
        this.props.navigation.setParams({results: 'one'});   // <--- set data when user clicks button.
      }
    
    
    console.log(this.props.navigation.state.params.results);
    

    【讨论】:

    • 我不明白为什么导航道具不能容纳多个值,但我还是尝试了它并没有解决它。 props.navigation 对象中仍然缺少密钥。
    • @tempomax 嗯,您实际上是在切换屏幕还是全部在一个文件上?
    【解决方案2】:

    在不同选项卡之间传递数据时设置道具不起作用。我什至尝试使用 AsyncStorage,尝试在不同的选项卡中保存和检索它们。

    我最终使用 Redux 来保存我的状态,并且到目前为止效果很好。

    【讨论】:

      【解决方案3】:

      我遇到了类似的问题。我有一个多页表单,客户坚持将每个步骤都包含在选项卡栏上的选项卡中。我使用 react 导航 createMaterialTopTabNavigator 创建导航器,但找不到在选项卡之间传递表单数据的简单方法。

      我最终做的是使用 react 的 Context API 并将选项卡导航器包装在一个根表单容器中,该容器为导航器和内部路由提供上下文值。这是我的做法:

      根表单容器

      // MultiScreenForm.js
      imports...
      import MultiScreenFormNavigator from './MultiScreenFormNavigator'
      
      export const FormContext = React.createContext()
      
      class MultiScreenForm extends Component {
        constructor(props) {
          super(props)
          this.state = {
            // formDataHere
            formUpdaters: {
                 onToggleOptIn: this.handleToggleOptIn // example updater method
                 // other
              }
            }
         }
          handleToggleOptIn = () => {
          // toggle opt in form data with this.setState
        }
      
        render() {
          return (
            <FormContext.Provider value={this.state}>
              <MultiScreenFormNavigator />
            </FormContext.Provider>
          )
        }
      }
      
      export default MultiScreenForm
      

      示例表单页面

      // ProfileForm.js
      imports...
      import { FormContext } from './MultiScreenForm'
      
      class ProfileForm extends Component {
        render() {
          // FormContext.Consumer uses function as child pattern
          return (
            <FormContext.Consumer>
              { (context) => (
                   // our form can now use anything that we pass through the context
                   // earlier, we passed the root form's state including an updater
                   <button onPress={context.formUpdaters.onToggleOptIn} />
                   // ...
                )
              }
            </FormContext.Consumer>
          )
        }
      }
      
      export default ProfileForm
      

      标签导航器

      // MultiScreenFormNavigator.js
      imports...
      import ProfileForm from './ProfileForm'
      import { createMaterialTopTabNavigator } from 'react-navigation'
      
      const MultiScreenFormNavigator = createMaterialTopTabNavigator(
        {
          Profile: ProfileForm,
          // AnotherForm: AnotherForm
        },
        // { navigator options here... }
      )
      
      export default MultiScreenFormNavigator
      

      然后我们直接渲染 MultiScreenForm 而不是选项卡导航器。

      这对我有用,但我觉得应该有一种更简单的方法来做到这一点。我希望阅读本文的人可以分享他们的方法。

      【讨论】:

        【解决方案4】:

        @tempomax 尝试使用 AsyncStorage 进行相同操作,但数据延迟传入。 如果你的应用很小,有时你就不需要 Redux。

        所以试图找到一种方法没有 Redux。 这是我想出的

        我希望现在回答还为时不晚。 通过 NavigationEvents 并将 params 设置为 Route 解决了这个问题。

        选项卡的问题是您不能将参数传递给屏幕,因为如果在非活动的 TabBar 按钮上滑动或单击 createMaterialTopTabNavigator,navigation.navigate 将自动触发。

        这可以通过如下所示的 NavigationEvent 来解决。

            import React from 'react';
            import { View } from 'react-native';
            import { NavigationEvents } from 'react-navigation';
        
            const MyScreen = () => (
              <View>
                <NavigationEvents
                  onWillFocus={payload => console.log('will focus',payload)}
                  onDidFocus={payload => console.log('did focus',payload)}
                  onWillBlur={payload => 
                     /*
                      if screen is about to change this will be triggred
                      In screen 'MyScreen2' you can get it with navigation.params
                     */
                      this.props.navigation.navigate('MyScreen2', { name: 'Brent' })
                  }
                  onDidBlur={payload => console.log('did blur',payload)}
                />
                {/* 
                  Your view code
                */}
              </View>
            );
        
            export default MyScreen;
        

        现在您可以在 MyScreen2 中获取数据

         /* 2. Get the param, provide a fallback value if not available */
        const { navigation } = this.props;
        const itemId = navigation.getParam('name', 'DefaultName');
        const otherParam = navigation.getParam('otherParam', 'some default value');
        

        【讨论】:

          【解决方案5】:

          如果您使用带有 DrawerNavigation 的 React Native Navigation 版本 5.x,您可以使用

          在屏幕 1 中:

           <Button
                      onPress={() => { 
                      this.props.navigation.navigate(<ScreenNameOfDrawerScreen>,
          {screen:'<ScreenNameInTabDrawer>',params:{your_json_Data}});
                                  }} />
          

          在屏幕 2 中:

            ............
               render() {
              
              if(this.props.route.params!=undefined){
                      if(this.props.route.params.your_json_Data!=null){
                       //    Use this.props.route.params.your_json_Data. It is your json data.
           }
                    
              }
                
                    
                      return (
              ..............
          

          【讨论】:

            猜你喜欢
            • 2020-10-17
            • 2018-03-13
            • 1970-01-01
            • 2018-02-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多