Как передать функции от родителя любым дочерним и дочерним элементам с помощью Navigator и WithSecurityScreen в React Native? - PullRequest
0 голосов
/ 31 января 2020

Я новичок в React Native и пытаюсь понять, как функция, написанная в родительском Компоненте, может передаваться (наследоваться) любым дочерним и дочерним элементам. В частности, я использую библиотеку для интернационализации своего приложения, используя:

import * as RNLocalize from 'react-native-localize'
import i18n from 'i18n-js'

Но я заметил, что мне нужно реализовать функцию translate(...) для каждого компонента всего проекта, и это кажется преувеличенным, потому что это требует много работы для реализации функции перевода (я следовал этого урока ).

Обратите внимание, что у меня есть базовое c понимание того, как передать функцию или некоторые данные, используя this.props , поэтому я не спрашиваю, как props работает от родителя к одному ребенку. Я спрашиваю: как избежать повторения кода от //BEGIN ... до //END... (см. Файл WithSecurityScreen) и чтобы избежать повторения реализации handleLocalizationChange , RNLocalize.addEventListener , RNLocalize.removeEventListener и translate .

Также обратите внимание, что библиотека перевода работает, тест предоставляется на следующей строке WithSecurityScreen:

const SecurityScreen = () => <View><Text>{translate('USER_SURNAME')}?</Text></View>;

Но я не могу передать функцию translate (...) каждому компоненту всего проекта.

Структура проекта:

  • Приложение. js (оборачивает SecureApp. js)
  • SecureApp. js (оборачивается в приложение. js и запускается WithSecurityScreen. js)
  • WithSecurityScreen . js (перенос маршрутов к видам, например, Welcome. js)
  • Welcome. js (основной вид)

Приложение. js

import { withSecurityScreen } from './src/components/withSecurityScreen'

import App from "./SecureApp.js"

export default withSecurityScreen(App);

SecureApp. js

const MainNavigator = createStackNavigator({
    Home: {
        screen: Welcome,
        navigationOptions: {
            headerShown: false
        }
    },
    UserProfile: {
        screen: CoreApp,
        navigationOptions: {
            headerShown: false
        }
    },
    NumPad: {
        screen: NumPad,
        navigationOptions: {
            header: 'PIN Creation',
            headerShown: false
        }
    }, /* , navigationOptions: {headerLeft: () => null} */
    QrScan: {
        screen: QrScan, navigationOptions: {
            header: 'QR Scan',
            headerShown: false
        }
    },
    ...
});

export default createAppContainer(MainNavigator);

WithSecurityScre EN. js

// START: https://heartbeat.fritz.ai/how-to-use-react-native-localize-in-react-native-apps-3bb3d510f801
import * as RNLocalize from 'react-native-localize'
import i18n from 'i18n-js'
import memoize from 'lodash.memoize'
const translationGetters = {
    en: () => require('./../../assets/locales/en/en.json'),
    it: () => require('./../../assets/locales/it/it.json')
};

const translate = memoize(
    (key, config) => i18n.t(key, config),
    (key, config) => (config ? key + JSON.stringify(config) : key)
)

const setI18nConfig = () => {
    const fallback = { languageTag: 'en' }
    const { languageTag } =
    RNLocalize.findBestAvailableLanguage(Object.keys(translationGetters)) ||
    fallback

    translate.cache.clear()

    i18n.translations = { [languageTag]: translationGetters[languageTag]() }
    i18n.locale = languageTag
}
// END: https://heartbeat.fritz.ai/how-to-use-react-native-localize-in-react-native-apps-3bb3d510f801

const SecurityScreen = () => <View><Text>{translate('USER_SURNAME')}?</Text></View>;

const showSecurityScreenFromAppState = appState =>
    ['background', 'inactive'].includes(appState);

