How to send data to another component in react-native - react-native

I want to pass data to another component but not like this.
return (
<View style = {{flex:1}}>
---> <LoginForm profile = {this.state.values}/> // I dont want to send like this
<Animated.View style={{ ...this.props.style, opacity: fadeAnim }} >
{this.props.children}
</Animated.View>
</View>
);
because if I do like this, this component includes LoginForm as well. and also I dont want to send with navigate. Because I dont want to open that component on screen. when I work in this screen I just want to send values to another component

You need to pass a function to mutate the state from LoginForm to this child component.
On LoginForm,
<View>
...
<ChildComponent changeProfile={(profile) => {
this.setState({
profile: profile
})
}}/>
</View>
then on this ChildComponent, call
this.props.changeProfile(this.state.values);
Or you can try a state management library too, like Redux or MobX. Personally, I prefer Redux.

Related

useEffect not working in custom drawer component without refresh

So I am using react-navigation 5 and I have a custom drawer component for my app. I want to display the name of the logged-in user in the drawer for which I am using a state variable and I am updating the state from firestore. I am calling a function in useEffect which accesses firestore and gets the name of the user. But I think the useEffect is not working without refresh because unless I save the project and refresh the application the state is not getting updated in the application and I cannot see the name of the user without refreshing but it is visible after a refresh. Any ideas why this is happening? Any help would be appreciated. Thank you.
Custom drawer
export default function CustomDrawer(props) {
const paperTheme = useTheme();
const [name,setName]=useState('');
useEffect(() => {
doStuff();
}, []);
const doStuff = async () => {
var phone=global.phone;
await firestore().collection("Users").where('Phone Number', '==', phone).get().then(querySnapshot=>{
querySnapshot.forEach(documentSnapshot => {
console.log("in drawer");
console.log(documentSnapshot.data());
setName(documentSnapshot.data().Name);
})
})
};
return(
<View style={{flex:1}}>
<DrawerContentScrollView {...props}>
<View style={styles.drawerContent}>
<View style={styles.userInfoSection}>
<View style={{flexDirection:'row',marginTop: 15}}>
<Avatar.Image
source={{
uri: ''
}}
size={50}
/>
<View style={{marginLeft:15, flexDirection:'column'}}>
<Title style={styles.title}>{name}</Title>
</View>
</View>
</View>
</View>
</DrawerContentScrollView>
</View>
);
}
Looks like you have doStuff function defined outside the useEffects.
Either you need to put it inside useEffects or add it in dependency list
useEffect(() => {
doStuff();
}, [doStuff]);

props data not being rendered

I'm trying to display some data in a FlatList. the data comes from a json file and is mapped to the component props using redux. I can console.log the props data from inside my component but i cant get to render it on screen. (this.props.library.title). Instead I have an empty list.
I'm following a udemy course and i'm pretty sure i followed the steps exactly
here is my child component :
class ListItem extends Component{
render(){
//const _this = this;
const {title,id}=this.props.library ;
console.log(this.props);
return(
<TouchableWithoutFeedback onPerss={()=> this.props.selectLibrary(id)}>
<View>
<CardSection>
<Text style={styles.textStyle}>
{title}
</Text>
</CardSection>
</View>
</TouchableWithoutFeedback>
);
}
}
const styles ={
textStyle:{
fontSize:18,
padding:5
}
}
export default connect(null,actions)(ListItem);
here is the console log :
https://imgur.com/pd2qbkt
you should put an item after this.props.library
like this
const { title, id } = this.props.library.item

How do I handle press and unpress touchable component with style changes?

The idea is to create a specific Touchable component acting like a button and have a feeling of pressed and unpressed, and using this component many times on my app but only one can be pressed at a time. If one is touched and then another one is touched, the first one should be unpressed and the second one should be pressed. The idea is not to use Redux to solve this problem.
I'm already handling which component was pressed, and sending through props the actions to the component. But i don't know how to manage all buttons at the same time in a generic way, by that I mean, not creating a variable to each button.
my App:
<View>
<ActivityButton activityTitle={"B1"} submit={() => this.submitHandler("B1")} />
<ActivityButton activityTitle={"B2"} submit={() => this.submitHandler("B2")} />
</View>
my Component (ActivityButton):
this.state={active:false}
<TouchableOpacity style={this.state.active ? styles.buttonPress : styles.button} onPress={this.props.submit}>
<View>
<Text>{this.props.activityTitle}</Text>
</View>
</TouchableOpacity>
I assume what you trying to do something like a Radio button groups? If your buttons only located in single page, you can achieve by using state in MyApp to check which buttons is enabled instead of button itself.
MyApp
constructor(props) {
super(props);
this.state = {
buttonIdThatEnable: "",
};
}
submitHandler = (buttonId) => {
this.setState({
buttonIdThatEnable: buttonId,
});
}
render() {
return (
<View>
<ActivityButton
activityTitle={"B1"}
active={this.state.buttonIdThatEnable === "B1"}
submit={() => this.submitHandler("B1")}
/>
<ActivityButton
activityTitle={"B2"}
active={this.state.buttonIdThatEnable === "B2"}
submit={() => this.submitHandler("B2")}
/>
</View>
)
}
ActivityButton (Use props.active to determine style)
<TouchableOpacity style={this.props.active ? styles.buttonPress : styles.button}
onPress={this.props.submit}>
<View>
<Text>{this.props.activityTitle}</Text>
</View>
</TouchableOpacity>
If your Buttons are located in different components and you do not want to use Redux, you may consider the React Context API

