React Native navigation get param as an array and map the array - javascript

I need to change data between 2 different screens using react-navigation. The default screen shows the notes and adding the note is done in a separate screen using text input. Adding screen needs to give an array to default screen.
I managed to give some parameter but adding screen should pass an array.
Adding note class. Text input makes a new addition to notes state.
class AddScreen extends React.Component {
constructor(props) {
super(props);
}
state = {
textInputComponent: '',
notes: [
{
text: "Note 1"
}
]
}
return(
<View>
<TextInput style = {styles.inputField} placeholder="Write the note here"
onChangeText={(textInputComponent) => this.setState({textInputComponent})}
value = {this.state.textInputComponent} />
<TouchableOpacity style = {styles.customBtn2}
onPress={() => {this.addToList(this.state.textInputComponent)}}>
<Text style = {styles.customBtnText}>Add note </Text>
</TouchableOpacity>
<TouchableOpacity style = {styles.customBtn3}
onPress={() => navigate('Notes', {note: this.state.notes})}>
<Text style = {styles.customBtnText2}>Add notes </Text>
</TouchableOpacity>
</View>
);
The default screen where notes should be showing
class NoteList extends React.Component {
constructor(props) {
super(props)
this.state = {
notes: []
}
}
makeNoteList(note){
this.state.notes.push(note);
console.log(this.state.notes);
return (
<View>
{this.state.notes.map(note => {console.log(note.text)})}
</View>
)
}
render() {
const {navigate} = this.props.navigation;
const {navigation} = this.props;
const note = navigation.getParam('note', 'No notes');
return(
<ScrollView style = {styles.background}>
<View style={{flex: 1,
flexDirection: 'column',
alignItems: 'center'}}>
{this.makeNoteList(note)}
</View>
<View style={{flex: 1,
flexDirection: 'row',
justifyContent: 'flex-end'}} >
<TouchableOpacity style = {styles.customBtn}
onPress={() => navigate('AddNotes', {name: 'AddNotes'})}>
<Text style = {styles.customBtnText}>List of notes </Text>
</TouchableOpacity>
</View>
</ScrollView>
)
}
}
I can't seem to map the parameters that AddScreen class gives. Default screen should map this given array to show notes. I'm aware that these code snippets are missing some curly brackets and maybe brackets to shorten these snippets so here you can see the whole code: https://snack.expo.io/rk4opjbqE

Related

React Native/TypeScript - How to manage state in functional component and apply flexible style with FlatList

Can anyone tell me how to solve these things?
1.if the list is pressed, I'd like to change the background color of the list
beige(#FFF5E7) to white(#FBFBFB)
2.Also, I'd like to change the read value of the Object fales to true with useState
Problem is that if I pressed the list, whole background color of the list will be changed.
index.tsx
import React, { useState } from 'react';
import { Text, View, TouchableOpacity, FlatList } from 'react-native';
import { useNavigation } from '#react-navigation/native';
import { DETAIL } from '../../sample';
import { Object } from './sample';
export default function sample() {
const [state, setState] = useState(Object);
const navigation = useNavigation();
let Element;
const renderItem = ({ item }) => {
const readState = () => {
navigation.navigate(NOTICE_DETAIL);
const readValue = [...state];
let value = { ...readValue[0] };
value.read = true;
readValue[0] = value;
setState(readValue);
};
if (state[0].read) {
Element = (
<TouchableOpacity onPress={readState}>
<View style={[styles.row, { backgroundColor: '#FBFBFB' }]}>
<View style={styles.container}>
<View style={styles.end}>
<Text style={styles.text}>{item.text}</Text>
<Text style={styles.time}>{item.time}</Text>
</View>
<Text style={styles.content}>{item.content}</Text>
</View>
</View>
</TouchableOpacity>
);
} else {
Element = (
<TouchableOpacity onPress={readState}>
<View style={[styles.row, { backgroundColor: '#FFF5E7' }]}>
<View style={styles.container}>
<View style={styles.end}>
<Text style={styles.text}>{item.text}</Text>
<Text style={styles.time}>{item.time}</Text>
</View>
<Text style={styles.content}>{item.content}</Text>
</View>
</View>
</TouchableOpacity>
);
}
return Element;
};
}
return (
<View style={{ flex: 1 }}>
<FlatList
extraData={Object}
data={Object}
renderItem={renderItem}
/>
</View>
);
}
Object.ts
export const Object = [
{
id: 1,
text: 'testtesttest',
content: 'testtesttest'
read: false
},
{
id: 2,
text: 'testtesttest',
content: 'testtesttest'
read: false
}
id: 3,
text: 'testtesttest',
content: 'testtesttest'
read: false
}
]
We can add inline styles into the component style props along with static styles,
For Example:
<TouchableOpacity onPress={readState}>
<View style={[styles.row, { backgroundColor: item.read ? '#FBFBFB' : 'FFF5E7' }]}>
<View style={styles.container}>
<View style={styles.end}>
<Text style={styles.text}>{item.text}</Text>
<Text style={styles.time}>{item.time}</Text>
</View>
<Text style={styles.content}>{item.content}</Text>
</View>
</View>
</TouchableOpacity>
Problem in your readState function and if (state[0].read) {. You always change item with index 0 and then check state[0].read for all elements of your array.

Passing data to routes navigation React Native

I made a screen of a flatlist that displays a bunch of Doctors infos(name,location,Picture),when i click on a doctor view it navigates to his profil. for the moment the profil screen is just blank, but i want to pass the params so i can just display them without re doing the api call.
here is the code of the research screen where the flatlist is:
render(){
return (
<View style={styles.main_container}>
<FlatList
data={this.state.dataSource}
keyExtractor={item=> item.id.toString()}
renderItem= {({item})=> <MedItem Med={item} />} />
</View>
);
}
i created a component custom med item to style my flat list:
//Meditem.js
class MedItem extends React.Component {
render(){
const Med = this.props.Med
return (
<View style={styles.main_container} >
<View style={styles.ctr1}>
<TouchableOpacity onPress={()=>NavigationService.navigate('MedProfil')}>
<Image style={styles.img} source={require('../assets/Title.jpg')} />
</TouchableOpacity>
<TouchableOpacity onPress={()=>NavigationService.navigate('MedProfil')}>
<Text style={styles.txt}> {Med.name} </Text>
<Text style={{flexWrap:'wrap'}} > {Med.specialite} </Text>
<Text> {Med.work} </Text>
</TouchableOpacity>
</View>
<View style={styles.ctr2}>
<Text style={{textAlign:'center',marginBottom:5}}>Disponibilité</Text>
<Calendar/>
</View>
</View>
);
}
}
last this is my doctor profil screen:
export default class MedProfilScreen extends React.Component {
render(){
return(
<View>
<Text>{Med.name}</Text>
<Button title='Prendre rendez-vous' onPress={()=>{}} />
</View>
);
}
}
Can someone please help me doing this.
thank you
Send Data through navigation like this
this.props.navigation.navigate("MedProfil",
{
name:Med.name
})
Get data in MedProfil Screen
const name=this.props.navigation.getParam("name")
In your Sending component use this:
constructor(props) {
super(props);
this.navigate = this.props.navigation.navigate;
}
//Send it like this
this.navigate("MedProfilScreen", { name:Med.name });
In your receiving component
constructor(props) {
super(props);
this.params = this.props.navigation.state.params;
}
//Can access it using
console.log(this.params.name);
thank you everyone! getParam won't work for me.
i used this to solve the problem
//MedItem.js
<TouchableOpacity onPress={()=>NavigationService.navigate('MedProfil',Med)}>
and in the profil screen
//MedProfil.js
export default function MedProfilScreen({route}){
const {name,specialite,work}=route.params;
return(
<ScrollView contentContainerStyle={{flex:1,alignItems:'center'}}>
<View style={styles.ctr1}>
<Text>{name}</Text>
<Text>{specialite}</Text>
<Text>{work}</Text>

How to pass and execute functions as props in class Component in React Native?

I'm a beginner in React Native and struggling in passing and executing functions as props from parent to child component. Here's the code:
MainMap
import React from 'react';
import {
TouchableWithoutFeedback,
StyleSheet,
View,
Button,
FlatList,
Dimensions
} from 'react-native';
import PlaceInput from '../components/PlaceInput';
const INCREMENT = 1;
const HEIGHT = Dimensions.get('window').height
const WIDTH = Dimensions.get('window').width
class MainMap extends React.Component{
constructor(props){
super(props);
this.state={
numOfInput:[],
counter: 0,
}
this.onAddSearch = this.onAddSearch.bind(this)
this.onDeleteSearch = this.onDeleteSearch.bind(this)
}
onAddSearch(){
this.setState((state) => ({
counter: state.counter + INCREMENT,
numOfInput: [...state.numOfInput, state.counter]
}))
}
onDeleteSearch(inputId){
const items = this.state.numOfInput.filter(item => item.id !== inputId)
this.setState({
numOfInput: items
})
}
render(){
return(
<TouchableWithoutFeedback onPress={this.hideKeyboard} >
<View style={styles.container} >
<Button title='Add a location' onPress={this.onAddSearch} />
<View style={{height: HEIGHT/2 }}>
<FlatList
data={this.state.numOfInput}
keyExtractor={(item, index) => item.id}
renderItem={itemData => {
return(
<PlaceInput
key={itemData.item.id}
// id={itemData.item.id}
onDelete={this.onDeleteSearch}
showDirectionOnMap={this.showDirectionOnMap}
userLatitude={userLatitude}
userLongitude={userLongitude}
/>
)
}}
/>
</View>
</View>
</TouchableWithoutFeedback>
)
}
}
export default MainMap;
const styles = StyleSheet.create({
container:{
flex: 1
},
})
Here's the PlaceInput component
class PlaceInput extends React.Component{
constructor(props){
super(props);
... // These lines have no relation to what I'm asking so don't mind them
}
...
render(){
return(
<View style={styles.buttonContainer} >
<View style={{flex: 1, alignItems: 'center'}}>
<Text style={{fontSize: 8}}>{'\u25A0'}</Text>
</View>
<View style={{flex: 4}}>
<TextInput
autoCorrect={false}
autoCapitalize='none'
style={styles.inputStyle}
placeholder='Search your places'
onChangeText={(input) => {
this.setState({destinationInput: input});
this.getPlacesDebounced(input);
}}
value={this.state.destinationInput}
/>
{/* {predictions} */}
</View>
<View style={styles.rightCol}>
<TouchableOpacity onPress={this.props.onDelete.bind(this, this.props.id)}>
<Ionicons name='md-car' size={25} style={{alignSelf: 'center'}} />
</TouchableOpacity>
</View>
</View>
)
}
}
What I'm trying to do:
Define a function to execute in MainMap.js (in FlatList --> PlaceInput for specific) , which is to delete an search bar( the whole PlaceInput in the FlatList) every time I click the right symbol of that search bar. The function is onDeleteSearch
The right symbol is styled in a TouachableOpacity as you can see in the PlaceInput.js component. I put it in the last View pair
However, When I click, the screen deletes all the search bars, not the one I click. Is it the problem of the id of the component PlaceInput ? Or with the way I call the props?...
Please help me !
<TouchableOpacity onPress={this.props.onDelete.bind(this, this.props.id)}>
<Ionicons name='md-car' size={25} style={{alignSelf: 'center'}} />
</TouchableOpacity>
Don't bind, just call this.props.onDelete(this.props.id);
In MainMap, try this:
<PlaceInput
key={itemData.item.id}
// id={itemData.item.id}
onDelete={() => this.onDeleteSearch(itemData.item.id)} // here
showDirectionOnMap={this.showDirectionOnMap}
userLatitude={userLatitude}
userLongitude={userLongitude}
/>
Assuming the function:
onPressed(optionalArgument = false) {
// do something
}
You can pass a function to onPress if it does not require any arguments, i.e
onPress={onPressed} // - would work if no arguments required.
onPress={onPressed(argument)} // - will get fired on component render
onPress={()=> onPressed(argument)} // - will work as expected on button press
onPress={()=> { // - will work as expected on button press
// Multiple lines of code
onPressed(argument);
anotherFunction();
}
};
In your MainMap you are doing everything correctly, just uncomment the
// id={itemdata.item.id}
In PlaceInput, just one small change:
<TouchableOpacity onPress={() => this.props.onDelete(this.props.id)}>
<Ionicons name='md-car' size={25} style={{alignSelf: 'center'}} />
</TouchableOpacity>
If you don't add ()=> to your onPress, the function gets called immediately, that's why you see such behaviour.
Your numOfInput is just a list of numbers, so instead of using item.id-s use item directly.
Here:
const items = this.state.numOfInput.filter(item => item !== inputId)
And here
<PlaceInput
key={itemData.item}
// id={itemData.item}
...
/>

How to avoid jsx styling error in react native?

Whenever I tried to build UI from scratch I'm getting this error adjacent jsx element must be wrapped in an enclosing tag. I don't know how to solve this. Because I tried different methods, I've tried to put the blocks within View component withflex:1 but non-use. Is there any proper solution for this. This is becoming a great challenge for me because I can't design any components of my own. What to do please help me. Following is my code.
screen.js
export default class FirstScreen extends Component {
constructor(props){
super(props);
this.state = {
showPopupDialog: false,
workType: "",
workers: []
}
}
componentWillMount(){
fetch('http://192.168.1.6:3000/api/worker', {
method:'GET',
headers:{
Accept: 'application/json'
}
})
.then(response => response.json())
.then(responseData =>
this.setState({
workers:responseData
})
)
}
onPressYes = (workType) => {
console.log(workType);
}
popupDialog = (id, workType) => {
this.setState ({
showPopupDialog: true,
workType: workType
});
//make sure you set showPopupDialog to false and workType to "" when you click yes or no button in PopupDialog component so that it will work the next time you click on card
}
render() {
const { workers, workType, showPopupDialog} = this.state;
return (
<View style={{flex:1}}>
<Header />
<ScrollView>
{workers.map((a, index)=> (
<View style={{flex:1}}>
<CardSection>
<TouchableOpacity onPress={() => this.popupDialog(a.id, a.work_type)}>
<View style={{ maringTop: 10, marginLeft:120}}>
<Image style={{ height: 100, width: 100 }} source={{ uri: a.work_type == 'Carpenter' ? images[0].image : images[1].image}}/>
<Text style={{marginLeft:20, fontSize:20}}>{a.work_type}</Text>
</View>
</TouchableOpacity>
</CardSection>
</View>
))}
{showPopupDialog && <PopupDialog
dialogStyle={{ backgroundColor: "#FFFFFF", height: 180, width:300, borderWidth:1,padding:10}}
overlayBackgroundColor="#fff" dismissOnTouchOutside={true}>
<View style={styles.dialogContentView}>
<Text style={{fontSize:18, margingTop:10,color:"#000000"}}>Are you sure you want to submit?</Text>
<View style={{flexDirection:'row'}}>
<View style={styles.button_1}>
<Button title="Yes" color="#FF6633" onPress={() => this.onPressYes(workType)}/>
</View>
<View style={styles.button_1}>
<Button title="No" color="#FF6633" onPress={() =>this._onPressNo() }/>
</View>
</View>
</View>
</PopupDialog>}
</ScrollView>
</View>
);
}
}
The issue I'm facing is I can't place the <PopupDialog> component adjacent to <CardSection> , in order to that I put the <PopupDialog> within <View> ,even though it doesn't solve my issue.Please help..Please
Give a try with below corrected code.
There are two things that needs be corrected
You are doing .map but you are not returning anything which I have
corrected in the code below
export default class FirstScreen extends Component {
constructor(props){
super(props);
this.state = {
workType: "",
workers: []
}
}
componentWillMount(){
fetch('http://192.168.1.6:3000/api/worker', {
method:'GET',
headers:{
Accept: 'application/json'
}
})
.then(response => response.json())
.then(responseData =>
this.setState({
workers:responseData
})
)
}
onPressYes = (workType) => {
console.log(workType);
}
popUpDialog = (id, workType) => {
this.setState ({
workType: workType
});
this.popupDialog.show();
//make sure you set workType to "" when you click yes or no button in PopupDialog component so that it will work the next time you click on card
}
render() {
const { workers, workType} = this.state;
return (
<View style={{flex:1}}>
<Header />
<ScrollView>
{workers.map((a, index)=> (
<View style={{flex:1}}>
<CardSection>
<TouchableOpacity onPress={() => this.popUpDialog(a.id, a.work_type)}>
<View style={{ maringTop: 10, marginLeft:120}}>
<Image style={{ height: 100, width: 100 }} source={{ uri: a.work_type == 'Carpenter' ? images[0].image : images[1].image}}/>
<Text style={{marginLeft:20, fontSize:20}}>{a.work_type}</Text>
</View>
</TouchableOpacity>
</CardSection>
</View>
))}
<PopupDialog ref={popupDialog => {
this.popupDialog = popupDialog;
}}
dialogStyle={{ backgroundColor: "#FFFFFF", height: 180, width:300, borderWidth:1,padding:10}}
overlayBackgroundColor="#fff" dismissOnTouchOutside={true}>
<View style={styles.dialogContentView}>
<Text style={{fontSize:18, margingTop:10,color:"#000000"}}>Are you sure you want to submit?</Text>
<View style={{flexDirection:'row'}}>
<View style={styles.button_1}>
<Button title="Yes" color="#FF6633" onPress={() => this.onPressYes(workType)}/>
</View>
<View style={styles.button_1}>
<Button title="No" color="#FF6633" onPress={() =>this._onPressNo() }/>
</View>
</View>
</View>
</PopupDialog>
</ScrollView>
</View>
);
}
}
If I understand your question correctly...
You can return multiple root elements in jsx by wrapping is in a <React.Fragment> element (you can use <> and </> in v16.2 and later). Fragments are new in React v16. Prior to that, you just have to wrap them in some element (a div or span, usually).
The problem is that you have this structure:
<a>
{this.state.workers.map((a, index)=>
<b/>
<c/>
)}
</a>
Since <b/><c/> is parsed separately and there's no enclosing element, you're getting the error. But an enclosing element isn't necessary for the final structure, which does have an enclosing element. The solution is to simply return an array of JSX elements, like this:
<a>
{this.state.workers.map((a, index)=>
[<b/>,
<c/>]
)}
</a>

Cannot display array in React Native

When i press the <TouchableOpacity> Button, i want the value 'abc' to be appended to the array selectedTags and then <Text> {this.list()} </Text> will print out my array.
But now when i press the Button, nothing display out.
Can anybody know what is the problem with my code?
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
selectedTags: []
}
}
list() {
return this.state.selectedTags.map(function(tags, i){
return(
<View key={i}>
<Text>{tags.name}</Text>
</View>
);
});
}
render() {
return (
<View style={styles.container}>
<TouchableOpacity onPress={() => this.state.selectedTags.push('abc')} key = {1} style={styles.buttonContainer}>
<Text style={styles.buttonText}> Button </Text>
</TouchableOpacity>
<Text> {this.list()} </Text>
</View>
);
}
}
This is because you never call setState, which would trigger re-render of your component.
instead of using:
onPress={() => this.state.selectedTags.push('abc')}
try:
onPress={() => this.setState({selectedTags: this.state.selectedTags.concat('abc')})}
The function list only push data in array but does not rerender the view, todo so you have to use setState or forceUpdate.
You can implement the onpress function like this.
onPress = () =>{
this.state.selectedTags.push("abc");
this.setState({selectedTags : this.state.selectedTags});
}

Categories

Resources