I went through React-Native docs to figure out what is renderRow() but for some reason I am unable to comprehend what does it say from Facebook React-Native docs
This what the official docs says
renderRow
(rowData, sectionID, rowID, highlightRow) => renderable
Takes a data entry from the data source and its ids and should return a renderable component to be rendered as the row. By default the data is exactly what was put into the data source, but it's also possible to provide custom extractors. ListView can be notified when a row is being highlighted by calling highlightRow(sectionID, rowID). This sets a boolean value of adjacentRowHighlighted in renderSeparator, allowing you to control the separators above and below the highlighted row. The highlighted state of a row can be reset by calling highlightRow(null).
[Question:] Can someone please explain me this with example?
ListView is deprecated, use FlatList instead with the equivalent renderItem method. This is responsible of the actual rendering of each row based on the data records:
const data = [
{ key: '1', label: 'foo' },
{ key: '2', label: 'bar' }
]
renderTheItem = ({item}) => {
return <Text>{item.label}</Text>
}
<FlatList
data={data}
renderItem={this.renderTheItem}
/>
And the rendered result will be something like this:
<View> --> coming from FlatList wrapper
<Text key="1">foo</Text> --> coming from the custom renderTheItem function
<Text key="2">bar</Text>
</View>
It is mandatory to either add a unique key prop for each data record, or define a keyExtractor function. Also important to destruct the item in the renderer function with ({item}) as it has other meta parameters as written in documentation of FlatList.
renderItem({ item, index, separators}) => {}
Related
I have a flatlist that shows a messages chat. I want to start at the bottom of the flatlist (showing the most recent messages). I added 'inverted={true}' and 'data={data.reverse()}' as the props.
It is sort of working, but the data alternates being reversed and not reversed every time i leave and enter the chat again.
Anyone know the fix?
Attached code
.reverse() mutates the original list.
If you do want your list reversed, do it like this
const App = ({ data }) => {
const reversed = [...data].reverse(); // Make a shallow copy, then reverse the copy
return <Flatlist data={reversed} inverted />;
};
However, you will probably notice that you don't want your list reversed, because inverted is already reversed.
const App = ({ data }) => {
return <Flatlist data={data} inverted />;
};
When I start screen, I get data from useQuery
And by using useEffect, I get data and immediately sort this data.
After sorting data, I put this data to useState named flatlistdata.
And I draw screen by using Flatlist with this data.
Flatlist data should be sorted.
So I need to refined data before.
const { data: allFeedData, refetch: allFeedRefetch } = useQuery(SEE_ALL_FEED_ORDER);
const [flatlistdata, setFlatlistdata] = useState([]);
useEffect(() => {
allFeedRefetch();
setFlatlistdata(
[...allFeedData.seeAllFeedOrder].sort(function (a, b) {
return b.directFeedNumber - a.directFeedNumber;
})
);
}, []);
<FlatList
data={flatlistdata}
keyExtractor={(item) => item.id}
renderItem={RankRow}
refreshing={refreshing}
onRefresh={refresh}
/>
However when I click screen, it says undefined is not an object which means data is empty.
I think the problem here is that screen is drawn, before sorting data and putting it to useState...?
I need a little hint ðŸ˜
Please help me.
The query is an asynchronous operation, so, the data variable will always start out as undefined while the network request completes. There are two possible solutions.
In your useEffect, only set your state if data is defined. Wrap your setFlatlistData with if (allFeedData?.length) { ... }
Use the React Query selection prop to have Query do the same operation before allFeedData gets populated. Check the select prop in the docs for useQuery: https://react-query-v2.tanstack.com/reference/useQuery
How would "item" know that it has the data from the Data properties? I mean I passed in the data using the data properties of Flatlist component and it seems I can give any name to the keyExtractor property and it will know to get the data from the data property. Is there any explanation for this? Thanks a lot and in advance.
<Flatlist
data={someData}
keyExtractor={item => item.TitleID}/>
I'll give you a briefly introduction and an example of what callback functions are and how to use them.
Basically you can define a function and it's parameters with any types. By that, you can also expect functions as parameters (those are also called higher order functions) and call them inside the parent function at any time you wish. Look at this and especially at the lambda calculus.
function bar(something) {
console.log(something);
}
function foo(callback) {
callback("Hello");
}
// This will generate the output 'Hello'.
foo(bar);
// This is the same, but using lambda calculus.
foo(something => console.log(something));
As you can see, you can pass function definitions as parameters to other functions. This is exactly, what your example is doing. I also give you an extra example.
import React from "react";
const FlatList = ({ keyExtractor, data, ...props }) => {
return (
<ul>
{data.map((item, index) => (
<li key={index}>{keyExtractor(item)}</li>
))}
</ul>
);
};
export default FlatList;
Here I tried to mockup the FlatList of your example. You can see the data.map call, which acts as the higher order function from the previous example. The FlatList component has a property called keyExtractor, which will be called for each element of the data property. Now, you can easily provide keyExtractor as follows.
const someData = [
{ name: "Something", id: 1 },
{ name: "Anything", id: 2 }
];
//...
<FlatList
data={someData}
keyExtractor={item => item.id}
/>
This will render an unordered list, which contains the id of every element of someData. In this case it is just a projection of your data.
Here the executable example https://codesandbox.io/s/laughing-paper-lmi22.
Cheers
Under the hood, FlatList passes your data item to the keyExtractor.
Here your function myKeyExtractor accepts a parameter, which is basically the reference to your data.
function myKeyExtractor(item) {
return item.TitleID;
}
<Flatlist
data={someData}
keyExtractor={myKeyExtractor}
/>
Let's take a simple example here.
It is similar to the parameters of add and subtract functions here.
You could name the parameters anything you like. Parameters are just placeholders for your value.
function add(x, y) {
return x + y;
}
function subtract(thisIsAFirstParameter, thisIsASecondParamater) {
return thisIsAFirstParameter - thisIsASecondParamater;
}
add(10, 5);
subtract(10, 5);
I am implementing a FlatList with initialScrollIndex and getItemLayout. However, every time my app starts up, it renders the first elements somehow and then jumps to the actual initialScrollIndex. This means that the actual performance boost that I am supposed to get, isn't working.
When checking the getItemLayout function I can see that when it renders the first index that is passed is -1 instead of the initialScrollIndex, thus throwing an error and breaking. The other random indexes are passed untilinitialScrollIndex` is passed.
Any ideas why this might be happening?
FlatList:
renderMonthPerMonth() {
const data = this.deriveMonthPerMonthDataFromProps();
const initialScrollIndex = this.deriveInitialScrollIndex();
return (
<FlatList
data={data}
ref={'flatlist'}
initialNumToRender={3}
onLayout={this.onLayout}
getItemLayout={this.getItemLayout}
showsVerticalScrollIndicator={false}
initialScrollIndex={initialScrollIndex}
renderItem={this.renderOneMonthPerMonth}
ListHeaderComponent={this.renderListHeader}
keyExtractor={el => `${el.monthName}-monthPerMonth`}
onScrollBeginDrag={() => this.onExpandMenu('scroll')}
ItemSeparatorComponent={this.renderItemSeparator}
ListFooterComponent={this.renderFooterComponent}
/>
);
}
getItemLayout:
getItemLayout(data, index) {
const monthAsNumber = moment().month(data[index].monthName).format('M')-1;
const SEPARATOR_HEIGHT = 25;
const MONTH_NAME_CONTAINER_HEIGHT = 55;
const ONE_DAY_HEIGHT = (((width-40)/7)/1.1);
const WEEKS_IN_MONTH = this.weeksInMonth(moment().format('YYYY'), monthAsNumber);
// define oneMonthHeight using weeksInMonth method
const oneMonthHeight = (ONE_DAY_HEIGHT * WEEKS_IN_MONTH) + (MONTH_NAME_CONTAINER_HEIGHT + SEPARATOR_HEIGHT);
return {
length: oneMonthHeight,
offset: oneMonthHeight * index,
index,
}
}
Console:
I have a suspicion the problem is in the renderItem prop and subsequently the renderOneMonthPerMonth() method.
Referring to the FlatList docs:
This is a PureComponent which means that it will not re-render if props remain shallow-equal. Make sure that everything your renderItem function depends on is passed as a prop (e.g. extraData) that is not === after updates, otherwise your UI may not update on changes. This includes the data prop and parent component state.
and
renderItem({ item: Object, index: number, separators: { highlight: Function, unhighlight: Function, updateProps: Function(select: string, newProps: Object) } }) => ?React.Element
Having this.deriveMonthPerMonthDataFromProps() may not be Pure (depending on that prop, I cannot see it).
Try fetching all the data and assigning to a const outside the renderItem method that is passed. Alternatively if this data is pure and not changing you can skip this step.
The next two are probably the crux of the issue: create a render function resembling this:
const renderItem = ({ item, index }) => {
return <DummyComponent item={item} index={index} /> // item and index are not necessarry just demonstrating
}
Ensure you have a keyExtractor returning unique identifier. Else this will error in a similar manner to your issue. Try the below as a sanity check
keyExtractor={(item, index) => index.toString()}
If the above is not the issue you also need to ensure that your data prop on your Flatlist is an array and not an Object or other data structure as explained in the data section of the Flatlist docs.
If your data is of type object and you don't rely on the keys to access specific pieces of data in other methods, you can change the initial data to be an array of objects like so:
[
{ ...monthOneData },
{ ...monthTwoData },
{ ...monthThreeData }
]
Or, if you want to keep the original data as an object you can convert it to an array of keys by using
Object.keys(this.state.data)
Then in your FlatList you could do something like this:
<FlatList
data={Object.keys(this.state.data)}
renderItem={({item}) =>
<DummyComponent month={this.state.data[item].month} /> // item is now the key value of the objects (almost like a look up table)
// also not having curly braces implies an implicit return in this case
}
/>
I have an async function like this:
getDeals() {
if(this.props.user) {
this.setState({loading: true});
this.setState({deals: []});
var parameters = {
zip: this.props.user.zip,
sort: 'All',
category: this.props.selectedCategory,
company: this.props.user.company,
page: null,
user: this.props.user,
search: null
}
axios.post(`${constants.api}/grab-deals/`, parameters)
.then((response) => {
this.setState({totalDeals: response.data.length});
this.setState({deals: response.data, loading: false, refreshing: false});
this.forceUpdate();
})
}
}
And a FlatList component Like this:
<FlatList data={this.state.deals} style={{flex: 1, padding: 10}} extraData={this.state} keyExtractor={this.keyExtractor} renderItem={this.renderDeal.bind(this)} />
Here is the keyextractor:
keyExtractor = (item, index) => item.id;
When I call this.getDeals() the first time it works great. However when I call it a second time the axios call get's all of the correct data, but the flat list still keeps old data (it doesn't remove items that aren't in the new call).
How do I get the FlatList to always reflect the returned data?
Call this.getDeals() in componentWillUpdate() and update props?
I believe you confussing what props and state is for. Basically state is used for things that could change during the lifecycle of the component and props are kept immutable. I use them for behavior.
Unless you are changing the parameters for the getDeals function on the second call, see that all of the properties are based on the props, which are not always updated.
RN has a method called componentWillUpdate that is triggered with the new props which you can then be used to update the component itself. If you want to keep using props in your getDeals method, you will need to check if the props have changed (this happens when the parent updates the child with new props) and then trigger again the data fetch.
If this does not help, please post more code.
According to the docs you need to set the state.selected value
By passing extraData={this.state} to FlatList we make sure FlatList
itself will re-render when the state.selected changes. Without setting
this prop, FlatList would not know it needs to re-render any items
because it is also a PureComponent and the prop comparison will not
show any changes.