14

我收到错误:

Invariant Violation:withNavigation 只能用于导航器的视图层次结构。被包装的组件无法从 props 或 context 访问导航

我不知道为什么,因为我withNavigation在我的应用程序的其他组件中使用它并且它有效。我看不出它所作用的组件与导致错误的组件有什么不同。

代码:

组件:

const mapStateToProps = (state: State): Object => ({
  alertModal: state.formControls.alertModal
})

const mapDispatchToProps = (dispatch: Dispatch<*>): Object => {
  return bindActionCreators(
    {
      updateAlertModalHeight: updateAlertModalHeight,
      updateAlertModalIsOpen: updateAlertModalIsOpen,
      updateHasYesNo: updateAlertModalHasYesNo
    },
    dispatch
  )
}

class AlertModalView extends Component<AlertModalProps, State> {
  render(): Node {
    return (
      <View style={alertModalStyle.container}>
        <PresentationalModal
          style={presentationalModalStyle}
          isOpen={this.props.alertModal.isOpen}
          title={this.props.alertModal.title}
          navigation={this.props.navigation}
          updateHasYesNo={this.props.updateHasYesNo}
          message={this.props.alertModal.message}
          updateAlertModalHeight={this.props.updateAlertModalHeight}
          viewHeight={this.props.alertModal.viewHeight}
          hasYesNo={this.props.alertModal.hasYesNo}
          yesClicked={this.props.alertModal.yesClicked}
          updateAlertModalIsOpen={this.props.updateAlertModalIsOpen}
        />
      </View>
    )
  }
}

// $FlowFixMe
const AlertModalViewComponent = connect(
  mapStateToProps,
  mapDispatchToProps
)(AlertModalView)

export default withNavigation(AlertModalViewComponent)

堆栈导航器:

import React from 'react'
import { View, SafeAreaView } from 'react-native'
import Icon from 'react-native-vector-icons/EvilIcons'
import Add from '../product/add/view'
import Login from '../user/login/view'
import Search from '../product/search/query/view'
import { Image } from 'react-native'
import { StackNavigator, DrawerNavigator, DrawerItems } from 'react-navigation'

const AddMenuIcon = ({ navigate }) => (
  <View>
    <Icon
      name="plus"
      size={30}
      color="#FFF"
      onPress={() => navigate('DrawerOpen')}
    />
  </View>
)

const SearchMenuIcon = ({ navigate }) => (
  <Icon
    name="search"
    size={30}
    color="#FFF"
    onPress={() => navigate('DrawerOpen')}
  />
)

const Stack = {
  Login: {
    screen: Login
  },
  Search: {
    screen: Search
  },
  Add: {
    screen: Add
  }
}


const DrawerRoutes = {
  Login: {
    name: 'Login',
    screen: Login
  },
  'Search Vegan': {
    name: 'Search',
    screen: StackNavigator(Stack.Search, {
      headerMode: 'none'
    }),
    navigationOptions: ({ navigation }) => ({
      drawerIcon: SearchMenuIcon(navigation)
    })
  },
  'Add vegan': {
    name: 'Add',
    screen: StackNavigator(Stack.Add, {
      headerMode: 'none'
    }),
    navigationOptions: ({ navigation }) => ({
      drawerIcon: AddMenuIcon(navigation)
    })
  }
}

const CustomDrawerContentComponent = props => (
  <SafeAreaView style={{ flex: 1, backgroundColor: '#3f3f3f', color: 'white' }}>
    <View>
      <Image
        style={{
          marginLeft: 20,
          marginBottom: 0,
          marginTop: 0,
          width: 100,
          height: 100,
          resizeMode: 'contain'
        }}
        square
        source={require('../../images/logo_v_white.png')}
      />
    </View>
    <DrawerItems {...props} />
  </SafeAreaView>
)

const Menu = StackNavigator(
    {
      Drawer: {
        name: 'Drawer',
        screen: DrawerNavigator(DrawerRoutes, {
          initialRouteName: 'Login',
          drawerPosition: 'left',
          contentComponent: CustomDrawerContentComponent,
          contentOptions: {
            activeTintColor: '#27a562',
            inactiveTintColor: 'white',
            activeBackgroundColor: '#3a3a3a'
          }
        })
      }
    },
    {
      headerMode: 'none',
      initialRouteName: 'Drawer'
    }
  )


export default Menu

在这里,我渲染了StackNavigatorMenu的应用程序组件中的内容:

import React, { Component } from 'react'
import Menu from './menu/view'
import Props from 'prop-types'
import { Container } from 'native-base'
import { updateAlertModalIsOpen } from './formControls/alertModal/action'
import AlertModalComponent from './formControls/alertModal/view'
import UserLoginModal from './user/login/loginModal/view'

