How can I send different functions from index in order to re use the footer code? - react-native

Im new in React, and Im starting with React native.
I'm working in my project, and in order to re-use code, I'm reading about HOC.
My use case is: I have a lot of views with a footer that have some buttons (one or two, it depends. They might have different actions, some of them navigates to another activity, other execute functions or state updates).
Im trying to execute a navigation.navigate from the "main" view, but I got an error: "Cant find variable: navigation".
This is my code:
index.js
import {
Text,
StyleSheet,
View,
TouchableOpacity,
ScrollView
} from 'react-native';
import withFooter from '../../components/withFooter';
const SignUp = ({ navigation }) => {
return (
<View style={styles.container}>
<View style={{ flex: 3 }}>
<Text>Test</Text>
</View>
</View>
)
};
export default withFooter(SignUp, {
buttons: [
{
text: 'Exit',
action: () => console.log('Exit'),
},
{
text: 'Accept',
action: () => navigation.navigate('PersonalDataSignUp'),
}
]
});
withFooter.js
import { Text, View, TouchableOpacity, StyleSheet } from 'react-native';
const withFooter = (WrappedComponent, { buttons }) => {
const WithFooter = props => {
return (
<>
<WrappedComponent {...props} />
<View style={{
flexDirection: 'row',
padding: 20
}}>
{
buttons.map(button => (
<TouchableOpacity style={[styles.button]} onPress={button.action}>
<Text style={{ fontWeight: '900' }}>{button.text}</Text>
</TouchableOpacity>
))
}
</View>
</>
)
};
return WithFooter;
};
const styles = StyleSheet.create({
button: {
flex: 1,
height: 50,
borderRadius: 5,
backgroundColor: '#FCCC00',
justifyContent: 'center',
alignItems: 'center',
borderColor: 'black',
borderWidth: 1
},
})
export default withFooter;
How can I send different functions from index in order to re use the footer code? Is there any other way to do it?. Thanks in advance!

Related

Change component style when state is set to certain value

I have a counter that counts down, when the counter hits zero, I would like a style to change. The counter displays properly but the style never changes. How can I get the style to change when the counter hits a certain value?
Below is the code for a very basic example.
import React, { useState, useEffect } from "react";
import { Text, StyleSheet, SafeAreaView, TouchableOpacity, View } from "react-native";
const ActionScreen = () => {
const [timeLeft, setTimeLeft] = useState(4);
const [opac, setOpac] = useState(0.8);
useEffect(() => {
const interval = setInterval(() => setTimeLeft(timeLeft - 1), 1000);
if (timeLeft > 2) {
setOpac(0.8);
console.log("GT");
} else {
setOpac(0.5);
console.log("LT");
}
console.log("opac: ", opac);
if (timeLeft === 0) {
// clearInterval(interval);
setTimeLeft(4);
// setOpac(0.5);
}
return () => {
clearInterval(interval);
};
}, [timeLeft]);
return (
<SafeAreaView style={styles.container}>
<View style={styles.subActionContainer}>
<TouchableOpacity
style={[
styles.topButtons,
{
opacity: opac,
}
]}
>
<Text
style={styles.buttonText}>
{timeLeft}
</Text>
</TouchableOpacity>
</View>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 25,
backgroundColor: 'black',
},
subActionContainer: {
flexDirection: "row",
alignContent: 'space-between',
},
topButtons: {
flex: 1,
backgroundColor: 'orange',
},
buttonText: {
fontSize: 18,
textAlign: 'center',
padding: 10,
color: 'white',
},
buttonFail: {
borderWidth: 1,
marginHorizontal: 5,
}
});
export default ActionScreen;
I'm fairly new to React-Native but read somewhere that some styles are set when the app loads and thus don't change but I have also implemented a Dark Mode on my app that sets inline styling, which works well. Why isn't the styling above changing?
Thank you.
you can create your timer and create a method isTimeOut and when it is true you can change the background
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
import {useTimerCountDown} from './useCountDownTimer'
export default function App() {
const {minutes, seconds, setSeconds} = useTimerCountDown(0, 10);
const isTimeOut = Boolean(minutes === 0 && seconds === 0);
const handleRestartTimer = () => setSeconds(10);
return (
<View style={styles.container}>
<View style={[styles.welcomeContainer,isTimeOut &&
styles.timeOutStyle]}>
<Text>welcome</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: 10,
backgroundColor: '#ecf0f1',
padding: 8,
},
welcomeContainer:{
backgroundColor:'red',
},
timeOutStyle:{
backgroundColor:'blue',
}
});
See the useTimerCountDown hook here in this
working example

Flatlist rendering empty space

