Stuck on "unique key" warning - react-native

I'm currently adapting a Mobx tutorial for a to-do app. link
What I want to do is add a simple counter button to each rendered list item. I figured this would be pretty simple, but I must be making a syntactical error because I cannot get things to mesh properly. The main error I'm getting right now is that "Each child in an array or iterator must have a unique 'key' property". I figured I would solve this by adding in a uuid to each counter(the counter is what cause the error to begin appearing). Alas, I cannot seem to find a solution.
Here is the github repository for the app: https://github.com/Darthmaul/UmCount
Specifically this file is the one that has received the most modifications. I also added a "counterstore.js" file to keep the store of the counter intact(which seems to be failing).
Any help would be appreciated. At this point I just don't know what's wrong and what's right.
Thanks,
Andrew

When you have a component which has an array of children, each of which might have its own children, not only the top-level children but also each child at a deeper level needs its own key.
The problem with doing
const Items = ({items}) => (
<View style={{flex: 1, paddingTop: 10}}>
{items.map((item, i) => {
return (<View>
<Text style={styles.item} key={i}>• {item} - {store.counter}</Text>
<Button onPress={() => store.increment()} title="+1" color="#50EB5D" key={uuid()} />
</View>
)})
}
</View>
)
is that your Text and Button components have keys, but your Views do not.
React uses keys for reconciliation and finding the minimal change whenever a list of components changes. How you set keys here will affect the reconciliation policy when your array changes: You can set your View, Text and Button for each array element to have the same key if you know that whenever one of them changes, the entire row changes, but if each of them changes separately, then you should generate a unique ID for each of them.
React docs on reconciliation and keys.

Related

Setting key for Swiper React Native

I have a Swiper implemented in my react native project (react-native-swiper), which I plan to show data along with pagination guides. While the swiper is working, I'm having an issue creating a consistent key - right now if one of the objects in the swiper list updates it may offset the index. While I've been able to prevent such glitches by adding a unique key on the objects, the Swiper pagination however is not in sync. The former key gets its data from mapping the list, but the Swiper object is on the outer scope so it's not able to use that identifier. I've attached the code for reference. Please let me know if I can set a key that ensures stable changes and correct pagination. Thank you.
<Swiper
key={data.length} //This is the key that enables correct pagination currently
paginationStyle={{bottom: -20}}
height={330}
dot={<View style={styles.Dot} />}
activeDot={<View style={styles.ActiveDot} />}
>
{data.map((dataX, index) => {
return (
<View key={dataX.uniqueToken}> //This (or the index) is the key I'd like to use on the Swiper element
... stuff to show images, etc.
</View>
)
})}
</Swiper>
You can try use index as a key value, I always using index and no problem

Flatlist vs map callback columns in React native

