React-Navigation - 与其屏幕组件的标题交互,Failed prop类型

问题描述 投票:6回答:2

我正在关注React-Navigation教程,并被卡在标题为Header interaction with its screen component的部分。教程中的The code在小吃提供的模拟器中运行良好,但我发现在本地运行时遇到以下错误:

Warning: Failed prop type: The prop 'onPress' is marked as required in 'Button', but its value is 'undefined'.

通过更改navigationOptions中的onPress事件分配,我设法使用expo-cli在我的本地机器上运行代码,如下所示(my snack here):

<Button
     onPress={()=>{navigation.getParam('increaseCount')()}}
   //onPress={navigation.getParam('increaseCount')} - as in tutorial
     title="+1"
     color={Platform.OS === 'ios' ? '#fff' : null}
/>

我希望有人可能会深入了解为什么会这样。我检查过,我在本地使用相同版本的Expo(v.32.0)。

App.js列表:

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

class LogoTitle extends React.Component {
  render() {
    return (
      <Image
        source={require('./spiro.png')}
        style={{ width: 30, height: 30 }}
      />
    );
  }
}

class HomeScreen extends React.Component {
  static navigationOptions = ({ navigation }) => {
    return {
      headerTitle: <LogoTitle />,
      headerRight: (
        <Button
          onPress={()=>{navigation.getParam('increaseCount')()}}
          //onPress={navigation.getParam('increaseCount')}
          title="+1"
          color={Platform.OS === 'ios' ? '#fff' : null}
        />
      ),
    };
  };

  componentWillMount() {
    this.props.navigation.setParams({ increaseCount: this._increaseCount });
  }

  state = {
    count: 0,
  };

  _increaseCount = () => {
    this.setState({ count: this.state.count + 1 });
  };

  render() {
    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Text>Home Screen</Text>
        <Text>Count: {this.state.count}</Text>
        <Button
          title="Go to Details"
          onPress={() => {
            /* 1. Navigate to the Details route with params */
            this.props.navigation.navigate('Details', {
              itemId: 86,
              otherParam: 'First Details',
            });
          }}
        />
      </View>
    );
  }
}

class DetailsScreen extends React.Component {
  static navigationOptions = ({ navigation, navigationOptions }) => {
    const { params } = navigation.state;

    return {
      title: params ? params.otherParam : 'A Nested Details Screen',
      /* These values are used instead of the shared configuration! */
      headerStyle: {
        backgroundColor: navigationOptions.headerTintColor,
      },
      headerTintColor: navigationOptions.headerStyle.backgroundColor,
    };
  };

  render() {
    /* 2. Read the params from the navigation state */
    const { params } = this.props.navigation.state;
    const itemId = params ? params.itemId : null;
    const otherParam = params ? params.otherParam : null;

    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Text>Details Screen</Text>
        <Text>itemId: {JSON.stringify(itemId)}</Text>
        <Text>otherParam: {JSON.stringify(otherParam)}</Text>
        <Button
          title="Update the title"
          onPress={() =>
            this.props.navigation.setParams({ otherParam: 'Updated!' })
          }
        />
        <Button
          title="Go to Details... again"
          onPress={() => this.props.navigation.navigate('Details')}
        />
        <Button
          title="Go back"
          onPress={() => this.props.navigation.goBack()}
        />
      </View>
    );
  }
}

const RootStack = createStackNavigator(
  {
    Home: {
      screen: HomeScreen,
    },
    Details: {
      screen: DetailsScreen,
    },
  },
  {
    initialRouteName: 'Home',
    defaultNavigationOptions: {
      headerStyle: {
        backgroundColor: '#f4511e',
      },
      headerTintColor: '#fff',
      headerTitleStyle: {
        fontWeight: 'bold',
      },
    },
  }
);

const AppContainer = createAppContainer(RootStack);

export default class App extends React.Component {
  render() {
    return <AppContainer />;
  }
}
javascript react-native react-navigation expo
2个回答
1
投票

我的猜测是,这不是一个致命的错误,只是一个警告。

无论如何都会发生这种情况。 React Navigation文档状态:

React Navigation不保证您的屏幕组件将在标题之前安装。因为increaseCount参数是在componentDidMount中设置的,所以我们可能没有在navigationOptions中使用它。这通常不会成为问题,因为如果回调为null,onPress for Button和Touchable组件将不会执行任何操作。如果您在此处拥有自己的自定义组件,则应确保其按下处理程序道具的行为与null一致。

因此,navigationOptions函数将被调用两次:

  • 第一次在componentDidMount之前。在这里,getParam将返回undefined
  • componentDidMount之后的第二次。

Button抱怨的是第一次。它不喜欢onPress设置为undefined

你可以用console.lognavigationOptions来检查:

class HomeScreen extends React.Component {
  static navigationOptions = ({ navigation }) => {
    console.log(navigation.getParam('increaseCount'))
    return {
      headerTitle: <LogoTitle />,
      headerRight: (
        <Button
          onPress={()=>{navigation.getParam('increaseCount')()}}
          //onPress={navigation.getParam('increaseCount')}
          title="+1"
          color={Platform.OS === 'ios' ? '#fff' : null}
        />
      ),
    };
  };

在我看来,你的代码是正确的,而文档中的代码只是忽略了这个问题。


0
投票

尝试使用navigation.getavram()而不是navigation.navigate()

© www.soinside.com 2019 - 2024. All rights reserved.