I made 2 screens home and editing screen. I want to change values from edit screen without redux and context but I don't know how? and also when I click save in editscreen it's throwing error that undefined is not an object (evaluating '_this.props.navigation.goBack') and displaing blank home screencwhy that's happening. Can some one help me please, below is my code
home.js
class Home extends Component {
state = {
modal: false,
editMode: false.
post: [
{
key: "1",
title: "A Good Boi",
des: "He's a good boi and every one know it.",
image: require("../assets/dog.jpg"),
},
{
key: "2",
title: "John Cena",
des: "As you can see, You can't see me!",
image: require("../assets/cena.jpg"),
},
],
};
addPost = (posts) => {
posts.key = Math.random().toString();
this.setState((prevState) => {
return {
post: [...prevState.post, posts],
modal: false,
};
});
};
onEdit = (data) => {
this.setState({ post: { title: data }, editMode: false });
};
render() {
if (this.state.editMode)
return <EditScreen item={item} onEdit={this.onEdit} />;
return (
<Screen style={styles.screen}>
<Modal visible={this.state.modal} animationType="slide">
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View style={styles.modalContainer}>
<AddPost addPost={this.addPost} />
</View>
</TouchableWithoutFeedback>
</Modal>
<FlatList
data={this.state.post}
renderItem={({ item }) => (
<>
<TouchableOpacity
activeOpacity={0.7}
onPress={() => this.setState({ editMode: true })}
style={styles.Edit}
>
<MaterialCommunityIcons
name="playlist-edit"
color="green"
size={35}
/>
</TouchableOpacity>
<Card>
<Image style={styles.image} source={item.image} />
<View style={styles.detailContainer}>
<Text style={styles.title} numberOfLines={1}>
{item.title}
</Text>
<Text style={styles.subTitle} numberOfLines={2}>
{item.des}
</Text>
</View>
</Card>
</>
)}
/>
</Screen>
Edit.js
import React, { Component } from "react";
import { View, StyleSheet, Image, KeyboardAvoidingView } from "react-native";
import colors from "../config/colors";
import AppButton from "../components/AppButton";
import AppTextInput from "../components/AppTextInput";
class EditScreen extends Component {
render() {
const { item, onEdit, onClose } = this.props;
return (
<KeyboardAvoidingView
behavior="position"
keyboardVerticalOffset={Platform.OS === "ios" ? 0 : 100}
>
<Image style={styles.image} source={item.image} />
<View style={styles.detailContainer}>
<AppTextInput value={item.title} />
<AppTextInput value={item.des} />
</View>
<AppButton
text="Save"
onPress={() => {
onEdit(this.state);
}}
/>
</KeyboardAvoidingView>
);
}
}
export default EditScreen;
AppTextInput.js
function AppTextInput({ icon, width = "100%", ...otherProps }) {
return (
<View style={[styles.container, { width }]}>
<TextInput
placeholderTextColor={defaultStyles.colors.medium}
style={defaultStyles.text}
{...otherProps}
/>
</View>
);
}
Try this:
Edit.js
import React, { Component } from 'react';
import { View, StyleSheet, Image, KeyboardAvoidingView } from 'react-native';
import colors from '../config/colors';
import AppButton from '../components/AppButton';
import AppTextInput from '../components/AppTextInput';
class EditScreen extends Component {
constructor(props) {
super(props);
this.state = { ...props.item };
}
render() {
const { onEdit, onClose } = this.props;
const { title, des, image } = this.state;
return (
<KeyboardAvoidingView
behavior="position"
keyboardVerticalOffset={Platform.OS === 'ios' ? 0 : 100}>
<Image style={styles.image} source={image} />
<View style={styles.detailContainer}>
<AppTextInput
value={title}
onChangeText={text => this.setState({ title: text })}
/>
<AppTextInput
value={des}
onChangeText={text => this.setState({ des: text })}
/>
</View>
<AppButton text="Save" onPress={() => onEdit(this.state)} />
</KeyboardAvoidingView>
);
}
}
export default EditScreen;
onEdit
onEdit = data => {
const newPosts = this.state.post.map(item => {
if(item.key === data.key) return data;
else return item;
})
this.setState({ post: newPosts, editMode: false });
};
Only the direct children of a navigator can access
this.props.navigation
If you want to access that inside the edit screen you can pass it from the Home screen as a prop. Like so:
return <EditScreen item={item} onEdit={this.onEdit} navigation={this.props.navigation} />;
But i don't think you need to go back because you are still on the Home page and just rendering the EditScreen within it. So just changing the state to have editMode: false should be enough
Related
Currently, this - is how the SearchBar and FlatList is showing up on the screen. Upon clicking on the SearchBar and typing one of the list components, it shows up this- way. I want the FlatList to only appear when I click on the SearchBar. How do I implement this in the app? Something like a dropdown search bar...
import React from 'react';
import { View, Text, FlatList, ActivityIndicator, StyleSheet } from 'react-native';
import { SearchBar } from 'react-native-elements';
import { Button, Menu, Divider, Provider, TextInput } from 'react-native-paper';
const restaurantList = [
{
type: 'Italian',
name: 'DiMaggio'
},
{
type: 'Greek',
name: 'Athena'
}
];
export default class App extends React.Component {
static navigationOptions = {
title: 'Search for Restaurants'
};
constructor (props) {
super(props);
this.state = {
loading: false,
data: restaurantList,
error: null,
value: '',
};
this.arrayholder = [];
}
renderSeparator = () => {
return (
<View
style={{
height: 1,
width: '86%',
backgroundColor: '#CED0CE',
marginLeft: '14%'
}}
/>
);
};
searchFilterFunction = text => {
this.setState({
value: text
});
const newData = restaurantList.filter(item => {
console.log(item.type)
const itemData = `${item.name.toUpperCase()} ${item.type.toUpperCase()}`;
const textData = text.toUpperCase();
return itemData.includes(textData);
});
this.setState({
data: newData
});
};
renderHeader = () => {
return (
<SearchBar
placeholder="Type..."
value={this.state.value}
onChangeText={text => this.searchFilterFunction(text)}
/>
);
};
render () {
if (this.state.loading) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<ActivityIndicator />
</View>
);
} else {
return (
<Provider>
<View
style={{
paddingTop: 50,
flexDirection: 'row',
justifyContent: 'center',
}}>
<View style={styles.container}>
<FlatList
keyExtractor={(item, index) => `${index}`}
extraData={this.state}
data={this.state.data}
renderItem={({ item }) => (
<Text>{item.name} {item.type}</Text>
)}
ItemSeparatorComponent={this.renderSeparator}
ListHeaderComponent={this.renderHeader}
/>
</View>
</View>
<View style={styles.container}>
<TextInput />
</View>
</Provider>
);
}
}
}
Try this way
this.state = {
searchClicked: false
};
<SearchBar
placeholder="Type..."
value={this.state.value}
onChangeText={text => this.searchFilterFunction(text)}
onFocus={() => this.setState({searchClicked: true})}
onBlur={() => this.setState({searchClicked: false})}
/>
<View>{this.renderHeader()}</View>
{this.state.searchClicked && <FlatList
keyExtractor={(item, index) => `${index}`}
extraData={this.state}
data={this.state.data}
renderItem={({ item }) => (
<Text>{item.name} {item.type}</Text>
)}
ItemSeparatorComponent={this.renderSeparator}
// ListHeaderComponent={this.renderHeader} <—- Remove from here —->
/>}
In case #Lakhani reply doesn't satisfy your question, I have another suggestion for you.
Your SearchBar should contain a TextInput. You can use onFocus and onBlur props to capture event you click on SearchBar or leave it.
...
<SearchBar
placeholder="Type..."
value={this.state.value}
onChangeText={text => this.searchFilterFunction(text)}
onFocus={()=>this.setState({showList: true})} // <---
onBlur={()=>this.setState({showList: false})} // <---
/>
...
render() {
return (
...
{
this.state.showList && <FlatList ... />
}
)
}
Here, I am fetching data from firebase and then trying to output it in a tinder card like format. My code is as follows -
import React from 'react';
import { View, ImageBackground, Text, Image, TouchableOpacity } from 'react-native';
import CardStack, { Card } from 'react-native-card-stack-swiper';
import City from '../components/City';
import Filters from '../components/Filters';
import CardItem from '../components/CardItem';
import styles from '../assets/styles';
import Demo from '../assets/demo';;
import {db} from '../config/config';
class Home extends React.Component {
constructor (props) {
super(props);
this.state = ({
items: [],
isReady: false,
});
}
componentWillMount() {
let items = [];
db.ref('cards').once('value', (snap) => {
snap.forEach((child) => {
let item = child.val();
item.id = child.key;
items.push({
name: child.val().pet_name,
description: child.val().pet_gender,
pet_age: child.val().pet_age,
pet_breed: child.val().pet_breed,
photoUrl: child.val().photoUrl,
});
});
//console.log(items)
this.setState({ items: items, isReady: true });
console.log(items);
});
}
componentWillUnmount() {
// fix Warning: Can't perform a React state update on an unmounted component
this.setState = (state,callback)=>{
return;
};
}
render() {
return (
<ImageBackground
source={require('../assets/images/bg.png')}
style={styles.bg}
>
<View style={styles.containerHome}>
<View style={styles.top}>
<City />
<Filters />
</View>
<CardStack
loop={true}
verticalSwipe={false}
renderNoMoreCards={() => null}
ref={swiper => {
this.swiper = swiper
}}
>
{this.state.items.map((item, index) => (
<Card key={index}>
<CardItem
//image={item.image}
name={item.name}
description={item.description}
actions
onPressLeft={() => this.swiper.swipeLeft()}
onPressRight={() => this.swiper.swipeRight()}
/>
</Card>
))}
</CardStack>
</View>
</ImageBackground>
);
}
}
export default Home;
I am fetching data and storing it in an array called items[]. Console.log(items) gives me the following result:
Array [
Object {
"description": "male",
"name": "dawn",
"pet_age": "11",
"pet_breed": "golden retriever",
"photoUrl": "picture",
},
Object {
"description": "Male",
"name": "Rambo",
"pet_age": "7",
"pet_breed": "German",
"photoUrl": "https://firebasestorage.googleapis.com/v0/b/woofmatix-50f11.appspot.com/o/pFkdnwKltNVAhC6IQMeSapN0dOp2?alt=media&token=36087dae-f50d-4f1d-9bf6-572fdaac8481",
},
]
Furthermore, I want to output my data in a card like outlook so I made a custom component called CardItem:
import React from 'react';
import styles from '../assets/styles';
import { Text, View, Image, Dimensions, TouchableOpacity } from 'react-native';
import Icon from './Icon';
const CardItem = ({
actions,
description,
image,
matches,
name,
pet_name,
pet_gender,
pet_age,
onPressLeft,
onPressRight,
status,
variant
}) => {
// Custom styling
const fullWidth = Dimensions.get('window').width;
const imageStyle = [
{
borderRadius: 8,
width: variant ? fullWidth / 2 - 30 : fullWidth - 80,
height: variant ? 170 : 350,
margin: variant ? 0 : 20
}
];
const nameStyle = [
{
paddingTop: variant ? 10 : 15,
paddingBottom: variant ? 5 : 7,
color: '#363636',
fontSize: variant ? 15 : 30
}
];
return (
<View style={styles.containerCardItem}>
{/* IMAGE */}
<Image source={image} style={imageStyle} />
{/* MATCHES */}
{matches && (
<View style={styles.matchesCardItem}>
<Text style={styles.matchesTextCardItem}>
<Icon name="heart" /> {matches}% Match!
</Text>
</View>
)}
{/* NAME */}
<Text style={nameStyle}>{name}</Text>
{/* DESCRIPTION */}
{description && (
<Text style={styles.descriptionCardItem}>{description}</Text>
)}
{/* STATUS */}
{status && (
<View style={styles.status}>
<View style={status === 'Online' ? styles.online : styles.offline} />
<Text style={styles.statusText}>{pet_age}</Text>
</View>
)}
{/* ACTIONS */}
{actions && (
<View style={styles.actionsCardItem}>
<View style={styles.buttonContainer}>
<TouchableOpacity style={[styles.button, styles.red]} onPress={() => {
this.swiper.swipeLeft();
}}>
<Image source={require('../assets/red.png')} resizeMode={'contain'} style={{ height: 62, width: 62 }} />
</TouchableOpacity>
<TouchableOpacity style={[styles.button, styles.orange]} onPress={() => {
this.swiper.goBackFromLeft();
}}>
<Image source={require('../assets/back.png')} resizeMode={'contain'} style={{ height: 32, width: 32, borderRadius: 5 }} />
</TouchableOpacity>
<TouchableOpacity style={[styles.button, styles.green]} onPress={() => {
this.swiper.swipeRight();
}}>
<Image source={require('../assets/green.png')} resizeMode={'contain'} style={{ height: 62, width: 62 }} />
</TouchableOpacity>
</View>
</View>
)}
</View>
);
};
export default CardItem;
The problem is when I try to pass the data in my items[] array, the cardItem component just doesnt work. To dry-run, I used a sample demo array and when I use the Demo array, my component works just fine. What am I doing wrong? I have been tinkering with this problem for quite a while now. Any help whatsoever would be appreciated.
When I want to distribute my data from my firebase database to my React Native mobile application in the form of a carousel with SwiperFlatList, an error is displayed
each time my class is updated, showing me as follows: "Invariant violation: scrolltoindex out of range: requested Nan but maximum is 1."
By hiding the error the carousel works well but it can be very annoying and cause problems during its build.
Here are my codes:
My Render function :
renderPost=post=>{
return(
<View style={styles.card}>
<HorizontalCard title={post.title_new} desc={post.text} img={post.image} />
</View>
)
}
HorizontalCard Component :
export default class HorizontalCard extends Component {
constructor(props) {
super(props);
}
static propTypes = {
screen: PropTypes.string,
title: PropTypes.string,
desc: PropTypes.string,
img: PropTypes.string,
};
state = {
modalVisible: false,
};
setModalVisible(visible) {
this.setState({modalVisible: visible});
}
render() {
return (
<View style={{flex: 1}}>
<TouchableOpacity
onPress={() => {
this.setModalVisible(true);
}}
style={styles.container}>
<Modal
animationType="slide"
transparent={false}
visible={this.state.modalVisible}
onRequestClose={() => {
alert('Modal has been closed.');
}}>
<View style={{marginTop: 22}}>
<View>
<Text>{this.props.desc}</Text>
<Button
title="Fermer la fenêtre"
onPress={() => {
this.setModalVisible(!this.state.modalVisible);
}} />
</View>
</View>
</Modal>
<View style={styles.card_discord}>
<Image style={styles.card_discord_img} source={{ uri: this.props.img }} />
<LinearGradient
start={[1.0, 0.5]}
end={[0.0, 0.5]}
colors={['rgba(51, 51, 51, 0.2)', '#333333', '#333333']}
style={styles.FadeAway}>
<View style={styles.FadeAway}>
<Text h4 style={styles.FadeAway_h2}>
{this.props.title}
</Text>
<Text style={styles.FadeAway_p}>{this.props.desc}</Text>
</View>
</LinearGradient>
</View>
</TouchableOpacity>
</View>
);
}
}
My HomeScreen component (page where the error appears) :
export default class HomeScreen extends Component {
constructor(props) {
super(props);
this.ref = Fire.shared.firestore.collection('posts')
this.useref=
this.state={
dataSource : [],
}
}
feedPosts = (postSnapShot) =>{
const post = [];
postSnapShot.forEach((doc) => {
const {uid,text,timestamp,title_new,image} = doc.data();
const data=Fire.shared.firestore
.collection('users')
.doc(uid)
.get()
.then(doc=>{
post.push({
text,
timestamp,
title_new,
image,
uid,
})
this.setState({
dataSource : post,
});
})
});
}
renderPost=post=>{
return(
<View style={styles.card}>
<HorizontalCard title={post.title_new} desc={post.text} img={post.image} />
</View>
)
}
render() {
return (
<ThemeProvider>
<ScrollView>
<SwiperFlatList
autoplay
autoplayDelay={5}
index={0}
autoplayLoop
autoplayInvertDirection
data={this.state.dataSource}
renderItem={({item})=>this.renderPost(item)}
/>
...
<ScrollView>
</ThemeProvider>
)
}
}
When I click on the checkbox to change state, the accordion that it's nested within also collapses.
It's very wierd; I can click the text bellow, and the accordion does not collapse.
This is the code for the component; look within CollapseBody:
import React, { Component } from 'react';
import { View, Text, Modal, TouchableHighlight } from 'react-native';
import {Collapse,CollapseHeader, CollapseBody, AccordionList} from 'accordion-collapse-react-native'
import { loadLeagues } from '../actions'
import { connect } from 'react-redux'
import Checkbox from 'react-native-modest-checkbox'
class LeagueSelect extends Component {
state = {
modalVisible: false,
checked: true
}
setModalVisible(visible) {
this.setState({modalVisible: visible});
}
componentDidMount() {
this.props.loadLeagues()
}
render() {
return (
<View style={{marginTop: 22}}>
{console.log('in league', this.props)}
<Modal
animationType="slide"
transparent={false}
visible={this.state.modalVisible}
onRequestClose={() => {
Alert.alert('Modal has been closed.');
}}>
<View style={{marginTop: 100}}>
<TouchableHighlight
onPress={() => {
this.setModalVisible(!this.state.modalVisible);
}}
>
<Text>Hide Modal</Text>
</TouchableHighlight>
<Collapse >
<CollapseHeader>
<Text>Leagues</Text>
</CollapseHeader>
<CollapseBody>
{this.props.league === null ?'' : this.props.league.map(
(v, i) => {
return(
<View>
<Checkbox
label={v.acronym}
onChange={() => { this.setState({ checked: false})}}
checked={this.state.checked}
/>
<Text>{v.acronym}</Text>
</View>
)
}
)}
</CollapseBody>
</Collapse>
</View>
</Modal>
<TouchableHighlight
onPress={() => {
this.setModalVisible(true);
}}>
<Text>Show Modal</Text>
</TouchableHighlight>
</View>
);
}
}
function mapStateToProps(state) {
return {
league: state.league.league
}
}
export default connect(mapStateToProps, { loadLeagues })(LeagueSelect);
This is a video of the behavior; it's difficult to describe without actually being able to see it: https://streamable.com/sbqab
Are you sure there isn't anything else going on that is interfering with it? I built a small sample project using the code you provided and it appears to be working fine.
One other thing (non-related) - you're using the same checked state for both boxes, so clicking one will change the status of the other. I don't think this is what you want, so I went ahead and set up your state to keep an entry for each checkbox.
Here's a copy of the complete code running in that gif:
import React, { Component } from 'react';
import { View, Text, Modal, TouchableHighlight } from 'react-native';
import { Collapse, CollapseHeader, CollapseBody, AccordionList } from 'accordion-collapse-react-native'
import Checkbox from 'react-native-modest-checkbox'
export default class App extends Component {
state = {
modalVisible: false,
checked: {},
}
// hardcoded props
league = [
{ acronym: 'NBA' },
{ acronym: 'NFL' },
];
setModalVisible(visible) {
this.setState({modalVisible: visible});
}
componentDidMount() {
const checked = this.league.reduce((acc, cur) => ({
...acc,
[cur.acronym]: false,
}), {});
this.setState({ checked });
}
render() {
return (
<View style={{marginTop: 22}}>
<Modal
animationType="slide"
transparent={false}
visible={this.state.modalVisible}
onRequestClose={() => {
Alert.alert('Modal has been closed.');
}}
>
<View style={{marginTop: 100}}>
<TouchableHighlight
onPress={() => {
this.setModalVisible(!this.state.modalVisible);
}}
>
<Text>Hide Modal</Text>
</TouchableHighlight>
<Collapse>
<CollapseHeader>
<Text>Leagues</Text>
</CollapseHeader>
<CollapseBody>
{this.league === null ? '' : this.league.map(
(v, i) => (
<View key={v.acronym}>
<Checkbox
label={v.acronym}
onChange={() => this.setState({
checked: {
...this.state.checked,
[v.acronym]: !this.state.checked[v.acronym]
}
})}
checked={this.state.checked[v.acronym]}
/>
<Text>{v.acronym}</Text>
</View>
)
)}
</CollapseBody>
</Collapse>
</View>
</Modal>
<TouchableHighlight
onPress={() => {
this.setModalVisible(true);
}}>
<Text>Show Modal</Text>
</TouchableHighlight>
</View>
);
}
}
The key pieces to note are the checkbox:
<Checkbox
label={v.acronym}
onChange={() => this.setState({
checked: {
...this.state.checked,
[v.acronym]: !this.state.checked[v.acronym]
}
})}
checked={this.state.checked[v.acronym]}
/>
and the state initialization from the "props" (I've hardcoded these for my example):
// hardcoded props
league = [
{ acronym: 'NBA' },
{ acronym: 'NFL' },
];
...
componentDidMount() {
const checked = this.league.reduce((acc, cur) => ({
...acc,
[cur.acronym]: false,
}), {});
this.setState({ checked });
}
I get some JSON array from API calling and I want to show them in a list using CardView. But while I am using the CardView tag, it keeps rendering but not showing the data in card. There is nothing wrong with fetching the data as I logged them in console and printed the values.
If, I remove the cardView tag then it works well.
I installed the CardView component using following command-
npm install react-native-cardview --save
I took help from the site-
https://www.npmjs.com/package/react-native-cardview
But it is not working as it is mentioned. So, here, I have provided the code-
import React from 'react';
import { StyleSheet, Text, View, Image, AsyncStorage, ActivityIndicator, TouchableOpacity, ToastAndroid, FlatList } from 'react-native';
import {Icon, Button, Container, Header, Content, Left} from 'native-base';
import CustomHeader from './CustomHeader';
import CardView from 'react-native-cardview';
let jwt=''
class NoteMeHome extends React.Component {
state = {
getValue: '',
dataSource:[],
isLoading: true
}
componentDidMount() {
AsyncStorage.getItem("token").then(value => {
const url = 'my url';
return fetch(url, {
method: 'GET',
headers: new Headers({
'Content-Type' : 'application/json',
'token': 'abc',
'jwt': value
})
})
.then((response)=> response.json() )
.then((responseJson) => {
console.log('####:'+responseJson[0].title)
this.setState({
dataSource: responseJson,
isLoading: false,
getValue: value
})
})
.catch((Error) => {
console.log(Error)
})
}
)}
static navigationOptions = ({navigation}) => ({
title: "Home",
headerLeft: <Icon name="ios-menu" style={{paddingLeft:10}}
onPress={()=>navigation.navigate('DrawerOpen')}/>,
drawerIcon:
<Image source={{uri: 'https://png.icons8.com/message/ultraviolet/50/3498db'}}
style={styles.icon}
/>
})
render() {
const { getValue } = this.state;
return(
this.state.isLoading
?
<View style={{flex:1, justifyContent:'center', alignItems:'center'}}>
<ActivityIndicator size="large" color="#330066" animating/>
</View>
:
<Container>
<CustomHeader
title="Home"
drawerOpen={()=>this.props.navigation.navigate('DrawerOpen')}
/>
<View>
<FlatList
data={this.state.dataSource}
renderItem={this.renderItem}
keyExtractor = {(item, index) => index+""}
ItemSeparatorComponent={this.renderSeparator}
/>
</View>
</Container>
)
}
renderSeparator = ()=> {
return (
<View style={{height:1, width:'100%', backgroundColor:'black'}}>
</View>
)
}
renderItem = ({item}) => {
return(
<TouchableOpacity style={{flex:1, flexDirection:'row'}}
onPress= {() => ToastAndroid.show(item.title, ToastAndroid.SHORT)}
>
<CardView
cardElevation={3}
cardMaxElevation={2}
cornerRadius={5}
paddingBottom={10}
style={{justifyContent:'center',margin:2,backgroundColor:'white'}}
// height='auto' or you can also specify the height in number as per requirement
>
<View style={{padding:10}}>
<Image style={{width:80, height:80, margin:5}}
source={{uri: 'https://png.icons8.com/message/ultraviolet/50/3498db'}}
/>
<View style={{flex:1, justifyContent:'center', marginLeft:5}}>
<Text style={{fontSize:18, color:'green', marginBottom:10}}>
{item.category}
</Text>
<Text style={{fontSize:18, color:'red', marginBottom:10}}>
{item.title}
</Text>
</View>
</View>
</CardView>
</TouchableOpacity>
)
}
}
const styles = StyleSheet.create({
icon:{
height: 24,
width: 24
},
container:{
flex:1,
backgroundColor:'#fff'
}
})
export default NoteMeHome;
So, it would be very nice if someone helps me to know how I can show the item lists in a cardView.