React-Navigation-标头与其屏幕组件的交互,失败的道具类型

时间:2019-02-19 01:27:43

标签: javascript react-native react-navigation expo

我正在关注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事件分配(如下所示,my snack here)来使用expo-cli在本地计算机上运行代码:

<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 />;
  }
}

2 个答案:

答案 0 :(得分:1)

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

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

  

React Navigation不保证您的屏幕组件将在标题之前安装。由于递增计数参数是在componentDidMount中设置的,因此我们可能无法在navigationOptions中使用它。这通常不会有问题,因为如果回调为null,则onPress for Button和Touchable组件将不执行任何操作。如果您在此处拥有自己的自定义组件,则应确保其行为符合预期,其新闻处理程序属性为null。

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

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

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

您可以使用console.log中的navigationOptions进行检查:

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}
        />
      ),
    };
  };

我认为您的代码是正确的,而文档中的代码只是忽略了此问题。

答案 1 :(得分:0)

尝试代替navigation.getParam()来使用navigation.navigate()