Как новый api контекста должен работать с навигатором React Native?

Я создал многоэкранное приложение с помощью React Navigator, следуя этому примеру:

import {
  createStackNavigator,
} from 'react-navigation';

const App = createStackNavigator({
  Home: { screen: HomeScreen },
  Profile: { screen: ProfileScreen },
});

export default App;

Теперь я хотел бы добавить состояние глобальной конфигурации с помощью нового встроенного контекстного API, чтобы я мог имеют некоторые общие данные, которыми можно управлять и отображать на нескольких экранах.

Проблема в том, что для контекста явно требуются компоненты, имеющие общий родительский компонент, поэтому этот контекст можно передать дочерним компонентам.

Как я могу реализовать это с помощью экранов, которые, насколько мне известно, не имеют общего родителя, потому что они управляются навигатором реагирования?


person Tom    schedule 05.07.2018    source источник
comment
Вы можете использовать Redux для управления своим состоянием.   -  person Mahipal    schedule 05.07.2018
comment
Да спасибо. Я знаю о Redux, но предположительно то же самое можно сделать с новым Context api, поэтому я хотел бы сделать это с помощью встроенных функций, а не добавлять внешний пакет только для этого.   -  person Tom    schedule 05.07.2018
comment
Я понимаю, что это на год позже, но я думаю, вы могли бы попробовать сделать это, создав собственный навигатор и передав поставщиков контекста при рендеринге навигатора. Вы можете сослаться на документ, чтобы узнать, как создать собственный навигатор (reactnavigation.org/docs/en/custom-navigators.html). Пожалуйста, вернитесь, если это работает для вас.   -  person maximast    schedule 27.08.2019


Ответы (4)


Вы можете сделать это так.

Создать новый файл: GlobalContext.js

import React from 'react';

const GlobalContext = React.createContext({});

export class GlobalContextProvider extends React.Component {
  state = {
    isOnline: true
  }

  switchToOnline = () => {
    this.setState({ isOnline: true });
  }

  switchToOffline = () => {
    this.setState({ isOnline: false });
  }

  render () {
    return (
      <GlobalContext.Provider
        value={{
          ...this.state,
          switchToOnline: this.switchToOnline,
          switchToOffline: this.switchToOffline
        }}
      >
        {this.props.children}
      </GlobalContext.Provider>
    )
  }
}

// create the consumer as higher order component
export const withGlobalContext = ChildComponent => props => (
  <GlobalContext.Consumer>
    {
      context => <ChildComponent {...props} global={context}  />
    }
  </GlobalContext.Consumer>
);

На index.js оберните корневой компонент компонентом поставщика контекста.

<GlobalContextProvider>
  <App />
</GlobalContextProvider>

Затем на вашем экране HomeScreen.js используйте потребительский компонент вот так.

import React from 'react';
import { View, Text } from 'react-native';
import { withGlobalContext } from './GlobalContext';

class HomeScreen extends React.Component {
  render () {
    return (
      <View>
        <Text>Is online: {this.props.global.isOnline}</Text>
      </View>
    )
  }
}

export default withGlobalContext(HomeScreen);

Вы также можете создать несколько поставщиков контекста, чтобы разделить ваши проблемы и использовать потребителя HOC на нужном вам экране.

person dehamzah    schedule 13.08.2018
comment
Redux - это еще один и лучший способ сделать это. - person Nagibaba; 12.10.2018
comment
Вы должны добавить причины, по которым это лучше, поскольку на данный момент этот комментарий не очень полезен. - person peterrattew; 21.10.2018
comment
@Dede, Спасибо за ваш ответ, но он не полностью касается того, как использовать контекст с React Navigator, как задано в вопросе - person Akshay Vijay Jain; 25.10.2018
comment
Извините, что обескураживаю, согласно моему чтению, я вижу, что передача состояния с одного экрана на другой - единственный возможный вариант, и я использую это состояние, например navigation.state.params - person Akshay Vijay Jain; 25.10.2018
comment
как насчет того, чтобы внедрить props.navigation маршрутизатора в контекст api? - person Abdul-Elah JS; 07.02.2019

Этот ответ учитывает пакет react-navigation.

Вы должны заключить свой App компонент в ContextProvider, чтобы иметь доступ к вашему контексту на обоих экранах.

    import { createAppContainer } from 'react-navigation'
    import { createStackNavigator } from 'react-navigation-stack'
    import ProfileContextProvider from '../some/path/ProfileContextProvider'

    const RootStack = createStackNavigator({
      Home: { screen: HomeScreen },
      Profile: { screen: ProfileScreen },
    });

    const AppContainer = createAppContainer(RootStack)    
    const App = () => {
      return (
      <ProfileContextProvider>
        <AppContainer />
      </ProfileContextProvider>);
    }
person René Michel    schedule 23.11.2019
comment
Ах, это самый близкий из тех, что я нашел. Что произойдет, если вы выполняете рендеринг через switchNavigator? - person barrylachapelle; 09.01.2020

https://wix.github.io/react-native-navigation/docs/third-party-react-context/

Поскольку экраны RNN не являются частью одного и того же дерева компонентов, обновление значений в общем контексте не запускает повторную визуализацию на всех экранах. Однако вы все равно можете использовать дерево компонентов React.Context per RNN screen.

Если вам нужно запустить повторный рендеринг на всех экранах, существует множество популярных сторонних библиотек, таких как MobX или Redux.

person Sjoerd Santema    schedule 15.11.2020

Если вам нужно подробное руководство, вы можете перейти по следующей ссылке: Посетите: https://www.thelearninguy.com/simple-react-native-context-api-detailed

Очень длинный ответ будет следующим.

import React, {Component} from 'react';
import {Text, View, Button} from 'react-native';

//make a new context
const MyContext = React.createContext();

//create provider component
class MyProvider extends Component {
    state = {
        name: "The Learnin Guy",
        age: 50
    };
    increaseAge = () => {
        this.setState({
            age: this.state.age + 1
        });
    };

    render() {
        return (
            <MyContext.Provider
                value={{
                    state: this.state,
                    increaseAge: this.increaseAge
                }}
            >
                {this.props.children}
            </MyContext.Provider>
        );
    }
}

class Person extends Component {
    render() {
        return (
            <View>
                <Text>This is Person Component</Text>
                <MyContext.Consumer>
                    {(context) => (
                        <React.Fragment>
                            <Text>Name: {context.state.age}</Text>
                            <Text>Age: {context.state.age}</Text>
                            <Button title="IncreaseAge" onPress={context.increaseAge} />
                        </React.Fragment>
                    )}
                </MyContext.Consumer>
            </View>
        );
    }
}

class Family extends Component {
    render() {
        return (
            <View>
                <Text>This is Family Component</Text>
                <MyContext.Consumer>
                    {(context) => (
                        <React.Fragment>
                            <Text>Age: {context.state.age}</Text>
                        </React.Fragment>
                    )}
                </MyContext.Consumer>
                <Person/>
            </View>
        );
    }
}

class App extends Component {
    render() {
        return (
            <MyProvider>
                <View>
                    <Text>This is App Component</Text>
                    <MyContext.Consumer>
                        {(context) => (
                            <React.Fragment>
                                <Text>Age: {context.state.age}</Text>
                            </React.Fragment>
                        )}
                    </MyContext.Consumer>
                    <Family/>
                </View>
            </MyProvider>
        );
    }
}

export default App;

Предоставлено: https://www.thelearninguy.com

person Ritesh Chitrakar    schedule 22.06.2019
comment
Это не отвечает на вопрос о том, как использовать контекст с реактивной навигацией. - person Ben Lorantfy; 22.08.2019