Create a reusable React Native Modal Component

I'm going back to basics with React Native, as I feel overwhelmed. I have been looking for an implementation of a reusable modal component. I'm looking for examples of a reusable Modal component in RN? Thanks in advance
You can find many examples of this on StackOverflow. Still, if you need example I can help you with one example. You have mentioned modal component in your question, right?
Your component will look like this with props. let the name be ModalComponent for this file.
render() {
const { isVisible, message, textValue } = this.props;
return (
<Modal
animationType="slide"
transparent={false}
isVisible={isVisible}
backdropColor={"white"}
style={{ margin: 0 }}
onModalHide={() => {}}>
<View>
<Text>textValue</Text>
<Text>message</Text>
</View>
</Modal>
);
}
so now in your js file you need to import this modalComponent and after that, you need to write as
<ModalComponent
isVisible={true}
textValue={'hi there'}
message={'trying to make a basic component modal'}/>
Hope this will help for you
EDIT:
Create seperate components that you want to render inside modal. for Ex: component1.js, component2.js, component3.js with props
component1.js:
render(){
const { textVal, message } = this.props
return (
<View>
<Text>{textVal}</Text>
<Text>{message}</Text>
</View>
)
}
now in ModalComponent
render() {
const { first, second, third, isVisible, component1Text, component1Message } = this.props;
<Modal
animationType="slide"
transparent={false}
isVisible={isVisible}
backdropColor={"white"}
style={{ margin: 0 }}
onModalHide={() => {}}>
<View>
{first && <component1
textValue= component1Text
message= component1Message />}
{second && <Component2 />}
{third && <Component2 />}
</View>
</Modal>
In this way, you can achieve it within the single modal.
You will make a component like this giving the parent component all the liberty to change it through props.
render() {
const { isVisible, message, textValue, animationType, backDropColor, style, onModalHide, children } = this.props;
return (
<Modal
animationType= {animationType || 'slide'}
transparent={transparent || false}
isVisible={isVisible || false}
backdropColor={backdropColor || "white"}
style={[modalStyle, style]}
onModalHide={onModalHide}>
{children}
</Modal>
);
}
Then in your parent component, you need to import this component like this:
import ModalComponent from '../ModalComponent'; //path to your component
<ModalComponent isVisible={true}>
<View>
//any view you want to be rendered in the modal
</View>
</ModalComponent>
I had a lot of troubles using react-native modal, sometimes i started the app and could not close it even when i set the isVisible prop to false, it is even worst on IOs, i did a research and these packages are not being maintained properly.
You will save a lot of time by using a top-level navigator like is recommended in the modal docs: https://facebook.github.io/react-native/docs/modal.
I tried https://github.com/react-native-community/react-native-modal but had the same problems because its an extension of the original react-native modal.
I suggest you to use the react-navigation modal as described here: https://reactnavigation.org/docs/en/modal.html#docsNav
You can refer the following code to write Modal component once and use multiple times.
Write once:
import React, { Component } from 'react';
import { View, Text, Button, Modal, ScrollView, } from 'react-native';
export class MyOwnModal extends Component {
constructor(props) {
super(props);
this.state = {
}
render() {
return(
<Modal
key={this.props.modalKey}
transparent={this.props.istransparent !== undefined ? true : false}
visible={this.props.visible}
onRequestClose={this.props.onRequestClose}>
<View style={{
//your styles for modal here. Example:
marginHorizontal: width(10), marginVertical: '30%',
height: '40%', borderColor: 'rgba(0,0,0,0.38)', padding: 5,
alignItems: 'center',
backgroundColor: '#fff', elevation: 5, shadowRadius: 20, shadowOffset: { width: 3, height: 3 }
}}>
<ScrollView contentContainerStyle={{ flex: 1 }}>
{this.props.children}
</ScrollView>
</View>
</Modal>
);
}
}
Now,
You can call your Modal like following example: (By doing this, you avoid re-writing the Modal and its outer styles everytime!)
Example
<MyOwnModal modalKey={"01"} visible={true} onRequestClose={() =>
this.anyFunction()} istransparent = {true}>
<View>
// create your own view here!
</View>
</MyOwnModal>
Note: If you are in using different files don't forget to import , and also you can pass the styles as props.
(You can create/customise props too based on your requirement)
Hope this saves your time.
Happy coding!
I am a contributor of react-native-use-modal.
This is an example of creating a reusable modal in a general way and using react-native-use-modal: https://github.com/zeallat/creating-reusable-react-native-alert-modal-examples
With react-native-use-modal, you can make reusable modal more easily.
This is a comparison article with the general method: https://zeallat94.medium.com/creating-a-reusable-reactnative-alert-modal-db5cbe7e5c2b

Passing State to another Component in React Native

React Native Newbie here.
I have an (in my opinion) common use case here. I work with React Navigation and have 4 different Tabs. In the first Tab I have a FlatList from which I want to choose Favourites. These Favourites should be then listed in the other Tab. Nothing more so far.
The Problem I encounter is that I'm not figuring out how I can transmit the favourites variable declared in my state of the first tab, to the other Tab. Maybe the approach is completely wrong too..
First Tab/Screen:
import React, {Component} from 'react';
import { FlatList, Text, View, ScrollView, Image, TouchableHighlight} from 'react-native';
import Icon from 'react-native-vector-icons/Ionicons'
export default class HomeScreen extends Component {
state = {
data: [],
favourites: []
};
//Function called on the click of the Heart Button, adding the List Element to the State
addFav = item => {
this.setState((prevState) => ({'favourites': prevState.favourites+item.title+' '}))
alert(item.title)
}
componentWillMount() {
this.fetchData();
}
//Fetching the data from the API
fetchData = async () => {
const response = await fetch("http://192.168.1.19:8080/v1/api/event");
const json = await response.json();
this.setState({ data: json});
};
render() {
return <FlatList
ItemSeparatorComponent={() =>
<View
style={{ height: 1, width: '100%', backgroundColor: 'lightgray' }}
/>
}
data={this.state.data}
keyExtractor={(item => item.title)}
renderItem={({ item }) =>
<ScrollView>
<Image style={{alignSelf:'stretch', width:undefined, height:undefined, flex : 1, borderRadius:10}} source = {require('../img/landscape.jpeg')}/>
<TouchableHighlight onPress={()=>this.openEvent(item)}>
<View style={{flex: 1, flexDirection:'row', padding: 5}}>
<View style={{flex: 1}}>
<Text style={{fontSize:15, textAlign:'center', padding: 2}}>{this.timeConverterMonth(item.time)}</Text>
<Text style={{fontSize:15, textAlign:'center', padding: 2}}>{this.timeConverterDay(item.time)}</Text>
</View>
<View style={{flex: 4}}>
<Text style={{fontSize:15, padding: 2}}>{item.title}</Text>
<Text style={{fontSize:10, padding: 2}}>{item.locShort}</Text>
</View>
//That's where the function is called
<TouchableHighlight
style={{flex: 2}}
onPress={() => this.addFav(item)}
>
<Icon name="ios-heart-empty" size={24} style={{alignSelf: 'center', padding: 10}}/>
</TouchableHighlight>
</View>
</TouchableHighlight>
//just checking the state
<Text>{this.state.favourites}</Text>
</ScrollView>}
/>;
}
}
Second Tab/Screen:
import React, {Component} from 'react';
import {Text} from 'react-native';
export default class FavouritesScreen extends Component {
constructor(props){
super(props)
}
render(){
//Here I want to display my favourites Array from the HomeScreen State
return <Text>{this.props.favourites}</Text>;
}
}
I am actually not wondering why it's not functioning, I just tried the props method by reading all the other articles but the Screens are not in Parent/Child relation.
So what I want to do would be in the Second Tab something like
HomeScreen.state.favourites
Thanks.
Your case is a very common one. One I faced was passing a 'shared state' between the application.
The components have a local state, which you can pass to child components via props (which you have mentioned).
The problem arises when you want to access that state in another component. The solution here is having a global state.
You may want to consider Redux for your application.
https://redux.js.org/introduction/getting-started
From the redux website:
Redux is a predictable state container for JavaScript apps.
It helps you write applications that behave consistently, run in
different environments (client, server, and native), and are easy to
test. On top of that, it provides a great developer experience, such
as live code editing combined with a time traveling debugger.
Essentially, you'll be getting a global state which can be accessed by all your application's components. This allows you to update states within one component and access them in another.
I will warn you, it's not the easiest thing to learn. When you first look at it - it's a bit daunting. But, as your application grows in complexity and you add more state - you'll be glad you used it.
The good news is, Redux is very well documented with React and React Native - so you should find lots of tutorials on how to integrate it into your current application.
Your usecase of having "globally" accessed state is where state management libraries come in. One good example is the libary Redux - in this case you could store the favourites under a piece of state called "HomeScreen" and map it and use it in any screen in the rest of the app.
Here is a good article about getting started with redux: https://blog.cloudboost.io/getting-started-with-react-native-and-redux-6cd4addeb29