I am trying to show a bunch of images in rows of 3 images and using Flatlist i got this error "Can't perform a React state update on an unmounted component". I tried everything about using an unmount flag but the problem still persists.
However, noticed that with the map() callback function that problem doesn't exist. The problem is how to create A View with map() in order to render 3 images at each row. Is there a possible way to create a View with 3 columns using map()?
If your problem is "The problem is how to create A View with map() in order to render 3 images at each row." then i'll answer your question with a .map() answer instead of a flatlist answer.
For .map() it will render as many images as there are in the array that you've called .map on. The spacing in that scenario is moreso done by the container you've wrapped it in, plus you can give each image a width of '33%'. Meaning, you'll want something like this:
<View style={{flexDirection: 'row', flexWrap: 'wrap'}}>
{YOURARRAY.map(() => {
return(
---- your image with the style {width: '33%'} here ----
)}
<View>

How to Set TextInput Field Without Using Value - React Native

Is there any way to set the TextInput field without using the value parameter?
I am using _lastNativeText to get data from the field on submission because onChangeText={} and value={} makes typing lag very badly, so instead I am just getting the input without state via _lastNativeText using a ref like this...
<TextInput
ref={(input) => { myTextInput = input }}
/>
Then getting the value with
myTextInput._lastNativeText
This works fine - it is not my favorite solution, but appears to be the only option I have.
This is for a posts feed. So my question is when I want to edit a post, how do I populate the TextInput using some other native function of which I am not aware?
Using setText(postData) and setting value={text} is the obvious answer, but that is not what I want.
Try this
myTextInput.setNativeProps({ text: 'XXXX' })

ReactNative render nested list slow: Suggestion

JSON Structure:
sectionItems={key: ..., name: .., title: ..listOf 20 nested data }
data =
{
"sections": [...sectionItems of 50 items]
}
When displaying in the FlatList its rendering too slow,
<FlatList
renderItem={({item}) => <Section item={item} />}
initialNumToRender={lastSelectedItemIndex}
/>
Prior to FlatList have used SectionList to render the data but it was too slow to render the data, the requirement is to show all the content in one shot, but FlatList takes too much time to load the items in the viewport, showing more whitespace.
What can be best solution the render a nested list, SectionList or FlatList, the list should have selected item highlighted, so i need to connect to store too.
I just do this by nesting flat lists and taking care of proper rendering within list items. For example I had a list of days, and per each day there were 'entries'. Instead of section list I have a flat list which holds "days list". The day list displays the list header for new day, say 14th January. the rest of this list item is a flat list, containing all the entries for this list. You can highlight easily by making the specific list item wrapped in a touchable. I must render 1000 elements at time and have never had performance issues besides massive updates coming after syncing process. I think this approach might work best for you.

How to pass the acquired ID param into a variable - React Native

I am using axios to make several http request simultaneously. Like so:
Afterwards I create a helper function called renderMoviesTrending() to show the data acquired from the api
As you can see from the screenshot, I am passing the movie id (movieTrending.id) via a onPress to the function onPressPosterTrending. This allows me to pass the data of a single selected movie along to movieDetails.js. (all this works fine)
The issue that I am facing now is I need to make a new api call where I must place the movieTrending.id in it, to retrieve a new set of data that allows me to play trailers for a chosen movie based of of the movie id.
The new url for that http request for retrieving the data concerning trailers is the following -> https://api.themoviedb.org/3/movie/353486/videos?api_key=2e3b3e231665535756b50c3e216e0467
Where the api data looks like this:
So when I create a new helper function to make that http request, how to get the movie id from the previous function into the url ?
UPDATED Code of my app.js
https://gist.github.com/anonymous/84107c7d295a848fbe1102b6df9ee8f5
I hope you guys understand what I am trying to achieve here. I have googled this but not really found anything. Maybe I am searching on the wrong keywords
Any help is much appreciated
I feel the easiest way is just storing the current movie trending ID in the state as a new variable. That way it will be available for the whole component.
You are actually already storing the current trending movie.
You can just access it with this.state.selectedMovieTrending.
So your url becomes: https://api.themoviedb.org/3/movie/{this.state.selectedMovieTrending}/videos?api_key=2e3b3e231665535756b50c3e216e0467
Or 'https://api.themoviedb.org/3/movie/' + this.state.selectedMovieTrending + '/videos?api_key=2e3b3e231665535756b50c3e216e0467
use flatlist from react native
like this
<FlatList
data={this.props.posts}
keyExtractor={(item, index) => item._id}
renderItem={({item}) =>{
return(
<View >
<TouchableHighlight onPress={() => this.props.navigation.navigate('SingleMovieScree',{movieid:item.id})} >
// Use React navigation to nvaigate to another screen
<Image style={styles.Poster} source={{ uri: `${TMDB_IMG_URL}${(movieTrending.poster_path)}` }} />
</TouchableHighlight>
</View>
)
}
}
/>
so on another screen you will get movie id parameter like this
console.log(this.props.navigation.state.params.movieid);
then use this id to get movie details from request and display in your screen