i'm new to react native and trying to use flatlist inside another component that's been rendered by another flatlist.
My concern is in the nested flatlist used like this:
Card component
import React, { useContext } from "react"
import { View, Image, Text, StyleSheet, FlatList } from "react-native";
import { QueryContext } from "../context/QueryContext"
function Card(props) {
const [query, setQuery] = useContext(QueryContext)
const { genres_list } = query
const { posterURLs, originalTitle, genres } = props
const listData = []
genres.forEach(genre => {
listData.push({ key: genres_list[genre] })
})
const renderItem = (item) => {
return (
<View>
<Text style={styles.item}>
{item.index}
{item.key}
</Text>
</View>
)
}
return (
<View style={styles.container}>
<Image
style={styles.images}
source={{ uri: posterURLs["original"] }} />
<Text style={styles.title}>{originalTitle}</Text>
<FlatList
data={listData}
renderItem={renderItem}
keyExtractor={(item)=> item.key}
/>
</View>
);
}
const styles = StyleSheet.create({
images: {
width: 400,
height: 500
},
container: {
flex: 1,
backgroundColor: 'lightgrey',
justifyContent: 'center',
alignItems: 'center',
},
title: {
fontSize: 30
},
item: {
padding: 10,
fontSize: 15,
color: "red",
},
})
I have to prepare the data for the flatlist since is inside an object that comes from the context. Weirdly enough i can see the index from item.index but not the item.key which makes me think is some styling issue but as much change i make i'm unable to see it
The card component is rendered by another flatlist and i don't know if that matters or not.
Thanks in advance
Nothing was showing because the data item.key values were actually stored in item.item.key

Why is React Native FlatList not working on Android but it is for Web?

I am using Expo to build a react native app with AWS for the backend.
I am trying to display a list of friends using FlatList and the AWS data. The list works and is visible on my web browser, but for some reason, it is not displaying on my Android phone. What might the issue be?
FriendsList.tsx
import { API, graphqlOperation } from 'aws-amplify';
import * as React from 'react';
import {useEffect, useState} from 'react';
import { FlatList, View, ScrollView, Text, StyleSheet } from 'react-native';
import { listUsers } from '../graphql/queries';
import FriendsListItem from '../components/FriendsListItem';
export default function FriendsList() {
const [ users, setUsers ] = useState([]);
useEffect( () => {
const fetchUsers = async () => {
try {
const usersData = await API.graphql(
graphqlOperation(
listUsers
)
)
setUsers(usersData.data.listUsers.items);
} catch (e) {
}
}
fetchUsers();
},[])
return (
<View style={ styles.container }>
<FlatList
style={{ width: '100%' }}
data={users}
renderItem={({ item }) => <FriendsListItem user={item} />}
keyExtractor={(item) => item.id}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
FriendsListItem.tsx
import * as React from 'react';
import { View, Text, StyleSheet, Image, TouchableWithoutFeedback } from 'react-native';
import { API, graphqlOperation, Auth } from "aws-amplify";
import { User } from './types';
export type FriendsListItemProps = {
user: User;
}
const FriendsListItem = ( props: FriendsListItemProps ) => {
const { user } = props;
return (
<TouchableWithoutFeedback>
<View style={styles.container}>
<View style={styles.lefContainer}>
<Image source={{ uri: user.imageUri }} style={styles.avatar}/>
<View style={styles.midContainer}>
<Text style={styles.username}>{user.name}</Text>
<Text numberOfLines={2} style={styles.status}>{user.email}</Text>
</View>
</View>
</View>
</TouchableWithoutFeedback>
);
}
export default FriendsListItem;
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
width: "100%",
justifyContent: 'space-between',
//height: '100%',
},
lefContainer: {
flexDirection: 'row',
padding: 16,
},
midContainer: {
justifyContent: 'space-around'
},
avatar: {
width: 60,
height: 60,
borderRadius: 50,
marginRight: 15,
},
username: {
fontWeight: 'bold',
fontSize: 16,
},
status: {
fontSize: 16,
color: 'grey',
},
});
Looking at the code example, in your FriendsListItem component, any time you use your "user" prop, you need to change it. For example, change this:
user.imageUri
to this:
user.item.imageUri
What you are passing in is an object (e.g. user), which then contains another object (e.g. item), which finally contains your data (e.g. imageUri).
I figured it out. Turns out I am just an idiot. The expo app on my phone was logged into a different account so that's why it wasn't showing any friends for that user.

Detox - Enter on Numpad

