I am developing an app with react-native , using RESTfull api with laravel backend , I have an object that has arrays in it . I am using it to create user's profile page . but I don't know how to render those arrays.
here is my api response:
{
meta: {
code: 200,
message: 'Success',
errors: []
},
data: {
users: [
{
personal_information: {
full_name: 'hesam sameni',
avatar: 'https://aaa/file/image/hesamsameni.jpeg',
rate: '0.0',
phone: [],
location: {
name: 'something',
lat: 00,
long: 00,
address: 'something',
distance: 00
},
about: {
quote: 'something',
bio: 'something'
},
topics: {
a: 'a',
b: 'b',
c: 'c',
d: 'd'
},
stats: {
a: 10,
b: 0,
c: 0,
d: 0,
e: 0
},
experiences: [
{
title: 'something',
organization: 'something',
start: 'something',
end: 'something'
}
],
educations: [
{
title: 'something1',
university: 'something1',
major: 'something1',
start: 'something1',
end: 'something1'
},
{
title: 'something2',
university: 'something2',
major: 'something2',
start: 'something2',
end: 'something2'
}
]
}
}
]
}
};
For example how can I show educations in user's profile?
here is the render method ( I already got data from api and stored in state {this.state.dataSource}
render method:
render() {
return (
<View>
<FlatList
data={this.state.dataSource}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }) => (
<View>
<Text>Name: {item.personal_information.full_name}</Text>
<Text>Rate: {item.personal_information.Rate}</Text>
<Text>Educations:</Text>
// Here I need to display all of user's educations
</View>
)}
/>
</View>
);
}
I am not sure if I had to use flatlist since it is only data for 1 specific user , but I didn't know how to render data in other way than flatlist .
try this it will help you achive what you want.
if not tell me..
<FlatList
data={this.state.itemArray}
keyExtractor={(item, index) => index.toString()}
renderItem={({item}) =>{
console.warn(item.data.users[0].personal_information.educations)
return(<FlatList
data={item.data.users[0].personal_information.educations}
keyExtractor={(item, index) => "D"+index.toString()}
renderItem={({item}) =>{
console.warn(item)
}
}/>)
}
}/>
if u want to get something from personal_information
try this example : console.warn(item.data.users[0].personal_information.full_name)
So .map itself only offers one value you care about... That said, there are a few ways of tackling this:
// instantiation
this.state.dataSource
//Using `.map` directlly
this.state.dataSource.map((obj, index)=> {
console.log(obj);
return(
<View />
)
});
// what's built into Map for you
this.state.dataSource.forEach( (val, key) => console.log(key, val) );
// what Array can do for you
Array.from( this.state.dataSource ).map(([key, value]) => ({ key, value }));
// less awesome iteration
let entries = this.state.dataSource.entries( );
for (let entry of entries) {
console.log(entry);
}
Note, I'm using a lot of new stuff in that second example... ...Array.from takes any iterable (any time you'd use [].slice.call( ), plus Sets and Maps) and turns it into an array... ...Maps, when coerced into an array, turn into an array of arrays, where el[0] === key && el[1] === value; (basically, in the same format that I prefilled my example Map with, above).
I'm using destructuring of the array in the argument position of the lambda, to assign those array spots to values, before returning an object for each el.
If you're using Babel, in production, you're going to need to use Babel's browser polyfill (which includes "core-js" and Facebook's "regenerator").
I'm quite certain it contains Array.from.
render(){
console.log(this.state.data.users[0].personal_information.educations,'cdscdscdcds')
return(
<div>
{this.state.data.users.map((value)=>{
console.log(value,'cd')
})}
</div>
Related
I am trying to display same screen with different parameter in react-native. i checked with https://snack.expo.io/#react-navigation/navigate-with-params-v3. its working fine. But i have to display the different data in same screen. My expectation is in tree view structure data have to display like in our normal system tile view folder structure.
Expected Output view:
The view like normal our system folder title structure. C:/user/ReactNative/file .. like tile view.
Ex:
1.FamilyScreen.js
params : Gradpa -> while click Grandpa it will navigate to same page but the data change as 'Father'
FamilyScreen.js
params:Me - While click 'Father' it will navigate to same page but the data as 'Erick and Rose'.
The data will come from service so it may contain some more than children. it will variant. How to pass the particular data in react-native.
const family = [
{
id: 'Grandparent',
name: 'Grandpa',
age: 78,
children: [
{
id: 'Father',
name: 'Father',
age: 30,
children: [
{
id: 'Erick',
name: 'Erick',
age: 10,
},
{
id: 'Rose',
name: 'Rose',
age: 12,
},
],
},
],
},
]
Thanks
Finaly its working, here my code is
constructor(props) {
super(props)
this.state = {
res:family,
}
this.getNestedData = this.getNestedData.bind(this);
}
getNestedData (item) {
var data;
Object.keys(item).map((propKey) => {
if ( propKey === 'children'){
data=item[propKey]
}
})
this.props.navigation.push('GridScreen',{
data:data
});
}
Item = ({ item }) => {
return (
<View style={styles.item}>
<Text style={styles.title} onPress={this.getNestedData.bind(this,item)}>{item.name}</Text>
</View>
);
}
render() {
const { navigation } = this.props;
const data = navigation.getParam('data', this.state.res);
return (
<View>
<FlatList
data={data }
renderItem={({ item }) => <this.Item item={item} />}
keyExtractor={item => item.id}
numColumns={3}
/>
</View>
)
}
}
I have a initial state as below in reducer
const initialState = {
medicationschedule: [
{
date: '2019-08-27',
medications: [
{
title: '8.00 AM',
data: [
{name:'item1', isTaken: 1,mg: '500 mg',capsules:'capsule'},
{name:'item2', isTaken: 4,mg: '2000 mg',capsules:'teaspoon'}
]},
{
title: '12.03 PM',
data: [
{name:'item3', isTaken: 2,mg: '500 mg',capsules:'capsule'},
{name:'item4', isTaken: 1,mg: '500 mg',capsules:'capsule'}
]},
{
title: '3.30 PM',
data: [
{name:'item1', isTaken: 3,mg: '500 mg',capsules:'capsule'}
]},
]
}
],
medication: [
{
title: '8.00 AM',
data: [
{name:'item1', isTaken: 1,mg: '500 mg',capsules:'capsule'},
{name:'item2', isTaken: 4,mg: '2000 mg',capsules:'teaspoon'}
]},
{
title: '12.03 PM',
data: [
{name:'item3', isTaken: 2,mg: '500 mg',capsules:'capsule'},
{name:'item4', isTaken: 1,mg: '500 mg',capsules:'capsule'}
]},
{
title: '3.30 PM',
data: [
{name:'item1', isTaken: 3,mg: '500 mg',capsules:'capsule'}
]},
]
};
I have my class as below for the React Native SectionList.
class HomeScreen extends Component {
state = {
selectedDate: Date(),
isModalVisible: false,
};
render() {
return (
<SafeAreaView style={styles.containter}>
<SectionList
renderItem={({item, index, section}) => <MedicineRow showTitle={0} key={index} setWidth='80%' title={item.name} mg={item.mg} capsules={item.capsules} onPress={() => this.medicineRowTapped(item.name)} medstatus={item.isTaken}/>}
stickySectionHeadersEnabled={false}
renderSectionHeader={({section: {title}}) => (
<SectionTitle showTitle={true} title={title}/>
)}
sections={
this.props.filteredMedications
}
keyExtractor={(item, index) => item + index}
/>
</SafeAreaView>
)
}
}
function mapStateToProps(state) {
return {
filteredMedications : state.medication
}
}
export default connect(mapStateToProps)(HomeScreen)
The list succesfully loads if I access the medication as given in the mapStateToProps. But if I attempt to filter the data inside medictionschedule based on the date then the sectionlist doesn't load anything in the screen.
Filtering in an external function also not helping here as shown below.
medicineForTheDate = () => {
this.props.filteredMedications.filter((schedule) => {
if (schedule.date === '2019-08-27') {
return schedule.medications
}
})
}
then inside the SectionList I would call this.medicineForTheDate()
<SectionList
renderItem={({item, index, section}) => <MedicineRow showTitle={0} key={index} setWidth='80%' title={item.name} mg={item.mg} capsules={item.capsules} onPress={() => this.medicineRowTapped(item.name)} medstatus={item.isTaken}/>}
stickySectionHeadersEnabled={false}
renderSectionHeader={({section: {title}}) => (
<SectionTitle showTitle={true} title={title}/>
)}
sections={
this.medicineForTheDate()
}
keyExtractor={(item, index) => item + index}
/>
I also tried filtering inside the mapsStateToProps but that also didn't help.
function mapStateToProps(state) {
return {
filteredMedications : state.medicationschedule.filter((schedule)=>{ schedule.date === '2019-08-27' })
}
}
and then...
<SectionList
renderItem={({item, index, section}) => <MedicineRow showTitle={0} key={index} setWidth='80%' title={item.name} mg={item.mg} capsules={item.capsules} onPress={() => this.medicineRowTapped(item.name)} medstatus={item.isTaken}/>}
stickySectionHeadersEnabled={false}
renderSectionHeader={({section: {title}}) => (
<SectionTitle showTitle={true} title={title}/>
)}
sections={
this.props.filteredMedications.medications
}
keyExtractor={(item, index) => item + index}
/>
How do I go about filtering data in this context?
For a start, the filter method expects a function, which takes in a parameter (the item inside the array) and returns a true (if the item should be in the filtered array) or a false (if the item should NOT be in the filtered array)
For example:
const arr = [1, 2, 3, 4, 5];
const evenNumbersOnly = arr.filter((item) => {
if (item % 2 === 0) {
// Even (Want it in the list
return true;
} else {
// Odd (Don't want it in the list
return false;
}
});
// evenNumbersOnly will now be [2, 4]
Try changing your filter method and see if the filtered array is what you are expecting. From there, I believe you will be able to continue debugging if it still does not show expected results.
Try this!
medicineForTheDate() {
let filteredValue = this.props.filteredMedications.filter((schedule) => {
if (schedule.date === '2019-08-27') {
return schedule.medications
}
});
return filteredValue;
}
You are close but you have some minor errors in each of your approaches.
In approach 1 with the external method you are not returning a value from the method and filter is not working like you expect. The filter method on an array will return another array only containing the elements of the original array where the filter clause returns a truthy value. So in your example even though you return schedule.medications you are still ending up with an array with the original data. The most similar code to your intention I believe is this:
medicineForTheDate = () => {
const matchingMedications = this.props.filteredMedications.filter((schedule) => {
return schedule.date === '2019-08-27'; // filter if dates are equal
})
if (matchingMedications.length) { // if we have a result
return matchingMedications[0].medications;
}
// decide about a default value if there is no match
}
That said I think a for loop is more clear:
medicineForTheDate = () => {
const {filteredMedications} = this.props;
for (let i=0; i < filteredMedications.length; i++) {
const schedule = filteredMedications[i];
if (schedule.date === '2019-08-27') {
return schedule.medications
}
}
// decide if you want to return a different value if no match is found
}
For the second case you have similar errors - using filter incorrectly and not actually returning a value from filter. Again something like
function mapStateToProps(state) {
return {
filteredMedications : state.medicationschedule.filter((schedule)=>{ return schedule.date === '2019-08-27' })[0]
}
}
will work as long as you account for filteredMedications being undefined in your component in that case if there is no match for the date.
I am rendering data fetched from an api response.
I want to be able to compare the current row being rendered with the last one.
Example: comparing item day with the last item. to be able to insert a separator of the day.
this is just a simple example of what I am trying to do.
//data
const array = [
{day: '3/14', name: 'item1'},
{day: '3/14', name: 'item2'},
{day: '3/14', name: 'item3'},
{day: '3/15', name: 'item4'}
]
if new day, I will insert a separator. the intention is to group data by day.
let lastDay = null;
renderRows(item, index) {
//conditions
let day = item.day;
if(day != lastDay) daySeparator = true;
//store last day
lastDay = day;
return (
<ListItem noIndent style={style.listRow}>
<Row style={[style.tableRow,{alignItems: 'center'}]}>
<Text>{item.name}</Text>
</Row>
</ListItem>
);
}
My problem is that renderRows does not work like for loops, it render each item as separate without being able to keep track of previous rendered items.
is it possible to do it as so, or do I need to manipulate the array before passing it to RenderRows? if so, what's the most optimal way to do it, foreach? for loop?
Now that your question is more clear I can suggest you to use something like <SectionList> (see doc).
In order to use a SectionList you have to pass it a sectioned array. With the data structure you posted I would group items by day:
const array = [
{ day: "3/14", name: "item1" },
{ day: "3/14", name: "item2" },
{ day: "3/14", name: "item3" },
{ day: "3/15", name: "item4" }
];
const grouped = array.reduce(
(result, item) => ({
...result,
[item["day"]]: [...(result[item["day"]] || []), item]
}),
{}
);
const sectionedList = Object.keys(grouped).map(item => ({
title: item,
data: grouped[item]
}));
Which will give you the following structure:
[
{
title: "3/14",
data: [
{ day: "3/14", name: "item1" },
{ day: "3/14", name: "item2" },
{ day: "3/14", name: "item3" }
]
},
{
title: "3/15",
data: [{ day: "3/15", name: "item4" }]
}
];
Now you can use it in a <SectionList>, for example:
<SectionList
renderItem={({item, index, section}) => {...}}
renderSectionHeader={({section: {title}}) => (
<Text style={{fontWeight: 'bold'}}>{title}</Text>
)}
sections={sectionedList}
keyExtractor={(item, index) => item + index}
/>
This way you can properly customize everything.
I really hope this could help you!
One option is to make a new array with map from your initial array. Hope this will get you on the right direction :)
const array = [1, 2, 3, 4]
export default class App extends React.Component {
render() {
const newArr = array.map ((item, idx) => {
const newItem = idx === array.length - 1 ? 'Gotta keep them separated' : item
return <Text>{newItem}</Text>
})
return (
<View>
{newArr}
</View>
);
}
}
Here's a working expo snack
A little inexperienced here. Trying to render data with React Native Flatlist.
Here is my data:
data = {
-LYIaWAxkQA38DAbC3By: {hours: "6", type: "Welding"}
-LYIab-Ys9WkUNHE2cqL: {hours: "2", type: "Hair Drying"
}
I am trying to use:
<FlatList
data=data
renderItem={
(item) => <Text>{item.type}</Text>
}
keyExtractor={(item, index) => index.toString()}
/>
I want to be able to create a component that is able to use each type and hours.
I keep getting error, 'Invariant Violation: Tried to get frame for out of range index NaN'
Appreciate any help.
Try using an array:
const data = [
{
hours: "6",
type: "Welding",
identifier: "-LYIaWAxkQA38DAbC3By",
id: 1
},
{
hours: "2",
type: "Hair Drying",
identifier: "-LYIab-Ys9WkUNHE2cqL",
id: 2
}
]
<FlatList
data=data
renderItem={
(item) => <Text>{item.type}</Text>
}
keyExtractor={(item, index) => item.id.toString()}
/>
are you using firebase? if yes, you can use forEach
componentDidMount(){
this._convert();
}
_convert = () => {
let ALL_DATA = this.state.data;
let CONVERTED_DATA = [];
ALL_DATA.forEach( (individu_Items) => {
CONVERTED_DATA.push(individu_Items)
}
this.setState({flatlist_data: CONVERTED_DATA})
}
transform your object in an array:
data = Object.keys(data).map((key) => data[key]));
I have two arrays, one for products, and one for supervisors. Obviously, both have very different types of data. I want to create a scrollable list that will display all of the products followed by all of the supervisors using a single scrolling list. Is this possible with React Native's FlatList? If so, or if not, how can I go about doing this?
I can currently render a single data array as follows:
<FlatList
data={this.state.products}
renderItem={this.renderItem}
/>
But, how can I append the supervisors data to the end of this list? Obviously, because the data is quite different between the two arrays I cannot simply merge the arrays and or the same renderItem function.
How can I display two completely different types of data one after the other in the same scrollable list?
You can merge your data together and use single FlatList with a single renderItem prop. Without a sample of your data its a little guessing game but below is an example how you can do.
Example
Let's assume you have data structure like below.
const Products = [
{
id: 1,
name: 'Product 1'
},
{
id: 2,
name: 'Product 2'
},
{
id: 3,
name: 'Product 3'
},
{
id: 4,
name: 'Product 4'
},
];
const Supervisors = [
{
belongsToPruduct: 1,
name: 'SuperVisor 1'
},
{
belongsToPruduct: 3,
name: 'SuperVisor 2'
},
{
belongsToPruduct: 2,
name: 'SuperVisor 3'
},
{
belongsToPruduct: 4,
name: 'SuperVisor 4'
}
];
And let's assume you render Products in a FlatList. You can do something like below in your renderItem function
renderItem = ({ item }) => {
const superviors = Supervisors.filter((supervisor) => supervisor.belongsToPruduct === item.id)
return (
<View style={styles.productContainer}>
<Text style={styles.productName}>{item.name}</Text>
<View style={styles.supervisorsContainer}>
{
superviors.map((supervisor) => <Text style={styles.supervisorName}>{supervisor.name}</Text>)
}
</View>
</View>
)
}
UPDATE
Referring to your comment I think then you can get use of SectionList rather than FlatList
<SectionList
renderSectionHeader={({ section: { title } }) => <Text style={{ fontWeight: 'bold' }}>{title}</Text>}
sections={[
{ title: 'Products', data: Products, renderItem: ({ item, index, section: { title, data } }) => <Text>{item.name}</Text> },
{ title: 'Supervisors', data: Supervisors, renderItem: ({ item, index, section: { title, data } }) => <Text>{item.name}</Text>},
]}
keyExtractor={(item, index) => item.name + index}
/>
I did this by creating a third array which contains FlatList compononets. Then rendered only the third array with new FlatList component