如何将应用程序的当前状态传递给选项卡导航屏幕

How to pass current state of App to Tab Navigation Screen

如果我使用的是 React Navigation v5,将父组件(在我的例子中是主应用程序)的当前状态通过 Tab 和 Stack 导航器向下传递到我的屏幕的最佳方法是什么?想使用当前状态吗?

根据文档,我为每个包含相应屏幕的选项卡创建了一个堆栈导航器。

App.js 包含需要用于一些事情的状态。最重要的是,它将在选项卡导航器上提供徽章计数,并作为其中一个选项卡屏幕上的 Flatlist 数据源。

在选项卡导航器的堆栈导航器中,从 App 一直向下获取子组件的状态的正确方法是什么?

App.js

const Tab = createBottomTabNavigator()

export default class App extends React.Component {
  constructor(props){
    super(props)
    this.state = {
      neededArray: []
    }
  }

  const updateTheArray = (newArray) => {
    this.setState({
      neededArray: newArray
    })
  }

  componentDidMount(){
    //Listener that searches for nearby bluetooth beacons and updates the array with the passed function
    startObserver(updateTheArray)
  }

  componentWillUnmount(){
    stopObserver()
  }

  render(){
    return(
      <NavigationContainer>
        <Tab.Navigator>
          <Tab.Screen
            name = "Home"
            component = { HomeStack }/>
          <Tab.Screen
            name = "About"
            component = { AboutStack }/>

          //The Stack that contains the screen that I need to use the App's state in
          <Tab.Screen
            name = "Nearby"
            component = { NearbyStack }/>
        </Tab.Navigator>
      </NavigationContainer>
    )
  }
}

NearbyStack.js

//This stack holds the screen that I need to use the App's state in

const NearbyStackNav = createStackNav()

const NearbyStack = () => {
  return(
    <NearbyStackNav.Navigator>
      <NearbyStackNav.Screen
        name = "Nearby"
        component = { NearbyScreen }
      />
    </NearbyStackNav.Navigator>
  )
}

NearbyScreen.js

//The screen that I want to use the App's state in
const NearbyScreen = () => {
  return(
    <View>
      <FlatList
        //Where I would like to use the App's state
      />
    </View>
  )
}

您可以将一些初始参数传递给屏幕。如果您在导航到此屏幕时未指定任何参数,则将使用初始参数。它们也与您传递的任何参数浅层合并。可以使用 initialParams 属性指定初始参数:

用法

<Tab.Screen
            name = "Nearby"
            component = { NearbyStack }
            initialParams={{ arrayItem: this.state.neededArray }}
 />

NearbyScreen.js

React.useEffect(() => {
    if (route.params?.arrayItem) {
      // Post updated, do something with `route.params.arrayItem`
      // For example, send the arrayItem to the server
    }
  }, [route.params?.arrayItem]);

我的解决方案是使用 React 的上下文 API。

BeaconContext.js - 新建

import React from 'react'

const BeaconContext = React.createContext()

export default BeaconContext

App.js - 已修改

import BeaconContext from './path/to/BeaconContext'

const Tab = createBottomTabNavigator()

export default class App extends React.Component {
  constructor(props){
    super(props)
    this.state = {
      neededArray: []
    }
  }

  const updateTheArray = (newArray) => {
    this.setState({
      neededArray: newArray
    })
  }

  componentDidMount(){
    startObserver(updateTheArray)
  }

  componentWillUnmount(){
    stopObserver()
  }

  render(){
    return(
      // Wrap the nav container in the newly created context!!!

      <BeaconContext.Provider value = { this.state.neededArray }
        <NavigationContainer>
          <Tab.Navigator>
            <Tab.Screen
              name = "Home"
              component = { HomeStack }/>
            <Tab.Screen
              name = "About"
              component = { AboutStack }/>
            <Tab.Screen
              name = "Nearby"
              component = { NearbyStack }/>
          </Tab.Navigator>
        </NavigationContainer>
      </BeaconContext.Provider>
    )
  }
}

NearbyStack.js - 不变

const NearbyStackNav = createStackNav()

const NearbyStack = () => {
  return(
    <NearbyStackNav.Navigator>
      <NearbyStackNav.Screen
        name = "Nearby"
        component = { NearbyScreen }
      />
    </NearbyStackNav.Navigator>
  )
}

NearbyScreen.js - 已修改

import BeaconContext from './path/to/BeaconContext'

const NearbyScreen = () => {
  return(
    <View>
      //Wrap the component in the new context's consumer!!!

      <BeaconContext.Consumer>
      {
        context => <Text>{ context }</Text>
      }
      </BeaconContext.Consumer>
    </View>
  )
}