Exported Constant not working in stylesheet - javascript

In one of the components in my project, I export a constant integer and then use it as a value for height in StyleSheet. In one particular case, it is not working and I can't figure out why. I have extracted the minimum possible code to reproduce it.
In TopBar.js, I export NAVBAR_HEIGHT and import it in both Home.js and MyModal.js. While it works right in Home.js when I use it as value of height in StyeSheet, it doesn't work in MyModal.js. However, if I replace NAVBAR_HEIGHT with a hardcoded int value, it works. It also works if I use NAVBAR_HEIGHT inline instead of creating a StyleSheet and passing the styles.topbar object.
(I wanted to make an rnplay for this, but looks like it can't make multiple files and thus, I couldn't reproduce it.)
Here is the code, apologies for making it long. I've also pushed it to git here.
Home.js (root component)
import React from 'react';
import {
View, StyleSheet, TouchableHighlight
} from 'react-native';
import TopBar, { NAVBAR_HEIGHT } from './TopBar';
export default class Home extends React.Component {
constructor(props) {
super(props);
this.state = { showModal: false };
}
render() {
return (
<TouchableHighlight onPress={this.toggleModal}>
<View style={styles.view}>
<TopBar showModal={this.state.showModal}
onClose={this.toggleModal} />
</View>
</TouchableHighlight>
);
}
toggleModal = () => {
this.setState({ showModal: !this.state.showModal });
}
}
const styles = StyleSheet.create({
view: {
height: NAVBAR_HEIGHT,
backgroundColor: 'blue',
}
});
MyModal.js
import React, { Component } from 'react';
import {
StyleSheet,
View,
Modal,
Text,
} from 'react-native';
import { NAVBAR_HEIGHT } from './TopBar';
export default class MyModal extends Component {
render() {
return (
<Modal animationType={'slide'}
visible={this.props.visible}
style={styles.container}
onRequestClose={this.props.onClose}>
<View style={styles.topbar}>
<Text style={styles.text}>{NAVBAR_HEIGHT}</Text>
</View>
</Modal>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
topbar: {
backgroundColor: 'red',
height: NAVBAR_HEIGHT,
},
text: {
fontSize: 20
}
});
TopBar.js
import React, { Component } from 'react';
import {
View,
StyleSheet,
Platform,
Text,
} from 'react-native';
import MyModal from './MyModal';
export const NAVBAR_HEIGHT = Platform.OS === 'ios' ? 200 : 100;
export default class TopBar extends Component {
render() {
return (
<View style={styles.container}>
<Text>TEST</Text>
<MyModal visible={this.props.showModal}
onClose={this.props.onClose} />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
backgroundColor: 'green',
},
});
I might be making some silly mistake but I have spent way too much time on this one and I'm still clueless. Help.

The modules TopBar.js and MyModal.js have a circular dependency: TopBar imports MyModal, and MyModal imports TopBar. Because module resolution is synchronous, the imported value is undefined.
Extract the common dependency into its own module and reference it from both TopBar and MyModal.
Here's a simple reproduction:
a.js
import {b} from './b';
export const a = 'a';
console.log('A sees B as', b);
b.js
import {a} from './a';
export const b = 'b';
console.log('B sees A as', a);
main.js
import {a} from './a';
Outputs:
B sees A as undefined
A sees B as b

Related

It doesn't recognize a file within an imported file

I have created a MenuButton as well as 2 other pages one of them being the settingScreen, where I have imported the MenuButton within both files and they seem to be working fine. But when I import the setting Screen on the DrawerNavigator file it doesn't recognize MenuButton
Failed to load bundle(http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false) with error:(Unable to resolve module `./Menu/MenuButton` from `/Users/camillebasbous/Project/Menu/SettingScreen.js`: The module `./Menu/MenuButton` could not be found from `/Users/camillebasbous/Project/Menu/SettingScreen.js`. Indeed, none of these files exist:
* `/Users/camillebasbous/Project/Menu/Menu/MenuButton(.native||.ios.js|.native.js|.js|.ios.json|.native.json|.json|.ios.ts|.native.ts|.ts|.ios.tsx|.native.tsx|.tsx)`
* `/Users/camillebasbous/Project/Menu/Menu/MenuButton/index(.native||.ios.js|.native.js|.js|.ios.json|.native.json|.json|.ios.ts|.native.ts|.ts|.ios.tsx|.native.tsx|.tsx)` (null))
__38-[RCTCxxBridge loadSource:onProgress:]_block_invoke.228
RCTCxxBridge.mm:414
___ZL36attemptAsynchronousLoadOfBundleAtURLP5NSURLU13block_pointerFvP18RCTLoadingProgressEU13block_pointerFvP7NSErrorP9RCTSourceE_block_invoke.118
__80-[RCTMultipartDataTask URLSession:streamTask:didBecomeInputStream:outputStream:]_block_invoke
-[RCTMultipartStreamReader emitChunk:headers:callback:done:]
-[RCTMultipartStreamReader readAllPartsWithCompletionCallback:progressCallback:]
-[RCTMultipartDataTask URLSession:streamTask:didBecomeInputStream:outputStream:]
__88-[NSURLSession delegate_streamTask:didBecomeInputStream:outputStream:completionHandler:]_block_invoke
__NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__
-[NSBlockOperation main]
-[__NSOperationInternal _start:]
__NSOQSchedule_f
_dispatch_call_block_and_release
_dispatch_client_callout
_dispatch_continuation_pop
_dispatch_async_redirect_invoke
_dispatch_root_queue_drain
_dispatch_worker_thread2
_pthread_wqthread
start_wqthread
I have tried testing ou the other page and after a few tests I realized that the presence of the imported MenuButton within these pages is what is forcing an error Is there a way to import a file that has imported another to be displayed or do I have to import both of them within drawerNavigation and if so how to structure the code. Thanks
Drawer Navigation code:
import * as React from 'react';
import { Text, View, Image, ScrollView, StyleSheet } from 'react-native';
import {
createDrawerNavigator,
createAppContainer,
DrawerItems,
SafeAreaView,
} from 'react-navigation';
import SettingScreen from './Menu/SettingScreen'
class Home extends React.Component {
static navigationOptions = {
title: 'Home',
};
render() {
return (
<View style={styles.container}>
<SettingScreen/>
</View>
);
}
}
const Navigator = createDrawerNavigator(
{
Home,
},
{
//drawerType: 'back',
// drawerPosition: 'right',
// drawerWidth: 200,
drawerBackgroundColor: '#262A2C',
// contentComponent: CustomDrawerContentComponent
}
);
export default createAppContainer(Navigator);
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
backgroundColor: '#ecf0f1',
}
});
SettingScreen code:
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import MenuButton from './Menu/MenuButton'
export default class SettingScreen extends React.Component{
render(){
return(
<View style={styles.container}>
<MenuButton/>
<Text style={styles.text}>Settings</Text>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'rgba(215,215,215,1)',
alignItems: 'center',
justifyContent: 'center',
},
text:{
fontSize: 30,
}
});
MenuButton code:
import React from 'react';
import {AppRegistry, StyleSheet, View} from "react-native" ;
import Icon from 'react-native-vector-icons/Ionicons'
import {widthPercentageToDP as wp, heightPercentageToDP as hp} from 'react-native-responsive-screen'
export default class MenuButton extends React.Component {
render() {
return(
<View >
<Icon name= "ios-menu" size={wp('12%')} color='#9B9B9B' style={{position: 'absolute', top: wp('-82.5%'), left: wp('-46%'), }}></Icon>
</View>
)
}
}
AppRegistry.registerComponent('Menu', () => FixedDimensionsBasics);
The path you are using on import is relative to your file. So, as everything is on the same folder, you must correct the import path like that:
On Drawer Navigator code
import SettingScreen from './SettingScreen'
On SettingScreen code
import MenuButton from './MenuButton'

