React Native, accessing a single element from an array nested in state - javascript

how can I access a single element from an array nested in a state like this
state = {
modal: 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"),
},
]
};
.....
<MyList.Provider
value={{
}}
>
<FlatList
data={this.state.post}
renderItem={({ item }) => (
<>
<TouchableOpacity
activeOpacity={0.7}
onPress={() => this.deleteItem(item)}
style={styles.Delete}
>
<MaterialCommunityIcons name="delete" color="red" size={30} />
</TouchableOpacity>
<TouchableOpacity
activeOpacity={0.7}
onPress={() => this.props.navigation.navigate("Edit", item)}
style={styles.Edit}
>
<MaterialCommunityIcons
name="playlist-edit"
color="green"
size={35}
/>
</TouchableOpacity>
<Card
title={item.title}
subTitle={item.des}
image={item.image}
onPress={() =>
this.props.navigation.navigate("Details", item)
}
/>
</>
)}
/>
</MyList.Provider>
how can I do this like this.state.post({title}) or some way else??
I need to use this values with context so I can share and change some particular data with between 2 screens. I know to pass data I need to use context or navigation.navigate("route name",item). But if I use navigation I won't able to edit it but how can I pass data in context value from array set, if I do this.state.post it will return whole list and if i do this.state.post[0].title it will return only title of that post. So how can i do this? Please help

You have to indicate the index of the object you’re trying to access in the array. For instance to access the first object in the array you can do this
this.state.post[0]

below is my solution which follows the logic i think you are trying to achieve. I have used a flatlist
Let me know if it helps
import React, { Component } from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
FlatList,
} from 'react-native';
export default class MyComponent extends Component {
constructor(props) {
super(props);
this.state = {
modal: 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"),
},
]
};
}
handleEdit(item) {
const { post } = this.state;
const extractIndex = post.findIndex(e => e.key === item.key);
const newPost = post[extractIndex];
this.props.navigation.navigate('Edit', { newPost })
this.setState({ post });
}
handleDelete(item) {
const { post } = this.state;
const newPost = post.filter(e => e.key !== item.key);
this.setState({ post: newPost });
}
renderItem = ({ item }) => {
return (
<View>
<Text>
{item.title}
</Text>
<TouchableOpacity key={item.key} onPress={this.handleEdit.bind(this, item)}>
<Text>Edit</Text>
</TouchableOpacity>
<TouchableOpacity key={item.key} onPress={this.handleDelete.bind(this, item)}>
<Text>Delete</Text>
</TouchableOpacity>
</View>
);
}
render() {
return (
<View style={styles.container}>
<FlatList
data={this.state.post}
renderItem={this.renderItem}
keyExtractor={(item, index) => index.toString()}
extraData={this.state}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
});