I wonder how to enter the number using native keyboard and then enter it in just like typeText on a normal string on Detox using "\n"
// await typeText('${screen_id}_screen_question_${question_id}_answer_input_', '\n');
How can I achieve this with number?
Whenever I do the typeText ('n') it will give me GREYKeyboard: No known SHIFT key was found in the hierarchy..
In my assumption, because the numpad key doesn't have Enter key. But still not sure why it look for a Shift key.
Thanks
Use Keyboard module from react-native to hide the keyboard.
It's a similar problem to this one: detox-how-to-test-multiline-textinput
Example:
import {Keyboard} from 'react-native'
import React, { Component } from 'react'
import {
AppRegistry,
StyleSheet,
Alert,
TouchableWithoutFeedback,
TouchableOpacity,
View,
Text,
TextInput
} from 'react-native'
class example extends Component {
constructor(props) {
super(props)
}
render() {
return (
<TouchableWithoutFeedback
onPress={Keyboard.dismiss}
style={styles.container}
>
<View style={styles.form}>
<View style={styles.input}>
<TextInput
testID='input'
style={styles.inputText}
keyboardType="numeric"
/>
</View>
<TouchableOpacity
testID='next'
style={styles.button}
onPress={() => Alert.alert("Button pressed")}
>
<Text>Next</Text>
</TouchableOpacity>
</View>
</TouchableWithoutFeedback>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1
},
form: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
input: {
height: 20,
width: 200,
borderColor: 'gray',
borderWidth: 1
},
inputText: {
flex: 1
},
button: {
margin: 20,
padding: 5,
borderColor: 'gray',
borderWidth: 1
}
})
AppRegistry.registerComponent('example', () => example)
Test:
it('Hide num keyboard', async () => {
const inputElement = element(by.id('input'));
await expect(inputElement).toBeVisible();
await inputElement.typeText('1234567890');
// click somewhere outside the input
await inputElement.tapAtPoint({x: 0, y: -1});
const buttonElement = element(by.id('next'));
await expect(buttonElement).toBeVisible();
await buttonElement.tap();
});
Result:

React Native render and switch with navigator onPress

I've just started to develop with React Native a week ago.
Can anyone help me with simple render and switch onPress to another view?
I've read tones of examples, but most of them are cutted or not well documents as if on FaceBook Doc pages. There was no totally completed example with Nav.
Here is what was done yet - View that should be rendered 1st:
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Image,
TextInput,
TouchableHighlight,
TouchableNativeFeedback,
Platform,
Navigator
} from 'react-native';
export default class SignUp extends Component {
buttonClicked() {
console.log('Hi');
this.props.navigator.push({title: 'SignUp', component:SignUp});
}
render() {
var TouchableElement = TouchableHighlight;
if (Platform.OS === ANDROID_PLATFORM) {
TouchableElement = TouchableNativeFeedback;
}
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to Cross-Profi!
</Text>
<Text style={styles.field_row}>
<TextInput style={styles.stdfield} placeholder="Profession" />
</Text>
<Text style={styles.field_row}>
<TextInput style={styles.stdfield} placeholder="E-mail" />
</Text>
<Text style={styles.field_row}>
<TextInput style={styles.stdfield} secureTextEntry={true} placeholder="Password" />
</Text>
<TouchableElement style={styles.button} onPress={this.buttonClicked.bind(this)}>
<View>
<Text style={styles.buttonText}>Register</Text>
</View>
</TouchableElement>
{/* <Image source={require("./img/super_car.png")} style={{width:120,height:100}} />*/}
<Text style={styles.instructions}>
Press Cmd+R to reload,{'\n'}
Cmd+D or shake for dev menu
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'lightblue',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
color: 'darkred',
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
field_row: {
textAlign: 'center',
color: '#999999',
margin: 3,
},
stdfield: {
backgroundColor: 'darkgray',
height: 50,
width: 220,
textAlign: 'center'
},
button: {
borderColor:'blue',
borderWidth: 2,
margin: 5
},
buttonText: {
fontSize: 18,
fontWeight: 'bold'
}
});
const ANDROID_PLATFORM = 'android';
Navigator class that should render different views:
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Platform,
Navigator
} from 'react-native';
var MainActivity = require('./app/MainActivity.js');
var SignUp = require('./app/SignUp.js');
class AwesomeProject extends Component {
/*constructor(props) {
super(props);
this.state = {text: ''};
}*/
render() {
// this.props.navigator.push({title:'SignUp'});
return (
<Navigator initialRoute={{title:'SignUp', component:SignUp}}
configureScene={() => {
return Navigator.SceneConfigs.FloatFromRight;
}}
renderScene={(route, navigator) =>
{
console.log(route, navigator);
if (route.component) {
return React.createElement(route.component, {navigator});
}
}
} />
);
}
}
const ANDROID_PLATFORM = 'android';
const routes = [
{title: 'MainActivity', component: MainActivity},
{title: 'SignUp', component: SignUp},
];
AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject);
It doesn't seem to be clear whether there must be require of a class and declaration of class as export default.
There is an error: Element type is invalid: expected a string, ... but got object etc
Help with examples would be great. Thx
In your require call, you should either replace it import statement or use default property of require module i.e:
var MainActivity = require('./app/MainActivity.js').default;
or use
import MainActivity from "./app/MainActivity";
In ES6, require doesn't assign default property of module to variable.
See this blog post for better understanding of require working in es6