How to solve Invarient violation:Text strings must be rendered within a <Text> component in React Native?

In my React- Native project I have installed the following version of react-navigation:
npm install react-navigation#^1.0.0-beta.11
And then run the command:
npm install
After all these installation I have created a class named WelcomeScreen.js and here is the code given below for that-
WelcomeScreen.js
import React, { Component } from "react";
import {
View,
StyleSheet,
Button
} from "react-native";
class WelcomeScreen extends Component {
static navigationOptions = {
header: 'none'
}
render() {
return (
<View style={styles.container}>
<Button title="Log in" onPress={() => this.props.navigation.navigate('LoginScreen')}/>
<Button title="Sign Up" onPress={() => this.props.navigation.navigate('SignUpScreen')}/>
</View>
)
}
}
export default WelcomeScreen;
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center'
}
});
After that, I have routed this class in my App.js file. Here is the code given below:
App.js
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { StackNavigator } from 'react-navigation'
import WelcomeScreen from './screens/WelcomeScreen'
export default class App extends React.Component {
render() {
return (
<AppStackNavigator/>
);
}
}
const AppStackNavigator = new StackNavigator({
WelcomeScreen: { screen: WelcomeScreen }
})
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
Then after running my project, I am keep getting this error:
Invarient violation:Text strings must be rendered within a component
Invarient violation:Text strings must be rendered within a component
I am not understanding why I am getting this error ?
I have tried following solutions-
Invariant Violation: Text strings must be rendered within a <Text> component
https://github.com/facebook/react-native/issues/20084
None of them were helpful for me. So, it would be very nice if someone help me out with this.
You have used a wrong value in a header
static navigationOptions = {
header: "none"
};
Replace "none" with null
static navigationOptions = {
header: null
};
const AppStackNavigator = new StackNavigator({
WelcomeScreen: { screen: WelcomeScreen }
})
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
}**,**
});
is it this comma?
I'd consider working with React's newest navigation package react-navigation-stack (currently in 2.0 alpha - link).
You would implement this exactly like previous react-navigation stack navigators.
import React from 'react'
// ...
import { createAppContainer } from 'react-navigation'
import { createStackNavigator } from 'react-navigation-stack'
const HomeStack = createStackNavigator(
{ HomeScreen, AboutScreen },
{ initialRouteName: "HomeScreen" }
)
HomeStack.navigationOptions = {
headerShown: false, // a more concise option, to avoid future deprecation.
}
// ... continues in next code block
Don't forget to wrap your application in a react-navigation AppContainer too.
// ...
const AppNav = createAppContainer(HomeStack)
export default AppNav
Of course, if you're modifying navigationOptions in other screens, you would simply attach the alternate options within that screen component:
class HomeScreen extends React.Component {
static navigationOptions = {
headerShow: false
}
render() {
return (<View><Text>Welcome home.</Text></View>)
}
}
As seen above, we can now use the navigation option: headerShown: false.
With this new package, you'll be preparing your application for the future iterations of React's navigation packages.
Note ;'s left out as a styling choice.

