I am still having trouble understanding ref's in React Native (and React in general). I am using functional component. I have a FlatList that has many items. How do I create a reference for a thing within an item like a Text or View component?
<FlatList
data={data}
renderItem={({ item }} => {
<View>
... lots of other stuff here
<TouchableOpacity onPress={() => _editITem(item.id)}>
<Text ref={(a) => 'text' + item.id = a}>EDIT</Text>
</TouchableOpacity>
</View>
}
/>
Then in _editItem I want to reference the Text component so that I can change its text from 'EDIT' to 'EDITING', or even change its style, or whatever.
_editPost = id => {
console.log(text + id)
}
I have tried...
FeedComponent = () => {
let editPosts = {}
<FlatList
data={data}
renderItem={({ item }} => {
<View>
... lots of other stuff here
<TouchableOpacity onPress={() => _editITem(item.id)}>
<Text ref={(a) => editPosts[item.id] = a}>EDIT</Text>
</TouchableOpacity>
</View>
}
/>
...and a few other things, but I think I might be way off so I could use some guidance.
Typically you don't use refs in react to update content like text. Content should be rendered based on the current props and state of your component.
In the case you describe you'll probably want to set some state in the parent component that then impacts the rendering of the item.
As a sidenote refs are used if you need to trigger a method on a child component like calling focus on a TextInput for example but not for imperatively updating component content.
In your case you'll want to update some state representing the current active item. Something like:
import React, {useState} from 'react';
FeedComponent = () => {
const [activeItem, setActiveItem] = useState(null);
<FlatList
data={data}
renderItem={({ item }} => {
return (
<View>
... lots of other stuff here
<TouchableOpacity onPress={() => setActiveItem(item.id)}>
{activeItem === item.id
? <Text>EDITING</Text>
: <Text>EDIT</Text>
}
</TouchableOpacity>
</View>
);
}
extraData={activeItem}
/>
Related
I have a grid of pokemons (below).
I am using flatlist to render the pokemons using the data fetched from an api. When I click on a pokemon I want to display the next page (below)
//Function for FlatList - To render Pokemon images
const renderPokemon = ({ item }) => {
let url = item.url
const idPokemon = url.split('https://pokeapi.co/api/v2/pokemon/')
const link = urlImage + idPokemon[1].substring(0, idPokemon[1].length-1) + ".png"
return (
//Individual images
<View style={styles.pokemons}>
<Image
style={styles.image}
resizeMode='contain'
source={{uri:link}}
/>
<Text style={styles.text}>{item.name}</Text>
</View>
)
}
//App container
<NavigationContainer>
<View style={styles.container}>
<TopBar/>
{/**Pokemon image grid display*/}
<FlatList
numColumns={2}
data={pokemons}
renderItem={renderPokemon}
keyExtractor={pokemon => `key-${pokemon.name}`}
style={styles.container}
onPress={() => alert('clicked')} //WHERE DO I PUT THIS ?
>
</FlatList>
</View>
<NavigationContainer>
But it doesnt seem to be responding. I am using Alert just to test. How to I get the flatlist imaages to handlle onpress so it navigates to the next page and displays the data for that specific pokemon?
Thanks in advance!
You need to add Pressable inside each rendered item, after importing from react-native and add onPress event and do as required in the callback function.(like in your case, navigate to new screen). You can pass pokemonDetailsObj in route params or just the pokemonId, depending on how the Pokemon details Component works.
I would also suggest you to create stack navigator and register your screen components to better use [reactnavigation][1] features.
import { Pressable} from 'react-native';
const renderPokemon = ({ item }) => {
let url = item.url
const idPokemon = url.split('https://pokeapi.co/api/v2/pokemon/')
const link = urlImage + idPokemon[1].substring(0, idPokemon[1].length-1) + ".png"
return (
//Individual images
<Pressable
onPress={() => {
// pass the 'ScreenName' of the Pokemon details component.
props.navigation.navigate('ScreenName', {
// props to be passed to the component like pokemonId or full pokemon Details Obj
})
}}
>
<Image
style={styles.image}
resizeMode='contain'
source={{uri:link}}
/>
<Text style={styles.text}>{item.name}</Text>
</Pressable>
)
}
[1]: https://reactnavigation.org/docs/getting-started
I want to pass the title of a React Native Button component into a neighbouring function. I am using React Native functional components only for this application.
Here's the component. I would like to pass the title of the button pressed by the user, which will be either 'English' or 'Arabic', into the function submitLanguageSelection so that I can then save that value into useLocalStorage(), a custom hook I wrote to handle AsyncStorage, so that the next time the user uses the app, their language choice will be persisted, and they will not be shown the ChooseYourLanguageScreen again.
All help appreciated, thank you.
const ChooseYourLanguageScreen = ({ navigation }) => {
const [saveData, storedValue, errorMessage] = useLocalStorage();
const [userSelectedLanguage, setUserSelectedLanguage] = React.useState('');
const submitLanguageSelection = () => {
//TODO: receive params from onPress
//TODO: save the data locally
//TODO: navigate to welcome screen
};
return (
<View style={styles.container}>
{errorMessage ? <Text>{errorMessage}</Text> : null}
<Text style={styles.text}>This is the Choose Your Language Screen</Text>
<View style={styles.buttons}>
<View>
<Button
title={'English'}
onPress={() => submitLanguageSelection()}
/>
</View>
<View>
<Button title={'Arabic'} onPress={() => submitLanguageSelection()} />
</View>
</View>
</View>
);
};
You can simply pass it to the function
<Button title={'Arabic'} onPress={() => submitLanguageSelection('Arabic')} />
And access like below
const submitLanguageSelection = (language) => {
console.log(language);
};
Getting data from a sibling component is an anti-pattern.
The source of the knowledge of the language options is the ChooseYourLanguageScreen component (as seems from your snippet), so it should hold the list of available languages. Having that, you can just iterate through them and render the appropriate components:
<View style={styles.buttons}>
{languages.map((language) => (
<View key={language}>
<Button
title={language}
onPress={() => submitLanguageSelection(language)}
/>
</View>
))}
</View>
I have scroll view in my HomeScreen with my measures that is array of Measure component.
<ScrollView>{measures}</ScrollView>
My Measure component looks like this:
class Measure extends Component {
render() {
return (
<View key={this.props.keyval}>
<TouchableOpacity onPress={deleteItem(this.props.val.measure_id)}>
<Text style={styles.measure}>
ID: {this.props.val.measure_id}
</Text>
</TouchableOpacity>
</View>
);
}
deleteItem(id) {
// delete item
);
}
}
My question is, how to notify parent component HomeScreen that Measure was deleted to reload scroll view items? Or Maybe you have better idea how to:
display measures
delete one in onPress item
reload items in scroll view
Thans for any advices
In your case it should be something like this:
class HomeScreen extends Component {
state = {
measures: []
};
handleDelete = (id) => {
// item was deleted
}
render() {
const { measures } = this.state;
const measuresList = measures.map(measure => (
<Measure
key={measure.measure_id}
onDelete={this.handleDelete}
val={measure}
/>
));
return (
<ScrollView>{measuresList}</ScrollView>
);
}
}
class Measure extends Component {
render() {
return (
<View key={this.props.keyval}>
<TouchableOpacity onPress={deleteItem(this.props.val.measure_id)}>
<Text style={styles.measure}>
ID: {this.props.val.measure_id}
</Text>
</TouchableOpacity>
</View>
);
}
deleteItem(id) {
const { onDelete } = this.props;
// delete item
onDelete(id); //will call parent method.
}
}
I recommend using FlatList as it render only those items which are visible. Much better in terms of performance, especially in big lists taken from API.
Example:
<FlatList
data={measures}
keyExtractor={item => item.id}
renderItem={({ item }) => <Measure
id={item.id}
anyOtherNeededPropsKey={anyOtherNeededPropsValue}
/>}
/>
Pass an additional property onDelete to the Measure and call it in deleteItem method
I am trying to render a FlatList inside a component. The Component itself is inside a ScrollView.
I am using map function to loop through the data to pass into the component.
Earlier I was using ScrollView instead of FlatList. It was working fine, but was rendering slow. So I decided to use FlatList.
Here's my code:
renderComp(){
const { filtersView,cats,cats_title, clearStyle} = styles;
const data = this.props.ingreds;
const arr = Object.entries(data);
return arr.map(i=> {
const name= i[0];
const items_obj = i[1];
const items = Object.values(items_obj);
return(
<View key={name} style= {filtersView}>
<View style={cats}>
<Text style ={cats_title}>{name}</Text>
<Text style={clearStyle}>Clear All</Text>
</View>
<View style={{justifyContent:'flex-start', alignItems:'flex-start'}}>
<FlatList
style={{ marginRight:6}}
data={items}
keyExtractor={(x,i)=> i.toString()}
renderItem={({item}) =>{
this.renderItems(item)
}}
/>
</View>
</View>
)
})
}
And here's the ScrollView Component:
<ScrollView contentContainerStyle={{alignItems:'flex-start',
justifyContent:'flex-start',flex:1, height:72}} >
{this.renderComp()}
</ScrollView>
And The loop stops after one iteration.
Here's the output: https://i.stack.imgur.com/yM151.png
Any suggestions?
ReactNative FlatList renderItem method should return a ?React.Element component. In your case either use return this.renderItems or skip the inner brackets.
https://facebook.github.io/react-native/docs/flatlist#renderitem
({item}) => this.renderItems(item)}
I am trying to render out a list of object data using FlatList in my React Native component, however I am getting a blank screen without any errors on the console which is why it is rather difficult to get to the bottom of the issue here. The data is made available to the component using Redux-Saga approach and supplied to the FlatList which is showing up a blank screen without any errors. To double check if the FlatList is working fine I did a mockup array in component and passed to the FlatList which renders out the UI as expected. Following is the code I am using here;
=======================================================
class Mobile extends Component {
componentDidMount() {
let { readPostsAction } = this.props;
readPostsAction();
}
renderItem = ({ item }) => {
return (
<View>
<TouchableOpacity onPress={() => this.props.navigation.navigate('HomeDetails', { item })}>
<Card>
<CardItem header>
<Text style={styles.titleHeading}>{item.title}</Text>
</CardItem>
<CardItem cardBody>
<Content style={styles.cardContainer}>
<CustomCachedImage
component={FitImage}
source={{ uri: contentURL(item.attachments[0].url) }}
style={{ width: width, height: 200 }}
/>
<HTML tagsStyles={bodyText} html={reduceStringLength(contentText(item.excerpt))} />
</Content>
</CardItem>
</Card>
</TouchableOpacity>
</View>
)
}
keyExtractor = (item, index) => item.id;
render() {
const { dataSource } = this.props;
console.log('this.props', this.props);
return (
<View>
<FlatList
data={dataSource}
keyExtractor={this.keyExtractor}
renderItem={this.renderItem}
/>
</View>
);
}
}
function mapStateToProps({ launchAppReducer }) {
return {
isLoading: launchAppReducer.isLoading,
dataSource: launchAppReducer.data
}
}
export default connect(mapStateToProps, { readPostsAction: actions.readPostsAction })(Mobile);
=======================================================
Here is the screenshot of the console showing that the data is available in the component.
Modify your FlatList code and retry
<FlatList
data={dataSource}
extraData={this.props}
keyExtractor={this.keyExtractor}
/>
There was the problem at in the Actions, I was firing readPostsActions instead I should have fired readMobilePostsActions - it works fine now, thank you guys all the all input and help here.
Regards
You just need to add this style in your Flatlist:
<FlatList
style={{height:'100%'}}
data={dataSource}
keyExtractor={this.keyExtractor}
renderItem={this.renderItem}
/>