I have a flatlist and it's working fine, I'm trying to put a function inside the code that is rendering my item but it gives me an error, and i need to put the function there so i can read the item's properties, here is my code:
_renderItem ({ item, index}) {
_shareText() {
Share.share({
message: item.name,
})
}
return (
<Button title="Share" onPress={this._shareText}/>
);
}
try this, i can see that _shareText is not defined like a function in the component
_shareText(item) {
Share.share({
message: item.name,
})
}
_renderItem({ item, index }) {
return (
<Button title="Share" onPress={() => { this._shareText(item); }} />
);
}
Related
I'm using FlatList as follows:
<FlatList
data={nodes}
renderItem={({ item }) => <Goal goal={item} />}
keyExtractor={item => item.id}
/>
I'm getting this error:
Error: Text strings must be rendered within a component.
when following component is passed to renderItem
const Goal = (props: { goal: GoalProps }) => {
const listTags = props.goal.tags.map(tag =>
<li key={tag.id}> {tag.name} </li>
);
return <>
<Text>goal title: {props.goal.title}</Text>
<ul>{listTags}</ul>
</>
}
When I simply return just one <Text> then it works without error.
This works:
const Goal = (props: { goal: GoalProps }) => {
const listTags = props.goal.tags.map(tag =>
<li key={tag.id}> {tag.name} </li>
);
return <Text>goal title: {props.goal.title}</Text>
}
How can I pass a more complex component to FlatList? Or maybe there is another list component I can use? I'm new to React and React Native.
Hi guys I am having trouble finding a solution on my problem because I want to navigate to another page but here's the problem
function NewOrderPopUp({id, services, name, rating, accepted, destinationPlaceName, userPlaceName, driverName, driverContactNumber, driverRating, driverTrackingNumber})
{
async function toggleAcceptBooking()
{
await firestore()
.collection('userBookingRequest')
.doc(id)
.update({
accepted : !accepted,
driverName: 'Sample Driver',
driverContactNumber: '09123456789',
driverRating: '4.9',
driverPlateNumber: 'NFT-2020',
driverTrackingNumber: GenerateTrackingNumber(),
})
CheckIfBookingAccepted();
}
}
return (
<View>....</View>
);
export default NewOrderPopUp;
And I am calling the NewOrderPopUp Page in another file.
like this
import NewOrderPopUp from "../../components/NewOrderPopUp";
const HomeScreen = () => {
//... codes here
return (
<View>
<FlatList
horizontal
contentContainerStyle={{paddingHorizontal: 30}}
data={userBookingData}
keyExtractor={(item) => item.id}
renderItem={({item}) => <NewOrderPopUp {...item}/>} />
</View>
);
}
export default HomeScreen;
What I wanted is that if I click the toggleAcceptBooking it will nagivate to another page like
navigation.navigate('BookingPage');
Can someone enlighten me please . Thank you.
Do it by passing navigation down as a prop.
do the following steps.
handle navigation prop in HomeScreen
const HomeScreen = ({ navigation }) => {
}
pass navigation as a prop to NewOrderPopUp
<FlatList
...
renderItem={({item}) => <NewOrderPopUp navigation={navigation} {...item}/>} />
handle navigation prop in NewOrderPopUp and use it to navigate.
function NewOrderPopUp( {navigation, ...} ){
async function toggleAcceptBooking(){
await ...
navigation.navigate('BookingPage');
}
}
So what I'm trying to do is fetching data from an API (works well), that has this autocomplete function.
Link to example: https://autocomplete.aws.dk/
Link to the guide: https://autocomplete.aws.dk/guide2.html
What is hard for me, is that the guide is HTML, and this is suppose to work in React Native.
So far I made an input field, that can detect when writing minimum two letters will show a list of addresses.
What I want is when the address is clicked, it takes that value and places it in the input field.
Heres my code:
The API fetch:
import React from "react";
import url from "./url";
export default class DawaFetch extends React.Component {
static defaultProps = {
options: {},
minCharacters: 2,
};
state = {
value: "",
suggestions: [],
};
handleChange = ({ target: { value } }) => {
this.setState({ value });
if (this.props.minCharacters <= value.length) this._fetch(value);
};
_fetch = (value) => {
fetch(
url("https://dawa.aws.dk/adresser/autocomplete", {
q: value,
["per_side"]: 100,
...this.props.options,
}),
{
method: "GET",
headers: {
"Accept-Encoding": "gzip, deflate",
},
}
)
.then((response) => response.json())
.then((json) => this.setState({ suggestions: json }))
.catch((err) => console.error("parsing failed", err));
};
render = () =>
this.props.children({ ...this.state, handleChange: this.handleChange });
}
And here is my view:
<DawaFetch>
{({ value, suggestions, handleChange }) => {
console.log(suggestions);
return (
<View>
<CustomInputs
type="text"
value={value}
onChange={handleChange}
/>
{suggestions.map((suggestion) => (
<TouchableOpacity>
<NormalText key={suggestion.adresse.id}>{suggestion.tekst}</NormalText>
</TouchableOpacity>
))}
</View>
);
}}
</DawaFetch>
Tried different solutions by making it a FlatList with renderItem, and making an onPress function, but I could never make it work.
Hopefully someone can guide me in the right direction, I might been overthinking this.
React-Native TextInput onChange value is not available inside the target as it's available in HTML, Remove target from handleChange function like below, also it's not onChange it's onChangeText in TextInput.
handleChange = (value) => {
this.setState({ value });
if (this.props.minCharacters <= value.length) this._fetch(value);
};
You can achieve your desired functionality in a very simple manner.
Add this to your DawaFetch class.
OnItemSelection=(address)=>{
this.setState({value: address})
}
Add this to your render Function
render = () =>
this.props.children({ ...this.state, handleChange: this.handleChange, OnItemSelection: this.OnItemSelection });
}
Then make these changes in your DawaFetch component
<DawaFetch>
{({ value, suggestions, handleChange, OnItemSelection }) => {
console.log(suggestions);
return (
<View>
<CustomInputs
type="text"
value={value}
onChangeText={handleChange}
/>
{suggestions.map((suggestion) => (
<TouchableOpacity onPress={()=> OnItemSelection(suggestion.adresse)}>
<NormalText key={suggestion.adresse.id}>{suggestion.tekst}</NormalText>
</TouchableOpacity>
))}
</View>
);
}}
</DawaFetch>
Edit:Here is Snack having solution
https://snack.expo.io/#waheed25/bad-raisins
my problem is quite simple but I'm new to react native dev. I'd like to save multiple elements with AsyncStorage (I'm using react-native-simple-store
a library that works like a wrapper but it's same logic) I want display all items for a key in a list , my code look like this:
constructor(props) {
super(props)
this.state = {
UserInput: "",
}
}
SaveValue = () => {
store.push('Favorites', this.state.UserInput)
Keyboard.dismiss()
};
FetchValue = () => {
store.get('Favorites').then((value) => {
this.setState({
favs: value
});
}).done();
};
Same thing with AsynStorage, it just update the item which is not my goal, I'd like to add a new one
SaveValue = () => {
AsyncStorage.setItem("Favorites", this.state.UserInput);
Keyboard.dismiss()
};
FetchValue = () => {
AsyncStorage.getItem("Favorites").then((value) => {
this.setState({
favs: value
});
}).done();
};
This part is my view where I try to display data, you can also see that I use a text input and two buttons one to save and the other to display an array of items stored
render() {
return (
<View>
<TextInput
onChangeText={(UserInput) => this.setState({UserInput})}
placeholder= "Type something"
value={this.state.UserInput} />
<TouchableOpacity
onPress={this.SaveValue}>
<Text>Save</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={this.FetchValue}>
<Text>Fetch</Text>
</TouchableOpacity>
<Text>{this.state.favs}</Text>
</View>
);
}
At this point I can see only one item, I tried to figure it out and saw that I have to use another method called push but when I changed save by push it throw me an error
Unhandled Promise Rejection : Existing value for key "Favorites" must be of type null or array, revived string.
Thanks!
it will work :)
renderFavorites = () => {
AsyncStorage.getItem("Favorites").then((favs) => {
favs.map((fav) => {
return (<Text> {fav} </Text>);
});
});
}
render() {
return (
<View>
<TextInput
onChangeText={(UserInput) => this.setState({UserInput})}
placeholder= "Type something"
value={this.state.UserInput} />
<TouchableOpacity
onPress={this.SaveValue}>
<Text>Save</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={this.FetchValue}>
<Text>Fetch</Text>
</TouchableOpacity>
{this.renderFavorites()}
</View>
);
}
Solution using JSON:
SaveValue = () => {
const newFavs = [...this.state.favs, this.state.UserInput];
this.setState({ favs: newFavs, UserInput: '' }, () => {
AsyncStorage.setItem("Favorites", JSON.stringify(this.state.favs));
Keyboard.dismiss()
});
};
FetchValue = () => {
AsyncStorage.getItem("Favorites").then((value) => {
this.setState({
favs: JSON.parse(value)
});
}).done();
};
I have the following React Native code that runs the press() method when a user taps an image. I want to get the itemIndex prop from the event object. I set a break point in the press method and added some expressions to the Watch. From the Watch I determined that the target (event origination) from the event is the Image which is correct. The itemIndex prop is also available. The element being processed is the currentTarget, the Watch sees it's a "RCTView" and I was expecting a TouchableOpacity, so maybe underneath TouchableOpacity is a View? The currentTarget itemIndex prop is undefined, why? How can I get the props from the currentTarget?
I want to do it this way to avoid creating addition methods for each rendered item.
FYI,
ref={(c) => this._input = c} will not work because it's being run in a loop.
onPress={(e) => this.press(e, i)} creates a new function which I'm trying to avoid.
Watch
target._currentElement.props.itemIndex: 2
target._currentElement.type.displayName: "RCTImageView"
currentTarget._currentElement.props.itemIndex: undefined
currentTarget._currentElement.type.displayName: "RCTView"
press: function(event){
var currentTarget = ReactNativeComponentTree.getInstanceFromNode(event.currentTarget);
var target = ReactNativeComponentTree.getInstanceFromNode(event.target);
var currentTargetIndex = currentTarget._currentElement.props.itemIndex;
var targetIndex = target._currentElement.props.itemIndex;
var url = this.state.data.items[currentTargetIndex].url;
Linking.openURL(url).catch(err => console.error('An error occurred', err));
},
render: function() {
return (
<ScrollView horizontal={true} showsHorizontalScrollIndicator={false} style={styles.galleryView}>
{
this.state.data.items.map((data, i) =>
<TouchableOpacity itemIndex={i} key={i} activeOpacity={0.5} onPress={this.press} >
<Image itemIndex={i} key={i} source={{uri:data.previewImageUri}} style={styles.galleryImage} />
</TouchableOpacity>
)
}
</ScrollView>
);
}
I actually came across this same issue recently, I found two different ways you could approach this. The easier way of doing it is altering your onPress to pass an index to your press function, this is the 2nd way of doing it:
press: function(event, index){
var url = this.state.data.items[index].url;
Linking.openURL(url).catch(err => console.error('An error occurred', err));
},
render: function() {
return (
<ScrollView
horizontal={true}
showsHorizontalScrollIndicator={false}
style={styles.galleryView}
>
{
this.state.data.items.map((data, i) =>
<Images data={data} key={i} index={i} press={this.press} />
)
}
</ScrollView>
);
}
const Images = (props) => {
const imageClicked = (e) => {
props.press(e, props.index);
}
return (
<TouchableOpacity activeOpacity={0.5} onPress={imageClicked} >
<Image source={{uri:props.data.previewImageUri}} style={styles.galleryImage} />
</TouchableOpacity>
)
}
You could make your event handler a curried function that accepts extra parameters.
//Curried function for onPress event handler
handleOnPress = (someId, someProp) => event => {
//USE someProp ABOVE TO ACCESS PASSED PROP, WHICH WOULD BE undefined IN THIS CASE
//Use event parameter above to access event object if you need
console.log(someProp)
this.setState({
touchedId: someId
})
}
Checkout the working snack below
https://snack.expo.io/#prashand/accessing-props-from-react-native-touch-event
Binding the needed information to a callback and assigning one to each child avoids recreating the callback on every render of children.
class Hello extends React.Component{
state = { names: this.props.names.map((name, i) => {
return Object.assign({
onClick: this._onClick.bind(this, i, this.props),
}, name)
}),
};
_onClick(ind, _props, e) {
alert('props:' + JSON.stringify(_props));
}
render() {
const { names } = this.state;
return (
<div>
{ names.map((name, i) => (
<div key={i}>Name: <input value={ name.first } onClick={ name.onClick } /></div>
))}
</div>
)}
}
ReactDOM.render(
<Hello names={[{first:'aaa'},{first:'bbb'},{first:'ccc'}]}/>,
document.getElementById('container')
);
JS Fiddle