【问题标题】:How to pass functions from parent to any children and sub-children using Navigator and WithSecurityScreen in React Native?如何在 React Native 中使用 Navigator 和 WithSecurityScreen 将函数从父级传递给任何子级和子级?
【发布时间】:2020-01-31 14:27:46
【问题描述】:

我是 React Native 的新手,我正在尝试了解如何将在父组件中编写的函数传递(继承)给任何子组件和子子组件。特别是我正在使用一个库来国际化我的应用程序:

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

但我注意到我必须为整个项目的每个组件实现translate(...)函数,这似乎被夸大了,因为实现翻译功能需要大量工作(我遵循this tutorial)。

请注意,我对如何使用 this.props 传递函数或某些数据有基本的了解,所以我不是在询问 props 如何从父级工作给一个孩子。我要问的是:如何避免重复从//BEGIN ...//END... 的代码(请参阅WithSecurityScreen 文件)并避免重复执行handleLocalizationChangeRNLocalize.addEventListener RNLocalize.removeEventListenertranslate

另请注意,翻译库可以正常工作,在 WithSecurityScreen 的以下行提供测试:

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

但我无法将 translate(...) 函数传递给整个项目的每个组件。

项目结构为:

  • App.js(包装 SecureApp.js)
  • SecureApp.js(包装在 App.js 中并运行 WithSecurityScreen.js)
  • WithSecurityScreen.js(包装到视图的路由,例如 Welcome.js)
  • Welcome.js(主视图)

App.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);

WithSecurityScreen.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;

Welcome.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>
        );
    }
}

我收到以下错误:

【问题讨论】:

    标签: react-native translation globalization


    【解决方案1】:

    首先,在您的情况下,您可以在单独的 js 文件 locale.js 中声明翻译函数,并可以在该文件中声明所有翻译逻辑并导出函数 translatesetI18nConfig

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

    更多细节你可以refer this repo我已经实现了。

    希望这会有所帮助。

    【讨论】:

      【解决方案2】:

      我使用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')
      

      您还可以使用来自 'react-i18next' 的 withNamespaces 包装组件,如下所示:

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

      然后访问翻译:

      
      this.props.t('welcome_message')
      

      【讨论】:

        猜你喜欢
        • 2020-07-21
        • 1970-01-01
        • 2020-09-09
        • 2021-04-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-03-09
        • 1970-01-01
        相关资源
        最近更新 更多