class Vepo extends Component {
  componentDidMount() {
    const { store } = this.context
    this.unsubscribe = store.subscribe(() => {})
    store.dispatch(this.props.fetchUserGeoCoords())
    store.dispatch(this.props.fetchSearchQueryPageCategories())
    store.dispatch(this.props.fetchCategories())
  }

  componentWillUnmount() {
    this.unsubscribe()
  }

  render(): Object {
    return (
      <Container>
        <Menu store={this.context} />
        <AlertModalComponent
          yesClicked={() => {
            updateAlertModalIsOpen(false)
          }}
        />

        <UserLoginModal />
      </Container>
    )
  }
}
Vepo.contextTypes = {
  store: Props.object
}

export default Vepo

和我的根组件:

export const store = createStore(
  rootReducer,
  vepo,
  composeWithDevTools(applyMiddleware(createEpicMiddleware(rootEpic)))
)

import NavigationService from './navigationService'

export const App = () => (
  <Provider store={store}>
      <Vepo
        fetchUserGeoCoords={fetchUserGeoCoords}
        fetchSearchQueryPageCategories={fetchSearchQueryPageCategories}
        fetchCategories={fetchCategories}
      />
  </Provider>
)
AppRegistry.registerComponent('vepo', () => App)

我已将我的 Vepo 组件更改为此以实现 vahissan 的答案:

import React, { Component } from 'react'
import Menu from './menu/view'
import Props from 'prop-types'
import { Container } from 'native-base'
import { updateAlertModalIsOpen } from './formControls/alertModal/action'
import AlertModalComponent from './formControls/alertModal/view'
import UserLoginModal from './user/login/loginModal/view'

import NavigationService from './navigationService'

class Vepo extends Component {
  componentDidMount() {
    const { store } = this.context
    this.unsubscribe = store.subscribe(() => {})
    store.dispatch(this.props.fetchUserGeoCoords())
    store.dispatch(this.props.fetchSearchQueryPageCategories())
    store.dispatch(this.props.fetchCategories())
  }

  componentWillUnmount() {
    this.unsubscribe()
  }

  render(): Object {
    return (
      <Container>
        <Menu
          store={this.context}
          ref={navigatorRef => {
            NavigationService.setTopLevelNavigator(navigatorRef)
          }}>
          <AlertModalComponent
            yesClicked={() => {
              updateAlertModalIsOpen(false)
            }}
          />
        </Menu>
        <UserLoginModal />
      </Container>
    )
  }
}
Vepo.contextTypes = {
  store: Props.object
}

export default Vepo

没有错误,但 alertModal 不再显示

4

4 回答 4

15

在 react-navigation 中,主 StackNavigator 创建一个上下文提供者,navigation如果组件树中低于其级别的任何组件使用上下文使用者,则该道具将可用。

使用上下文使用者访问navigation道具的两种方法是将组件添加到 StackNavigator,或者使用withNavigation函数。然而,由于 React 的 context API 是如何工作的,任何使用withNavigation函数的组件都必须位于组件树中的 StackNavigator 之下。

如果无论组件树中的位置如何,您仍想访问navigationprop,则必须将 ref 存储到模块中的 StackNavigator。遵循 react-navigation 的指南将帮助您做到这一点https://reactnavigation.org/docs/en/navigating-without-navigation-prop.html

于 2018-10-13T20:00:47.787 回答
5

如果您使用的是 react-navigation 版本 5,请使用带有功能组件的 useNavigation 挂钩。这个钩子将导航对象注入到功能组件中。这是文档的链接:

https://reactnavigation.org/docs/use-navigation/

于 2020-04-16T14:31:37.190 回答
0

Vahissan 的回答是正确的,但我无法让它工作,因为我的代码与https://reactnavigation.org/docs/en/navigating-without-navigation-prop.html存在各种差异,比如我的 stackNavigator 不是一个组件,它是只是一个对象。

我设法做的是让AlertModal组件成为 stackNavigator 的子组件,从而通过将它添加到我的 ContentComponent来接收navigation道具。StackNavigator代码如上,但CustomDrawerContentComponent只是让它像这样:

const CustomDrawerContentComponent = props => (
  <SafeAreaView style={{ flex: 1, backgroundColor: '#3f3f3f', color: 'white' }}>
    <View>
      <Image
        style={{
          marginLeft: 20,
          marginBottom: 0,
          marginTop: 0,
          width: 100,
          height: 100,
          resizeMode: 'contain'
        }}
        square
        source={require('../../images/logo_v_white.png')}
      />
    </View>
    <DrawerItems {...props} />

    <AlertModalComponent
          yesClicked={() => {
            updateAlertModalIsOpen(false)
          }}
        />
  </SafeAreaView>
)
于 2018-10-13T23:54:21.173 回答
0

对于任何可能感兴趣的人,您需要 npm install @react-navigation/native @react-navigation/compat @react-navigation/stack 以使 withNavigation 在最新版本中工作

于 2021-01-04T16:41:51.180 回答