const withSecurityScreenIOS = Wrapped => {
    return class WithSecurityScreen extends React.Component {

        constructor(props) {
            super(props)
            setI18nConfig()
        }

        state = {
            showSecurityScreen: showSecurityScreenFromAppState(AppState.currentState)
        };

        componentDidMount() {
            AppState.addEventListener('change', this.onChangeAppState)
            RNLocalize.addEventListener('change', this.handleLocalizationChange)
        }

        componentWillUnmount() {
            AppState.removeEventListener('change', this.onChangeAppState)
            RNLocalize.removeEventListener('change', this.handleLocalizationChange)
        }

        handleLocalizationChange = () => {
            setI18nConfig()
                .then(() => this.forceUpdate())
                .catch(error => {
                    console.error(error)
                })
        }

        onChangeAppState = nextAppState => {
            const showSecurityScreen = showSecurityScreenFromAppState(nextAppState);

            this.setState({showSecurityScreen})
        };

        render() {
            return this.state.showSecurityScreen
                ? <SecurityScreen/>
                : <Wrapped {...this.props} />
        }
    }
};

const withSecurityScreenAndroid = Wrapped => Wrapped;

export const withSecurityScreen = Platform.OS === 'ios'
    ? withSecurityScreenIOS
    : withSecurityScreenAndroid;

Добро пожаловать. js

export default class Welcome extends Component {
    let username = 'UserName';
    render() {
        return (
            <View style={styles.container}>
                <LinearGradient colors={globalStyles.colors.gradientGreen} style={{flex: 1}}>
                    <View style={styles.upperView}><Text style={styles.upperViewText}>{this.props.translate('WELCOME_TEXT')}{this.username}</Text>
                    </View>

                </LinearGradient>
            </View>
        );
    }
}

Я получаю следующую ошибку:

enter image description here

Ответы [ 2 ]

0 голосов
/ 31 января 2020

Прежде всего, в вашем случае вы можете объявить функцию перевода в отдельном js языковом стандарте js и можете объявить все ваши логи перевода c в этом файле и экспортировать функции translate и setI18nConfig

local. js

  import * as RNLocalize from 'react-native-localize'
    import i18n from 'i18n-js'
    import memoize from 'lodash.memoize'
    const translationGetters = {
        en: () => require('./../../assets/locales/en/en.json'),
        it: () => require('./../../assets/locales/it/it.json')
    };

   export const translate = memoize(
        (key, config) => i18n.t(key, config),
        (key, config) => (config ? key + JSON.stringify(config) : key)
    )

   export const setI18nConfig = () => {
        const fallback = { languageTag: 'en' }
        const { languageTag } =
        RNLocalize.findBestAvailableLanguage(Object.keys(translationGetters)) ||
        fallback

        translate.cache.clear()

        i18n.translations = { [languageTag]: translationGetters[languageTag]() }
        i18n.locale = languageTag
    } 

и импортируйте эти функции в свои компоненты, где вы хотите использовать это, как

App. js

import React, { Component } from 'react';
import { View, Text } from 'react-native';
import { setI18nConfig, translate } from './locale';

export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  render() {
    setI18nConfig(); // This should be called only once through out the app at the time of changing locale. 
    return (
      <View>
        <Text> translate ('key_from_json_to_label') </Text>
      </View>
    );
  }
}

Для получения более подробной информации вы можете см. Репо , где я реализовал то же самое.

Надеюсь, это поможет.

0 голосов
/ 31 января 2020

я использую import i18n from "i18next", для перевода. Вот файл конфигурации:


//config/i18n
import i18n from "i18next";
import { reactI18nextModule, initReactI18next } from "react-i18next";
import translationFR from '../translation/fr/translation.json';
import translationEN from '../translation/en/translation.json';
import DeviceInfo from 'react-native-device-info';

let locale = DeviceInfo.getDeviceLocale().substring(0, 2);
if (locale != 'fr') {
  locale = 'en';
}

// the translations
const resources = {
  en: translationEN,
  fr: translationFR,
};

i18n
  .use(reactI18nextModule) // passes i18n down to react-i18next
  .init({
    resources: resources,
    lng: locale,
    fallbackLng: ['en', 'fr'],
    keySeparator: false, // we do not use keys in form messages.welcome
    interpolation: {
      escapeValue: false // react already safes from xss
    }
  });

export default i18n;

Одним из применений является

import i18n from 'config/i18n'

и использование перевода в файле, подобном этому

i18n.t('bottomTab:home_tab')

Вы также можете обернуть компонент с withNamespaces из'act-i18next ', например:


export default withNamespaces([], {wait: true})(Welcome)

, а затем доступ к переводу с помощью:


this.props.t('welcome_message')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...