Use .map() function
Ex-
var cat_data = categories_list.map(function (item) {
var cat_data = categories_list.map(function (item) {
return {
name: item.Name,
thumb_url: item.PictureModel.ImageUrl,
cat_id: item.Id.toString(),
};
});
this.setState({
data: cat_data,
});

Related

Can't pass the state props, says undefined

I have bee trying to pass the notes data to another component But I don't know why it says undefined.
export default App = () => {
const [notes, setNotes] = useState([
{ key: 1, value: "Hello there what up", title: "Some Title for this" },
{ key: 2, value: "I want to take notes", title: "another for this one" },
]);
return (
<View>
<FlatList
data={notes}
renderItem={({ note }) => (
<View>
<NoteItem note={note} />
</View>
)}
/>
</View>
);
};
export default NoteItem = ({ note }) => {
<Text>{note.title}</Text>
);
};
First of you assume that renderItem in Flatlist has a 'note' property inside it. It does not, it is called item. Also you pass notes but you try to deconstruct note? It should be like this:
export default App = () => {
const [notes, setNotes] = useState([
{ key: 1, value: "Hello there what up", title: "Some Title for this" },
{ key: 2, value: "I want to take notes", title: "another for this one" },
]);
return (
<View>
<FlatList
data={notes}
renderItem={({ item }) => (
<View>
<NoteItem note={item} />
</View>
)}
/>
</View>
);
};
This syntax - ({ note }) - means that the NoteItem component expects a prop named note to be set; however, you're setting the notes prop instead.
Try this:
<FlatList
data={notes}
renderItem={({ item, index }) => (
<View key={index}>
<NoteItem note={item} />
</View>
)}
/>

How to get the get data of Flatlist Item in reactNative

I am trying to get the data of a flat list when onPressed is called the onpressed is called as I am using an alert but the selected data is not getting called
import React from "react";
import {StyleSheet,Text,View,FlatList,TouchableWithoutFeedback,} from "react-native";
const App = () => {
return (
<View style={styles.container}>
<FlatList
data={[
{ key: "Devin" },
{ key: "Dan" },
{ key: "Jillian" },
{ key: "Jimmy" },
{ key: "Julie" },
]}
renderItem={({ item }) => (
<TouchableWithoutFeedback onPress={() => actionOnRow(item)}>
<View>
<Text style={styles.item}>Name: {item.key}</Text>
</View>
</TouchableWithoutFeedback>
)}
/>
</View>
);
};
const actionOnRow = (item) => {
const value = "Selected Item : "+ item;
alert(value);
};
export default App;
I have check the react documentation but i can't find anything on flatlist item OnPress, when i run this the alert displays the message "Selected : " but i am expecting "Selected : 'the item selected' ".
you are using alert . Alert does not accept two arguments.
Try using console.log or alert("Selected :" + item.key);
Answer in Full incase anyone else needs it
import React from "react";
import {StyleSheet,Text,View,FlatList,TouchableWithoutFeedback,} from "react-native";
const App = () => {
return (
<View style={styles.container}>
<FlatList
data={[
{ key: "Devin" },
{ key: "Dan" },
{ key: "Jillian" },
{ key: "Jimmy" },
{ key: "Julie" },
]}
renderItem={({ item }) => (
<TouchableWithoutFeedback onPress={() => selectStudent(item)}>
<View>
<Text style={styles.item}>Name: {item.key}</Text>
</View>
</TouchableWithoutFeedback>
)}
/>
</View>
);
};
const selectStudent = (item) => {
const value = "Selected Student : "+ item.key;
alert(value);
};
export default App;

React Native, values are not updating

I made a edit screen and trying to update the value of post through navigation v4 by using getParams and set setParams but when I change the old value and click save buttton to save it, it's not updating it and no error is showing either. It's still showing old values. Can someone please help me, below is my code
EditScreen.js
class EditScreen extends Component {
render() {
const { params } = this.props.navigation.state;
return (
<KeyboardAvoidingView
behavior="position"
keyboardVerticalOffset={Platform.OS === "ios" ? 0 : 100}
>
<Image
style={styles.image}
source={this.props.navigation.getParam("image")}
/>
<View style={styles.detailContainer}>
<AppTextInput
value={this.props.navigation.getParam("title")}
onChangeText={(text) =>
this.props.navigation.setParams({ title: text })
}
/>
<AppTextInput
value={this.props.navigation.getParam("des")}
onChangeText={(text) =>
this.props.navigation.setParams({ des: text })
}
/>
</View>
<AppButton
text="Save"
style={styles.button}
onPress={() => {
this.props.navigation.getParam("onEdit");
this.props.navigation.goBack();
}}
/>
</KeyboardAvoidingView>
Home.js
class Home extends Component {
state = {
modal: 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"),
},
],
};
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 });
};
render() {
return (
<Screen style={styles.screen}>
<FlatList
data={this.state.post}
renderItem={({ item }) => (
<>
<TouchableOpacity
activeOpacity={0.7}
onPress={() =>
this.props.navigation.navigate("Edit", {
image: item.image,
title: item.title,
des: item.des,
onEdit: this.onEdit,
})
}
style={styles.Edit}
>
<MaterialCommunityIcons
name="playlist-edit"
color="green"
size={35}
/>
</TouchableOpacity>
<Card onPress={() => this.props.navigation.push("Details", item)}>
<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>
</>
I recommend you to keep the data in the component state:
constructor(props) {
super(props);
// get the data that you need from navigation params
const { key, title, ..} = this.props.navigation.state.params
this.state = {key, title, ..}
}
then :
<AppTextInput
value={this.state.title}
onChangeText={(text) =>
this.setState({ title: text })
}
/>
<AppButton
text="Save"
style={styles.button}
onPress={() => {
this.props.navigation.getParam("onEdit")(this.state);
this.props.navigation.goBack();
}}
/>
Maybe try this:
<AppButton
text="Save"
style={styles.button}
onPress={() => {
this.props.navigation.getParam("onEdit")(this.props.navigation.state.params);
this.props.navigation.goBack();
}}
/>
and:
this.props.navigation.navigate("Edit", {
key: item.key,
image: item.image,
title: item.title,
des: item.des,
onEdit: this.onEdit,
})

Adding new object to an array in React Native

I have created a form to upload the image and text field on the home screen but I am facing a problem that it's not updating the array and validation is failing due to that. I think something wrong with my implementation
AddPost.js
const validationSchema = Yup.object({
title: Yup.string().required().min(5).max(15).label("Title"),
des: Yup.string().required().min(15).max(200).label("Description"),
image: Yup.array().required().label("Image"),
});
class AddPost extends Component {
render() {
return (
<Formik
initialValues={{ title: "", des: "", image: [] }}
onSubmit={(values, actions) => {
actions.resetForm();
this.props.addPost(values);
}}
validationSchema={validationSchema}
>
{(value) => (
<View>
<FormImage />
<Text style={styles.error}>
{value.touched.image && value.errors.image}
</Text>
<TextInput
placeholder="Title"
onChangeText={value.handleChange("title")}
style={styles.input}
value={value.values.title}
onBlur={value.handleBlur("title")}
/>
<Text style={styles.error}>
{value.touched.title && value.errors.title}
</Text>
Here is my form field I think everything is right here
home.js
class Home extends Component {
state = {
modal: 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"),
},
],
image: null,
};
addPost = (posts) => {
posts.key = Math.random().toString();
this.setState.post((currentPost) => {
return [posts, ...currentPost];
});
this.state.modal();
};
render() {
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 }) => (
<>
<Card
title={item.title}
subTitle={item.des}
image={item.image}
onPress={() => this.props.navigation.navigate("Edit", item)}
/>
</>
I think something wrong with the addPost method because I did it before with function base that time I only added text to the list and its worked but in class base I don't know to do it I just try the same way I did in function base
FormImage.js
class FormImage extends Component {
state = {
image: null,
hasCameraPermission: null,
};
async componentDidMount() {
const { status } = await Permissions.askAsync(Permissions.CAMERA_ROLL);
this.setState({ hasCameraPermission: status === "granted" });
}
_pickImage = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
aspect: [4, 3],
});
if (!result.cancelled) {
this.setState({ image: result.uri });
}
};
render() {
const { image } = this.state;
return (
<TouchableWithoutFeedback onPress={this._pickImage}>
<View style={styles.container}>
{!image && (
<MaterialCommunityIcons
color={colors.medium}
name="camera"
size={40}
/>
)}
{image && <Image style={styles.image} source={{ uri: image }} />}
</View>
</TouchableWithoutFeedback>
);
}
}
after submiting
Iam assuming your addPost function logic is wrong,
Try the below code
addPost = (posts) => {
posts.key = Math.random().toString();
this.setState((prevState) => {
return {...prevState, post: [...prevState.post, ...posts] };
});
this.state.modal();
};
Let me know incase you are getting the same error.
You are not updating images to formik so is normal you get the required error.
First in your AddPost Component pass down formikProps to FormImage component.
return (
<Formik
initialValues={{ title: "", des: "", image: [] }}
onSubmit={(values, actions) => {
// actions.resetForm(); --> comment this
this.props.addPost(values);
}}
validationSchema={validationSchema}
>
{(value) => (
<View>
<FormImage formikProps={value}/>
<Text style={styles.error}>
{value.touched.image && value.errors.image}
</Text>
<TextInput
placeholder="Title"
onChangeText={value.handleChange("title")}
style={styles.input}
value={value.values.title}
onBlur={value.handleBlur("title")}
/>
<Text style={styles.error}>
{value.touched.title && value.errors.title}
</Text>
In FormImage use that formikProps and call setFieldValue("image", result.uri) to update formik value for image.
class FormImage extends Component {
state = {
image: null,
hasCameraPermission: null,
};
async componentDidMount() {
const { status } = await Permissions.askAsync(Permissions.CAMERA_ROLL);
this.setState({ hasCameraPermission: status === "granted" });
}
_pickImage = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
aspect: [4, 3],
});
if (!result.cancelled) {
this.setState({ image: result.uri });
this.props.formikProps.setFieldValue("image", result.uri);
}
};
render() {
const { image } = this.state;
return (
<TouchableWithoutFeedback onPress={this._pickImage}>
<View style={styles.container}>
{!image && (
<MaterialCommunityIcons
color={colors.medium}
name="camera"
size={40}
/>
)}
{image && <Image style={styles.image} source={{ uri: image }} />}
</View>
</TouchableWithoutFeedback>
);
}
}
In home
addPost = (posts) => {
console.log('add post');
posts.key = Math.random().toString();
this.setState((prevState) => {
return {...prevState, post: [...prevState.post, ...posts], modal:
true };
});
// this.state.modal();
};

i want to re create Flatlist every time in react native

Please check shared video form understanding my issue
https://drive.google.com/file/d/1GKU07Mv7IjiLnrfps5gWpfMPsMphvRDv/view
I need to Flatlist screen every time empty because this below code every time Flatlist API called and then after change Flatlist data.
App Flow
first screen: shows category
second screen: shows selected category quotes
import { StyleSheet,Button,View, Text,FlatList,Dimensions,TouchableHighlight,Clipboard,ToastAndroid,Share,YellowBox } from 'react-native';
import { createAppContainer,NavigationEvents } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import { createDrawerNavigator } from 'react-navigation-drawer';
import { createSwitchNavigator } from 'react-navigation-switch-transitioner'
import Icon from 'react-native-vector-icons/Ionicons';
import Style from '../constants/Style';
import Spinner from 'react-native-loading-spinner-overlay';
export default class QuoteActivity extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
title: navigation.getParam('Title', 'Default Title'),
headerStyle: {
backgroundColor: navigation.getParam('BackgroundColor', '#5F4B8BFF'),
},
headerTintColor: navigation.getParam('HeaderTintColor', '#fff'),
headerLeft: (
<Icon
style={{ paddingLeft: 15,paddingTop: 5,color:'#FFFFFF' }}
onPress={() => navigation.goBack(null)}
name="ios-arrow-back"
size={40}
/>
)
};
};
constructor(props) {
super(props);
YellowBox.ignoreWarnings([
'Warning: componentWillMount is deprecated',
'Warning: componentWillReceiveProps is deprecated',
]);
}
state = {
spinner: false,isLoading: false,
dataSource:[]
}
// ON FOCUS CALL API
componentDidMount() {
this._doApiCall();
}
// API CALL
_doApiCall = () => {
this.setState({
spinner: true,isLoading:true
});
const { navigation } = this.props;
let CategoryId = navigation.getParam('CategoryId');
fetch('API_URL', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
}
}).then((response) => response.json())
.then((responseJson) => {
this.setState({
// SAMPLE JSON
// {
// "data": [
// {
// "Id": "462",
// "CategoryId": "5",
// "Title": "Being 'Single' is My Attitude!"
// },
// {
// "Id": "464",
// "CategoryId": "5",
// "Title": "I never dreamed about success. I worked for it."
// }
// ],
// "success": "1",
// "message": "2 Quotes found.",
// "service_time": "0.030284881591797 seconds"
// }
// SAMPLE JSON END
spinner:false,isLoading:false,
dataSource:responseJson.data
})
})
.catch((error) => {
console.error(error);
});
};
// Copy to clipboard
writeToClipboard = async (text) => {
await Clipboard.setString(text);
ToastAndroid.show('Quote copied!', ToastAndroid.SHORT);
};
// Share quotes
shareQuotes = async (text) => {
const result = await Share.share({
message:text.toString()+'\n\n Download app from play store',
});
};
_keyExtractor = (item) => item.id;
// RENDER DATA ITEMS
_renderItem = ({item}) => {
return (
<View style={Style.CategoryTitleList}>
<Text style={Style.CategoryTitle}>{item.Title}</Text>
<View style={[{ flexDirection:'row',justifyContent: 'center',alignItems:'center',textAlign:'center',alignSelf:"center"}]}>
<Icon name="ios-copy" onPress={() => this.writeToClipboard(item.Title)} title="Copy" size={25} color="#5F4B8BFF" style={[{margin:5,alignItems:'flex-end',paddingTop:3,paddingRight:20,paddingLeft:20 }]} />
<Icon name="ios-share" onPress={() => this.shareQuotes(item.Title)} size={25} color="#5F4B8BFF" style={[{margin:5,alignItems:'flex-end',paddingTop:3,paddingRight:20,paddingLeft:20 }]} />
</View>
</View>
)
}
render() {
// RENDER DATA ITEMS INSIDE RENDER FNS
renderItem = ({ item, index }) => {
return (
<View style={Style.CategoryTitleList}>
<Text style={Style.CategoryTitle}>{item.Title}</Text>
<View style={[{ flexDirection:'row',justifyContent: 'center',alignItems:'center',textAlign:'center',alignSelf:"center"}]}>
<Icon name="ios-copy" onPress={() => this.writeToClipboard(item.Title)} title="Copy" size={25} color="#5F4B8BFF" style={[{margin:5,alignItems:'flex-end',paddingTop:3,paddingRight:20,paddingLeft:20 }]} />
<Icon name="ios-share" onPress={() => this.shareQuotes(item.Title)} size={25} color="#5F4B8BFF" style={[{margin:5,alignItems:'flex-end',paddingTop:3,paddingRight:20,paddingLeft:20 }]} />
</View>
</View>
);
};
return (
<View style={Style.QuotesListView}>
<NavigationEvents
onDidFocus={this._doApiCall}
onWillFocus={() => this.setState({spinner: true})}
/>
<FlatList
data={this.state.dataSource}
renderItem={renderItem} // USED INSIDE RENDER FNS
refreshing={this.state.isLoading}
onRefresh={this._doApiCall}
maxToRenderPerBatch={10}
updateCellsBatchingPeriod={1000}
initialNumToRender={1}
removeClippedSubviews={false}
keyExtractor={this._keyExtractor}
/>
</View>
);
}
}```
Before doing the API Call you can clean the DataSource array that you have.
// API CALL
_doApiCall = () => {
this.setState({
spinner: true,isLoading:true,
dataSource: []
});
...
You can handle that in 2 different ways.
whenever you call _doApiCall function, change initial value of dataSource as an empty array.
_doApiCall = () => {
this.setState({
spinner: true,
isLoading: true,
dataSource: []
});
}
Using ternary operator, diaplay spinner when data loading & if not diaplay faltlist
{
this.state.isLoading ?
<Show your Spinner /> :
<FlatList
data={this.state.dataSource}
renderItem={renderItem}
refreshing={this.state.isLoading}
onRefresh={this._doApiCall}
maxToRenderPerBatch={10}
updateCellsBatchingPeriod={1000}
initialNumToRender={1}
removeClippedSubviews={false}
keyExtractor={this._keyExtractor}
/>
}
Feel free for doubt. hope this helps you.

Categories

Resources