So, I'm trying to use Hooks in React Native but I'm very new to React Native and I don't know how to properly use Hooks in Class and Function components. But in this project, I'm using the Class component but I'm getting an error of invalid hook call, so how do I turn this hook for the function component into the class component.
This is my code:
export default class Home extends Component {
render() {
let [fontsLoaded, error] = useFonts({
Raleway_100Thin,
Raleway_100Thin_Italic,
Raleway_200ExtraLight,
Raleway_200ExtraLight_Italic,
Raleway_300Light,
Raleway_300Light_Italic,
Raleway_400Regular,
Raleway_400Regular_Italic,
Raleway_500Medium,
Raleway_500Medium_Italic,
Raleway_600SemiBold,
Raleway_600SemiBold_Italic,
Raleway_700Bold,
Raleway_700Bold_Italic,
Raleway_800ExtraBold,
Raleway_800ExtraBold_Italic,
Raleway_900Black,
Raleway_900Black_Italic,
});
if (!fontsLoaded) {
return <AppLoading />;
}
return (
<View style={styles.container}>
{/* TITLE */}
<Text style={styles.title}>MALIGAYANG PAGDATING!</Text>
<Text style={styles.subtitle}>RECENTLY VIEWED</Text>
</View>
);
}
}
You can't use hooks inside of a class component. See the Hooks FAQ on the React documentation.
Use this way like
import React from 'react';
import { View, Text } from 'react-native';
import AppLoading from 'expo-app-loading';
import { useFonts, Inter_900Black } from '#expo-google-fonts/inter';
export default function App() {
let [fontsLoaded] = useFonts({
Inter_900Black,
});
if (!fontsLoaded) {
return <AppLoading />;
}
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={{ fontFamily: 'Inter_900Black', fontSize: 40 }}>Inter Black</Text>
</View>
);
}
Details Here also you can try this way too Here
You cannot use hooks inside a class component. Hooks was designed for functional component only. You can modify your class based component to functional based like below and use it.
// Imports
function Home() {
const [fontsLoaded, error] = useFonts({
Raleway_100Thin,
Raleway_100Thin_Italic,
Raleway_200ExtraLight,
Raleway_200ExtraLight_Italic,
Raleway_300Light,
Raleway_300Light_Italic,
Raleway_400Regular,
Raleway_400Regular_Italic,
Raleway_500Medium,
Raleway_500Medium_Italic,
Raleway_600SemiBold,
Raleway_600SemiBold_Italic,
Raleway_700Bold,
Raleway_700Bold_Italic,
Raleway_800ExtraBold,
Raleway_800ExtraBold_Italic,
Raleway_900Black,
Raleway_900Black_Italic,
});
return fontsLoaded ? (
<View style={styles.container}>
{/* TITLE */}
<Text style={styles.title}>MALIGAYANG PAGDATING!</Text>
<Text style={styles.subtitle}>RECENTLY VIEWED</Text>
</View>
) : (
<AppLoading />
);
}
export default Home;
I want to pass a state with value - 3 to another functional component that uses value - 1. How can I do that ?
My code:
Screen 1.
import { Text, TouchableOpacity } from "react-native";
import React from "react";
import { useNavigation } from "#react-navigation/native";
export default function ScreenOne() {
const navigation = useNavigation();
const [myState, setMyState] = useState(1);
return (
<TouchableOpacity
onPress={() =>
navigation.navigate("ScreenTwo", setMyState(myState(3)))
}
>
<Text>Go to another screen</Text>
</TouchableOpacity>
); }
Screen 2.
import { View, Text } from "react-native";
import React from "react";
import { useRoute } from "#react-navigation/native";
export default function screenTwo() {
const [myState, setMyState] = useState(1);
const route = useRoute();
const setMyState = route.params;
return (
<View>
<Text>myState</Text>
</View>
); }
For example, the myState in the first screen has the value 1, after clicking the button in the first screen I need to change the value of myState the state 3 in the second screen.
To share state between two sibling function components you need to lift the state up to their common parent component. The state must be located only in the parent.
First screen: you just need to handle the new state and lift up to the parent component.
export default function ScreenOne({ handleState }) {
const navigation = useNavigation();
return (
<TouchableOpacity
onPress={() => {
handleState(3)
navigation.navigate("ScreenTwo")
}}
>
<Text>Go to another screen</Text>
</TouchableOpacity>
);
}
Second screen: you only need to get state value.
export default function ScreenTwo({ state }) {
return (
<View>
<Text>{state}</Text>
</View>
);
}
Parent component: you have your useState here, so childs components can interact with it like this.
function Parent() {
const [state, setState] = useState(1);
return {
<View>
<ScreenOne handleState={(state) => setState(state)} />
<ScreenTwo state={state} />
</View>
}
}
I am trying to make a reusable component with linear gradient which can be used to dynamically change each page's theme/color but i keep getting an error cannot read property of children undefined.
import React from 'react';
import LinearGradient from 'react-native-linear-gradient';
export const GradientStyle = ({ theme }) => {
const { primary, primaryGradient2, primaryGradient1 } = theme;
return (
<LinearGradient
style={{ flex: 1 }}
colors={[primary, primaryGradient2, primaryGradient1]}>
{this.props.children}
</LinearGradient>
);
};
usage
import {GradientStyle} from '../../../styles/theme/GradientTheme'
const theme1 ={
primary: '#4c669f',
primaryGradient2: '#3b5998',
primaryGradient1: '#192f6a'
}
render() {
return (
<GradientStyle colors={theme1}>
.......content
</GradientStyle>
);
}
You cannot use this.props in a functional component. You have to do add it to the destructuring parameter, like this:
export const GradientStyle = ({ children, theme }) => {
const { primary, primaryGradient2, primaryGradient1 } = theme;
return (
<LinearGradient
style={{ flex: 1 }}
colors={[primary, primaryGradient2, primaryGradient1]}>
{children}
</LinearGradient>
);
};
You can then create a GradientStyle like this:
import {GradientStyle} from '../../../styles/theme/GradientTheme'
const theme1 ={
primary: '#4c669f',
primaryGradient2: '#3b5998',
primaryGradient1: '#192f6a'
};
render() {
return (
<GradientStyle theme={theme1}></GradientStyle>
);
}
Im new to react native and I'm stuck at following.
Im performing navigation (when clicked on alert view button) using the code below.
const {navigation} = this.props.navigation;
…
.
.
{ text: 'Done', onPress:() => {
navigate.push(HomeScreen);}
How can I pass data to another Page in React native? Can I declare the parameter global and just assign to it?
What would be the correct way of performing this and how would I go about it?
Note
This answer was written for react-navigation: "3.3.0". As there are newer versions available, which could bring changes, you should make sure that you check with the actual documentation.
Passing data between pages in react-navigation is fairly straight forward. It is clearly explained in the documentation here
For completeness let's create a small app that allows us to navigate from one screen to another passing values between the screens. We will just be passing strings in this example but it would be possible to pass numbers, objects and arrays.
App.js
import React, {Component} from 'react';
import AppContainer from './MainNavigation';
export default class App extends React.Component {
render() {
return (
<AppContainer />
)
}
}
MainNavigation.js
import Screen1 from './Screen1';
import Screen2 from './Screen2';
import { createStackNavigator, createAppContainer } from 'react-navigation';
const screens = {
Screen1: {
screen: Screen1
},
Screen2: {
screen: Screen2
}
}
const config = {
headerMode: 'none',
initialRouteName: 'Screen1'
}
const MainNavigator = createStackNavigator(screens,config);
export default createAppContainer(MainNavigator);
Screen1.js and Screen2.js
import React, {Component} from 'react';
import { View, StyleSheet, Text, Button } from 'react-native';
export default class Screen extends React.Component {
render() {
return (
<View style={styles.container}>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'white'
}
});
Here we have 4 files. The App.js which we will import the MainNavigation.js. The MainNavigation.js sets up a StackNavigator with two screens, Screen1.js and Screen2.js. Screen1 has been set as the initial screen for our StackNavigator.
Navigating between screens
We can navigate from Screen1 to Screen2 by using
this.props.navigation.navigate('Screen2');
and we can go back to Screen1 from Screen2 by using
this.props.navigation.goBack();
So code in Screen1 becomes
export default class Screen extends React.Component {
render() {
return (
<View style={styles.container}>
<Button title={'Go to screen 2'} onPress={() => this.props.navigation.navigate('Screen2')} />
</View>
)
}
}
And code in Screen2 becomes:
export default class Screen extends React.Component {
render() {
return (
<View style={styles.container}>
<Button title={'Go back'} onPress={() => this.props.navigation.goBack()} />
</View>
)
}
}
Now we can navigate between Screen1 and Screen2
Sending values from Screen1 to Screen2
To send a value between Screen1 and Screen2, two steps are involved. First we have to send it, secondly we have to capture it.
We can send a value by passing it as a second parameter. Notice how the text value is contained in an object.
this.props.navigation.navigate('Screen2', {text: 'Hello from Screen 1' });
And we can capture it in Screen2 by doing the following, the first value in getParams is the key the second value is the default value.
const text = this.props.navigation.getParams('text','nothing sent');
So Screen1 now becomes
export default class Screen extends React.Component {
render() {
return (
<View style={styles.container}>
<Button
title={'Go to screen 2'}
onPress={() => this.props.navigation.navigate('Screen2', {
text: 'Hello from screen 1'
})} />
</View>
)
}
}
And code in Screen2 becomes:
export default class Screen extends React.Component {
render() {
const text = this.props.navigation.getParam('text', 'nothing sent')
return (
<View style={styles.container}>
<Text>{text}</Text>
<Button
title={'Go back'}
onPress={() => this.props.navigation.goBack()} />
</View>
)
}
}
Sending values from Screen2 back to Screen1
The easiest way I have discovered to send a value from Screen2 to Screen1 is to pass a function to Screen2 from Screen1 that will update the state in Screen1 with the value that you want to send
So we can update Screen1 to look like this. First we set an initial value in state. Then we create a function that will update the state. Then we pass that function as a parameter. We will display the captured value from Screen2 in a Text component.
export default class Screen1 extends React.Component {
state = {
value: ''
}
receivedValue = (value) => {
this.setState({value})
}
render() {
return (
<View style={styles.container}>
<Button
title={'Go to screen 2'}
onPress={() => this.props.navigation.navigate('Screen2', {
text: 'Hello from Screen 1',
receivedValue: this.receivedValue }
)} />
<Text>{this.state.value}</Text>
</View>
)
}
}
Notice that we are passing the function receivedValue in the same way that we passed the text earlier.
Now we have to capture the value in Screen2 and we do that in a very similar way that we did previously. We use getParam to get the value, remembering to set our default. Then when we press our Go back button we update it to call the receivedValue function first, passing in the text that we want to send back.
export default class Screen2 extends React.Component {
render () {
const text = this.props.navigation.getParam('text', 'nothing sent');
const receivedValue = this.props.navigation.getParam('receivedValue', () => {});
return (
<View style={styles.container}>
<Button
title={'Go back'}
onPress={() => {
receivedValue('Hello from screen 2')
this.props.navigation.goBack()
}} />
<Text>{text}</Text>
</View>
);
}
}
Alternatives to using getParam
It is possible to not use the getParam method and instead access the values directly. If we were to do that we would not have the option of setting a default value. However it can be done.
In Screen2 we could have done the following:
const text = this.props.navigation.state.params.text;
const receivedValue = this.props.navigation.state.params.receivedValue;
Capturing values in lifecycle events (Screen1 to Screen2)
react-navigation allows you to capture values using the lifecycle events. There are a couple of ways that we can do this. We could use NavigationEvents or we could use listeners set in the componentDidMount
Here is how to set it up using NavigationEvents
import React, {Component} from 'react';
import { View, StyleSheet, Text } from 'react-native';
import { NavigationEvents } from 'react-navigation'; // you must import this
export default class Screen2 extends React.Component {
state = {
text: 'nothing passed'
}
willFocusAction = (payload) => {
let params = payload.state.params;
if (params && params.value) {
this.setState({value: params.value});
}
}
render() {
return (
<View style={styles.container}>
<NavigationEvents
onWillFocus={this.willFocusAction}
/>
<Text>Screen 2</Text>
<Text>{this.state.text}</Text>
</View>
)
}
}
Here is how to do it using listeners in the componentDidMount
export default class Screen2 extends React.Component {
componentDidMount () {
// we add the listener here
this.willFocusSubscription = this.props.navigation.addListener('willFocus', this.willFocusAction);
}
componentWillUmount () {
// we remove the listener here
this.willFocusSubscription.remove()
}
state = {
text: 'nothing passed'
}
willFocusAction = (payload) => {
let params = payload.state.params;
if (params && params.value) {
this.setState({value: params.value});
}
}
render() {
return (
<View style={styles.container}>
<Text>Screen 2</Text>
<Text>{this.state.text}</Text>
</View>
)
}
}
Passing navigation via components
In the above examples we have passed values from screen to screen. Sometimes we have a component on the screen and we may want to navigate from that. As long as the component is used within a screen that is part of a navigator then we can do it.
If we start from our initial template and construct two buttons. One will be a functional component the other a React component.
MyButton.js
// this is a functional component
import React, {Component} from 'react';
import { View, StyleSheet, Text, TouchableOpacity } from 'react-native';
export const MyButton = ({navigation, value, title}) => {
return (
<TouchableOpacity onPress={() => navigation.navigate('Screen2', { value })}>
<View style={styles.buttonStyle}>
<Text>{title}</Text>
</View>
</TouchableOpacity>
)
}
const styles = StyleSheet.create({
buttonStyle: {
width: 200,
height: 60,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'red'
}
});
MyOtherButton.js
// this is a React component
import React, {Component} from 'react';
import { View, StyleSheet, Text, TouchableOpacity } from 'react-native';
export default class MyOtherButton extends React.Component {
render() {
const { navigation, value, title } = this.props;
return (
<TouchableOpacity onPress={() => navigation.navigate('Screen2', { value })}>
<View style={styles.buttonStyle}>
<Text>{title}</Text>
</View>
</TouchableOpacity>
)
}
}
const styles = StyleSheet.create({
buttonStyle: {
width: 200,
height: 60,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'yellow'
}
});
Regardless of the type of component, notice that navigation is a prop. We must pass navigation to the component otherwise it will not work.
Screen1.js
import React, {Component} from 'react';
import { View, StyleSheet, Text, Button } from 'react-native';
import { MyButton } from './MyButton';
import MyOtherButton from './MyOtherButton';
export default class Screen1 extends React.Component {
render() {
return (
<View style={styles.container}>
<Text>Screen 1</Text>
<MyButton
title={'Press my button'}
navigation={this.props.navigation}
value={'this is a string passed using MyButton'}
/>
<MyOtherButton
title={'Press my other button'}
navigation={this.props.navigation}
value={'this is a string passed using MyOtherButton'}
/>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'white'
}
});
Notice in Screen1.js as it is contained in a StackNavigator it will have access to this.props.navigation. We can pass that through to our component as a prop. As long as we use that in our component then we should be able to navigate by using the components own functionality.
<MyButton
title={'Press my button'}
navigation={this.props.navigation} // pass the navigation here
value={'this is a string passed using MyButton'}
/>
Snacks
Here is a snack for passing params.
Here is a snack for passing params and capturing in lifecycle events.
Here is a snack passing navigation to components
1) On Home Screen:-
Initialise:-
constructor(props) {
super(props);
this.navigate = this.props.navigation.navigate; }
Send:-
this.navigate("DetailScreen", {
name: "Detail Screen",
about:"This is Details Screen Page"
});
2) On Detail Screen:-
Initialise:-
constructor(props) {
super(props);
this.params = this.props.navigation.state.params;
}
Retrive data:-
console.log(this.params.name);
console.log(this.params.about);
const {navigate} = this.props.navigation;
…
.
.
{ text: 'Done', onPress:() => {
navigate('homeScreen',...params);}
You can get those params like
const {params} = this.props.navigation.state
HomeScreen.js
this.props.navigation.navigate('Screen2',{ user_name: 'aaa',room_id:'100' });
Screen2.js
const params = this.props.route.params;
user_name = params.user_name;
room_id = params.room_id
You can easily send and receive your params with react-navigation like below
Send params:
{
text: 'Done',
onPress: () => {
this.props.navigation.navigate(
HomeScreen,
{param1: 'value1', param2: 'value2'}
);
}
}
Get params in HomeScreen:
const { navigation } = this.props;
var param1 = navigation.getParam('param1', 'NO-VALUE');
var param2 = navigation.getParam('param2', 'NO-VALUE');
the 'NO-VALUE' is default value, if there is not desired param
I am assuming that you are using react-navigation. So, in react-navigation we can pass data in two pieces:
Pass params to a route by putting them in an object as a second parameter to the navigation.navigate function:
this.props.navigation.navigate('RouteName', { /* params go here */ })
Read the params in your screen component:
this.props.navigation.getParam(paramName, someDefaultValue)
Alert Button
<Button
title="Alert View"
onPress={() => {
this.props.navigation.navigate('alerts', {
itemId: 86,
otherParam: 'anything you want here',
});
}}
/>
Screen:
const itemId = navigation.getParam('itemId', 'NO-ID');
const otherParam = navigation.getParam('otherParam', 'some default value')
Screen 1:
<Button title="Go Next"
onPress={() => navigation.navigate('SecondPage', { paramKey: userName })} />
Screen 2:
const SecondPage = ({route}) => {
....
....
<Text style={styles.textStyle}>
Values passed from First page: {route.params.paramKey}
</Text>
....
....
}
I'm following a udemy tutorial on react-native.
I'm trying to pass a prop from my index.js into my header.js. The header should say, "Albums". But is is always showing up blank.
If I remove {props.headerText} from header.js and replace it with
"Albums"
then it works. But I'm trying to make the component reusable per the tutorial instructions.
note: I'm using Create React Native App and this is on an android emulator.
App.js
import React from 'react';
import { View } from 'react-native';
import Header from './src/components/header';
export default class App extends React.Component {
render() {
return (
<Header />
);
}
}
index.js
import React from 'react';
import { Text, AppRegistry } from 'react-native';
import Header from './src/components/header';
const App = () => (
<Header headerText={'Albums'} />
);
AppRegistry.registerComponent('albums', () => App);
header.js
import React from 'react';
import { Text, View } from 'react-native';
const Header = (props) => {
const { textStyle, viewStyle } = styles;
return (
<View style={viewStyle}>
<Text style={textStyle}>{props.headerText}</Text>
</View>
);
};
const styles = {
viewStyle: {
justifyContent: 'center'
},
headerStyle: {
fontSize: 20
}
};
export default Header;
Am I missing anything? I've been over and over each file line by line and I can't find any issues.
Thanks!
I would suggest you
const Header = ({props}) => {
const { textStyle, viewStyle } = styles;
return (
<View style={viewStyle}>
<Text style={textStyle}>{props.headerText}</Text>
</View>
);
};
And to pass props ;
const App = () => (
<Header props={someProps} />
);