I am quite new in React Native and I am trying to understand how function written in a parent Component could be passed (inherited) to any children and sub-children. In particular I am using a library to internationalise my App using:
import * as RNLocalize from 'react-native-localize'
import i18n from 'i18n-js'
But I noticed that I have to implement the translate(...)
function for each Component of the whole project and this seems to be exaggerated because it requires a lot of work to implement the translation feature (I followed this tutorial).
Please, note that I have a basic understanding how to pass a function or some data using this.props, so I am not asking how props works from a parent to a single child. What I am asking is: how to avoid to repeat the code from //BEGIN ...
to //END...
(please see WithSecurityScreen file) and to avoid to repeat the implementation of handleLocalizationChange, RNLocalize.addEventListener, RNLocalize.removeEventListener and translate.
Please also note that the translation library works, test is provided at following line of WithSecurityScreen:
const SecurityScreen = () => <View><Text>{translate('USER_SURNAME')}</Text></View>;
But I am not be able to pass translate(...) function to each components of the whole project.
The project structure is:
- App.js (wraps SecureApp.js)
- SecureApp.js (wrapped in App.js and runs WithSecurityScreen.js)
- WithSecurityScreen.js (wraps routes to views, e.g. Welcome.js)
- Welcome.js (main view)
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>
);
}
}
I get following error: