Fonts not applied on style unless hot-reloaded in React-Native - javascript

I am using global object to store font names (so later I can change all the fonts), but some how they not applied unless I save the component (and trigger hot-reload).
After experiments I found that global do not store values in the beginning, so the hot reload have to re-assign values to global variables that closured.
Code:
App.jsx
...
global.fontRegular = 'Montserrat-Regular';
global.fontSemiBold = 'Montserrat-SemiBold';
global.fontExtraBold = 'Montserrat-ExtraBold';
...
HeaderTitle.jsx
import React from 'react';
import {Text, TouchableOpacity, StyleSheet} from 'react-native';
const styles = StyleSheet.create({
text: {
fontSize: 24,
color: '#f1f1f1',
textAlign: 'center',
fontFamily: global.fontExtraBold,
margin: 10,
},
});
export default function () {
return (
<TouchableOpacity>
<Text style={styles.text}>SUPPORT.UA</Text>
</TouchableOpacity>
);
}
Screen before hot-reload
Screen after hot-reload

What I found out, is that using global object do not work for enclosured object if not in export body, so original code WILL NOT WORK,
but the following one WILL (now I wonder how this works):
import React from 'react';
import {Text, TouchableOpacity, StyleSheet} from 'react-native';
export default React.memo(function ({navigation, ...props}) {
const styles = StyleSheet.create({
text: {
fontSize: 24,
color: '#f1f1f1',
textAlign: 'center',
fontFamily: global.fontExtraBold,
margin: 10,
},
});
return (
<TouchableOpacity onPress={() => navigation.navigate('MainScreen')}>
<Text style={styles.text}>SUPPORT.UA</Text>
</TouchableOpacity>
);
});

Your const styles object is declared outside a function block, therefore it is evaluated immediately on app launch (with global.yourFont being unassigned yet). However, assignments to global are operations, that are done after the entire code has been crawled and unscoped const's have been evaluated. Therefore, moving it inside a component fixes the problem, because the component function will be called way after the initial crawl.

Related

Why when I try to use react native hooks it does not work properly as intended to be?

I am developing an app using react native, when I try to console.log(useDeviceOrientation());. The output (true/false) during the portrait and landscape did not change. Could someone help?
The library that is used is: #react-native-community/hooks
API that I used: useDeviceOrientation
What I try to do:
uninstall the library
reinstall the same library
add dependencies of the library to package.json
same problem occurred. no changes when changing orientation
Code:
// import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { Dimensions, StyleSheet, SafeAreaView, Alert, Button, Platform, StatusBar, View } from 'react-native';
import { useDimensions, useDeviceOrientation } from '#react-native-community/hooks'
export default function App() {
console.log(useDeviceOrientation());
const { landscape } = useDeviceOrientation();
return (
<SafeAreaView style={styles.container}>
<View style={{
backgroundColor: "dodgerblue",
width: "100%",
height: landscape ? "100%" : "30%",
}}
></View>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
paddingTop: Platform.OS === "android" ? StatusBar.currentHeight : 0,
// justifyContent: "center",
// alignItems: "center",
},
});
There is no need for 3rd party library for this. You can use this approach.
First, create a functional component named useOrientarion,
import { useWindowDimensions } from 'react-native';
const useOrientation = () => {
const { width, height } = useWindowDimensions();
return { isPortrait: height > width };
};
export default useOrientation;
and then in your component,
// import useOrientation
import useOrientation from './useOrientation';
function App() {
const orientation = useOrientation();
console.log(orientation);
// use orientation wherever you want
// OUTPUT: {"isPortrait": true} or {"isPortrait": false}
}
it works for me.
const { height, width } = useDimensions().window;
const landscape = width > height;
react-native-community
I believe it is a known issue that they are working on: https://github.com/react-native-community/hooks/issues/210. #ReadRise answer works great as a workaround it though!
I had the same issue; stopping the app and re-building was sufficient to have it fixed.

Create Generic Custom Component React

This is react-native question but similar concepts can be applied to react.
I want to create a CustomView in react-native. I am using typescript.
So far, I have:
const styles = StyleSheet.create({
container: {
backgroundColor: '#ffffff',
borderRadius: 10,
}
});
type CustomViewProps= {
width: number,
height: number,
marginTop?: string | number,
}
const CustomView = ({ width, height, marginTop }: CustomViewProps) => (
<View style={[styles.container, { height, width, marginTop }]} />
);
This is ok so far because only 3 props are being used: width, height and marginTop.
However, this is not reusable and it can become verbose if I need to add many more props.
So, the question is: How can I make CustomView receive any props as a native component View could receive?
My guess is I should delete CustomViewProps. Then, I should make the props inherit from the same type that the native component View does. However, I am struggling with it.
Since you are creating CustomViewProps, I assume that you want to add some specific behaviours to your native component above the already written behaviours of that component.
Let's create an example.
I want to create a button with some specific behaviours but i want it to behave, in other cases, like a normal TouchableOpacity component. For example, i want to add a "loading" state which will show a loader inside instead of its content.
So the logic is: create your custom props and merge you custom props with native's default props
import React, { FC, ReactElement } from 'react'
import { ActivityIndicator, TouchableOpacity, TouchableOpacityProps, StyleSheet } from 'react-native'
type MyProps = {
loading?: boolean
children: ReactElement
}
const MyButton: FC<MyProps & TouchableOpacityProps> = (props: MyProps & TouchableOpacityProps) => (
<TouchableOpacity {...props} disabled={props.disabled || props.loading} style={[styles.button, props.style]}>
{props.loading ? <ActivityIndicator /> : props.children}
</TouchableOpacity>
)
const styles = StyleSheet.create({
button: {
backgroundColor: 'yellow',
borderColor: 'black',
borderWidth: 1,
borderRadius: 10,
padding: 10
},
})
export default MyButton
The loading prop will be responsible for both content of the button or is disabled prop. The TouchableOpacity component will receive every compatible prop (autosuggest will be enabled because you have assigned the TouchableOpacityProps). The styles.button will behave like default style but will be overwritten if you specify something different in your style prop. That's it!

React native use a local font on snack.expo.io

How can I use a local font on snack.expo.io?
I have a ttf font, which I would like to use as evidence on snack.expo.io, but I do not quite understand how I could do it.
Some advice?
When you are creating your snack you can import files. You can see beside Project there are three vertical dots, click that takes you to the import menu.
Selecting Import files will take you to this screen where you can either browse or drag and drop your files. I prefer to drag and drop.
You can then drag the files to the folder that you wish them to be located in.
Then to use your custom font you can follow the guide in the documentation.
https://docs.expo.io/versions/latest/guides/using-custom-fonts/
Here is a quick code example.
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
import { Constants, Font } from 'expo';
// You can import from local files
export default class App extends React.Component {
// <- use the button on the left, three vertical dots to import files
// set the initial state
state = {
fontLoaded: false
}
async componentDidMount() {
// load fonts
await this.loadFonts();
}
loadFonts = async () => {
// load the font
await Font.loadAsync({
'open-sans-bold': require('./assets/fonts/OpenSans-Bold.ttf'),
});
this.setState({fontLoaded: true})
}
render() {
// use the font in your text components
// only render the Text component when the font has been loaded.
return (
<View style={styles.container}>
{this.state.fontLoaded ? (<Text style={{ fontFamily: 'open-sans-bold', fontSize: 56 }}>
Hello, world!
</Text>) : null}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
}
});
And an accompanying snack to show it working, notice I have stored my fonts in the folder ./assets/fonts/ https://snack.expo.io/#andypandy/custom-font

React native drawer menu: can`t find variable styles

I am trying to create a slider menu with the react-native-drawer-menu module. After installing the module . get an error can`t find variable styles. This is the code copied from the example:
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { Provider } from 'react-redux'
import'../I18n/I18n.js';
import RootContainer from './RootContainer'
import createStore from '../Redux'
import Drawer from 'react-native-drawer-menu';
import {Easing} from 'react-native'; // Customize easing function (Optional)
// create store
const store = createStore()
export default class App extends React.Component {
render() {
// prepare your drawer content
var drawerContent = (<View style={styles.drawerContent}>
<View style={styles.leftTop}/>
<View style={styles.leftBottom}>
<View><Text>Drawer Content</Text></View>
</View>
</View>);
var customStyles = {
drawer: {
shadowColor: '#000',
shadowOpacity: 0.4,
shadowRadius: 10
},
mask: {}, // style of mask if it is enabled
main: {} // style of main board
};
return (
<Drawer
style={styles.container}
drawerWidth={300}
drawerContent={drawerContent}
type={Drawer.types.Overlay}
customStyles={{drawer: styles.drawer}}
drawerPosition={Drawer.positions.Right}
onDrawerOpen={() => {console.log('Drawer is opened');}}
onDrawerClose={() => {console.log('Drawer is closed')}}
easingFunc={Easing.ease}
>
<View style={styles.content}>
<Text>{Object.values(Drawer.positions).join(' ')}</Text>
<Text>{Object.values(Drawer.types).join(' ')}</Text>
</View>
</Drawer>
);
}
}
If I delete the variable from the code then the slide menu works but looks extremely bad.
Do you think that I am supposed to create the style of the menu on my own or shall I imported from somewhere? If I have to create it, how can I know which parameters did it take? Or is it a normal view?
Looks like you have to add styles by yourself to make look Drawer content exactly as you want to. To achieve it you have to create Stylesheet
You can use this answer to get more info about React Native Stylesheet properties (it's pretty much similar to css)
Also maybe this example from drawer repo would be helpful
Cheers.

Issues getting Meteor data into React Native using createContainer

I can't seem to get createContainer to work with React Native and Meteor data. I'm currently using the react-native-meteor package and the latest releases of Meteor/React Native. I've reviewed the info for the package and Meteor's official write-up of createContainer. I guess first off, I'm not really sure how this container works. It looks like it wraps the component called at the end and updates it when the reactive data changes?
I've tried it a few different ways but below is what I currently am using. I'm not sure if createContainer is even getting called, as I don't see anything in the console from my log statement. I've tried using Meter.user() and Meteor.userId() as well with no luck. Any idea as to what I'm doing wrong?
'use strict';
import React, { Component } from 'react'
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
import { loginToSpotify } from './react-native-spotify-auth'
import Meteor, { createContainer } from 'react-native-meteor'
//import { testComponent } from './component'
//TODO: openURL bug on iOS9 causes iOS to confirm before redirect: http://stackoverflow.com/questions/32312009/how-to-avoid-wants-to-open-dialog-triggered-by-openurl-in-ios-9-0
//May also want to look into using Universal links
Meteor.connect('http://localhost:3000/websocket');//do this only once
class ReactNativeApp extends Component {
constructor(props) {
super(props);
this.state = {
access_token: null
};
}
componentDidMount() {
loginToSpotify();
}
render() {
const { todosReady } = this.props;
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
<Text style={styles.instructions}>
To get started, edit index.ios.js
</Text>
<Text style={styles.instructions}>
Press Cmd+R to reload,{'\n'}
Cmd+D or shake for dev menu
</Text>
<Text>
Hello {!todosReady && <Text>Not Ready</Text>}
</Text>
</View>
);
}
}
export default createContainer(params=>{
const handle = Meteor.subscribe('todos');
console.log('todos: ' + Meteor.collection('todos').find());
return {
todosReady: handle.ready()
}
}, ReactNativeApp);
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF'
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5
}
});
AppRegistry.registerComponent('ReactNativeApp', () => ReactNativeApp);
Can you see in console that meteor connected to the app? You shouldn't use http in Meteor.connect anymore, instead ws://localhost:3000/websocket
Be sure that your meteor application is running.
Use the IP of your local machine, don't use localhost. If you are using mobile as emulator that's good. Connect both in Router and use your machine language.
For more information you can follow this React Native Meteor Boilerplate.

Categories