Fix Error: The component for route 'Home' must be a React component

I'm trying to used react-navigation but I can not get it to work when I move each screens' components into multiple files. I always get this error: "The component for route 'Home' must be a React component". This error doesn't happen if I move all of the code into one file, so I'm not sure what the difference is.
Here is my App.js:
import React from 'react';
import { StackNavigator } from 'react-navigation';
import { AppRegistry, StyleSheet, Text, View, TouchableHighlight } from 'react-native';
import { HomeScreen } from './screens/HomeScreen';
import { JoinScreen from './screens/JoinScreen';
import { HostScreen } from './screens/HostScreen';
const Root = StackNavigator(
{
Home: {
screen: HomeScreen,
},
Details: {
screen: JoinScreen,
}
},
{
initialRouteName: 'Home',
headerMode: 'none',
}
);
export default class App extends React.Component {
render() {
return (
<Root />
)
}
}
And here is my .screens/HomeScreen.js
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
export default class HomeScreen extends React.Component {
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.container}>
<Text style={styles.title}>Hello World</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'space-around',
}
});
I think that if you change this line:
import { HomeScreen } from './screens/HomeScreen';
to:
import HomeScreen from './screens/HomeScreen';
(i.e. removing the braces around HomeScreen) then it will work. Because you used export default in the HomeScreen component's source file, you don't need the destructuring on the import. This is attempting to access a variable called HomeScreen on the component, which is resolving to undefined and causes the error you saw.
Alternatively, you can remove the default from export default and keep the import the same. I personally prefer removing the braces as the code looks cleaner.
There's also a missing closing brace on this line:
import { JoinScreen from './screens/JoinScreen';
But I assumed that was a typo ;)
I think that react is having a problem figuring out what to import
Since you're exporting one thing by default
You should replace import { HomeScreen } from './screens/HomeScreen';
with
import HomeScreen from './screens/HomeScreen';
Try with:
Home: {
screen: () => <HomeScreen/>,
},
It also happens if you do not export your class.
export default class HomeScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button
title="Go to Details"
onPress={() => this.props.navigation.navigate('Details')}
/>
</View>
);
}
}
Add this to your js file at the bottom add this Line
export default MainActivity;
import React, { Component } from 'react';
import { createStackNavigator } from 'react-navigation-stack';
class MainActivity extends Component{
...
}
export default MainActivity;
Since you've mentioned the default, I think that if you change this line:
import { HomeScreen } from './screens/HomeScreen';
to:
import HomeScreen from './screens/HomeScreen';
This would solve the issue. Cheers mate!
Keep the braces intact for your external screen files imports. Just do the following and it should run on both Android and iOS simulators regardless
// HomeScreen.js
... all imports
export class HomeScreen extends React.Component {
...
This fixed the issue for me in both platforms.
I was using "react" instead of 'react'. I removed the double quotes from react and the error gone away.

React native: Component not defined? Can't import?

Ok, very new to react native here and Im trying to very simply import another .js file and have that be run in the main render() func in index.ios.js
I have looked everywhere and tried both import and require to do this, however I am stuck with error:
Here is what I have, the error is thrown at just the addition of the import line:
import React, { Component } from 'react';
import { Button, Card } from 'react-native-material-design';
import {
StyleSheet,
Text,
View,
Animated,
Easing,
ScrollView,
RefreshControl,
AppRegistry
} from 'react-native';
//import { Container, Content } from 'native-base';
import TestClass from "./TestClass";
//var animation = require('./TestClass');
//BODY
export default class SkysReact extends Component {
render() {
return (<View style={styles.container}>
<TestClass/>
</View>);
// return (<View style={styles.container}>
// {this.test()}
// </View>);
}
test() {
console.log("Hello World")
}
animate()
{
console.log("animate");
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#404040',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
color: '#333333'
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
AppRegistry.registerComponent('SkysReact', () => SkysReact);
And my other class:
import React from 'react';
import Animation from 'lottie-react-native';
import {
StyleSheet,
Text,
View,
Animated,
Easing,
ScrollView,
RefreshControl,
AppRegistry
} from 'react-native';
export default class TestClass extends Component { // not defined error here
render() {
return (<View style={styles.container}>
{this.test()}
</View>);
}
test() {
console.log("Hello World 2222")
}
}
module.exports = TestClass;
How can I just display TestClass in my index.ios.js? What is wrong?
Ah hah. I know exactly what it is. Compare the very top line of your TestClass file with mine below. You will see the difference. Fix this, and your done.
import React, {Component} from 'react';
import Animation from 'lottie-react-native';
import {
StyleSheet,
Text,
View,
Animated,
Easing,
ScrollView,
RefreshControl,
AppRegistry
} from 'react-native';
export default class TestClass extends Component {
render() {
return (<View style={styles.container}>
{this.test()}
</View>);
}
test() {
console.log("Hello World 2222")
}
}
You were missing the, {Component} in your import statement. I also took our your module.exports statement, its unnecessary.
this.test() is not a valid child of your <View> in TestClass because it is not a valid React Component, nor does it return one.
If you want to "test" that your TestClass.render() function is running, put the console.log() above your return statement, like this:
render() {
this.test();
return (
<View style={styles.container}></View>
);
}
Of course, you won't actually see anything because TestClass doesn't have any children.

Communicate Between Components in React Native (child -> parent)

I need inside the file artistPage.js to refer to the TabNavigator in index.ios.js. In particular, I need to change the styles to hide the TabBar when the user is on the page artistPage.
How can I do that? Any ideas?
I tried to transfer styles in the props but there is the read-only mode(
index.ios.js
'use strict'
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
View,
Image,
Text,
NavigatorIOS,
TouchableHighlight,
NavigationBar,
} from 'react-native';
import config from './config';
import ImagesList from './app/imagesList';
import TabNavigator from 'react-native-tab-navigator';
import Badge from './node_modules/react-native-tab-navigator/Badge'
class MyApp extends Component {
constructor(props) {
super(props);
this.state = {
selectedTab: 'images',
showTabBar: true
};
}
render() {
let tabBarStyle = {};
let sceneStyle = {};
if (this.state.showTabBar) {
tabBarStyle = styles.tabBar;
sceneStyle.paddingBottom = 54;
} else {
tabBarStyle.height = 0;
tabBarStyle.overflow = 'hidden';
sceneStyle.paddingBottom = 0;
}
return (
<View style={styles.container}>
<TabNavigator
tabBarStyle={ tabBarStyle }
sceneStyle={sceneStyle}
>
<TabNavigator.Item
titleStyle={styles.title}
selectedTitleStyle={styles.title_select}
selected={this.state.selectedTab === 'images'}
title="TATTOOS"
renderIcon={() => <Image source={require('./images/tabbar/tattoos_icon.png')} />}
renderSelectedIcon={() => <Image source={require('./images/tabbar/tattoos_icon_selected.png')} />}
onPress={() => this.setState({ selectedTab: 'images' })}>
<NavigatorIOS
style={styles.container}
initialRoute={{
title: 'MyApp',
component: ImagesList,
passProps: { showTabBar: true},
}}
navigationBarHidden={true}/>
</TabNavigator.Item>
</TabNavigator>
</View>
);
}
}
AppRegistry.registerComponent('MyApp', () => MyApp);
imageList.js
'use strict'
import React, { Component } from 'react';
import {
StyleSheet,
ListView,
View,
Text,
Image,
Dimensions,
ActivityIndicator,
TouchableHighlight,
RefreshControl
} from 'react-native';
import ArtistPage from './imageCard';
class ImagesList extends Component {
constructor(props) {
super(props);
this.state = {
};
}
_artistPage() {
this.props.navigator.push({
component: ArtistPage
});
}
render() {
return (
<View style={styles.container}>
<TouchableHighlight
onPress={this._artistPage()}
>
<Text>Got to Next Page</Text>
</TouchableHighlight>
</View>
);
}
}
}
module.exports = ImagesList;
artistPage.js
'use strict'
import React, { Component } from 'react';
import {
StyleSheet,
Text,
ListView,
View,
TouchableHighlight,
Image,
} from 'react-native';
class ArtistPage extends Component {
constructor(props) {
super(props);
this.state = {
};
}
_backTo() {
this.props.navigator.pop();
}
render() {
return (
<View>
<TouchableHighlight style={{marginTop: 100, marginLeft: 50}} onPress={() => this._backTo()} >
<Text>Back {this.props.showTabBar.toString()}</Text>
</TouchableHighlight>
</View>
);
}
}
module.exports = ArtistPage;
Here is how to hide TabNavigator: https://github.com/exponentjs/react-native-tab-navigator
let tabBarHeight = 0;
<TabNavigator
tabBarStyle={{ height: tabBarHeight, overflow: 'hidden' }}
sceneStyle={{ paddingBottom: tabBarHeight }}
/>
But I don't understand how to access it from artistPage.js
Thank you!
Data flow in React is one way. What it means in practice is that, to change something that a certain component receives via props, it will need to call back into the parent component, via a function from props.
The React website has a nice intro to the concept.
In your particular case, you could have a tabBarVisible state in MyApp, and inside render, compute the style to apply to the tab bar.
MyApp also can have a method to change this state:
hideTabBar() {
this.setState({ tabBarVisible: true });
}
Now, in order to let ArtistPage toggle that, you can pass the hideTabBar function from MyApp to ArtistPage as a prop, and call it in ArtistPage in a lifecycle hook, like componentDidMount.

Categories