How can I delete a single item from a list in React Native? - react-native

So that's what my render list looks like:
renderEvent(){
return this.props.eventList.map(listedEvent=>
<CardSection key={listedEvent._id}>
<EventListItem>
{listedEvent.eventName}
</EventListItem>
<DeleteButton
onClick={this.deleteEvent(listedEvent._id)}
key={listedEvent._id}
/>
</CardSection>
);
}
and here the rendering of the whole list
render(){
if (this.props.eventList !== undefined) {
return(
<Card>
{this.renderEvent()}
</Card>
)
}else{
return(
<View>
<Spinner/>
</View>
)
}
}
}
So far so good, the list and the delete button appear correctly, yet when I try to delete one line, it addresses all. I created my event handler which for now, only logs the passed id.
deleteEvent(eventID){
console.log(eventID)
}
Yet when called, it logs all the _ids on the list. What am I doing wrong? How can I make sure I'm passing one single id of the list item I'm clicking on?
Thank you!

Problem is that you are rather than passing a deleteEvent function to onClick prop you are executing it. This causes to deleteEvent fire for each item while rendering.
You can sort this out by changing this,
onPress={this.deleteEvent(listedEvent._id)}
to this
onPress={() => this.deleteEvent(listedEvent._id)}
This will also assure that deleteEvent is bind with this.

Related

Can't get TextInput value in react native

Hi friends I hope you are doing very well ^^
I am struggling to get a TextInput value when a user enters it in a simple basic form I've created, here is the field :
<TextInput placeholder='latitude' name='lat'/>
<Button style={styles.signIn}
title="Show my entered text"
onPress={() => {
alert(this.state.lat)}}
/>
I tried so many methods to get the value of this field but unfortunately none works.. I am new to react native so I really don't know how can this be done properly (is there any variable I need to define) because in javascript I used to get it only by the GetElementById quite simple right XD
I tried creating a variable exactly bellow the imports like this :
value={this.state.lat}
So I can get the above textInput actual value entered by the user but it isn't working at all and my alert function is not returning anything (I actually don't know if alert() is a react native integrated function or I need to define it from scratch :/), please help I am really lost I tried many solutions on the web but nothing resolves my problem. Thanks in advance
Try this sample code
class Example extends React.Component {
state = { lat: "" };
render() {
return (
<View>
<TextInput
placeholder="latitude"
name="lat"
value={this.state.lat}
onChangeText={(text) => this.setState({ lat: text })}
/>
<Button
style={styles.signIn}
title="Show my entered text"
onPress={() => {
alert(this.state.lat);
}}
/>
</View>
);
}
}

React Native - FlatList not invoking renderItem's lifecycle methods on refresh

I want to make a fetch request inside renderItem's componentDidMount method every time the list is refreshed, but the FlatList calls the lifecycle methods only once.
The list
<FlatList data={this.state.dataSource}
renderItem={({item}) => <ListItem imageHref={item.imageHref} />}
keyExtractor={(item, index) => index.toString()}
refreshing={this.state.refreshing}
onRefresh={/* Fetching data from JSON and updating dataSource[] */} />
Inside ListItem component:
render() {
return <Image source={this.state.imageSource} />
}
componentDidMount() {
fetch(this.props.imageHref)
.then(response => {
if(response.status !== 200)
this.setState({imageSource: require('../assets/default-image.png')
else
this.setState({imageSource: {uri: this.props.imageHref}});
}
});
}
I tried calling fetch inside render method but that didn't work either.
I basically want the imageSource to update every time the list is refreshed. Please help.
Because of that ListItem was not change. You have to fetch new icon in onRefresh and pass it into ListItem then all data will be changed when ListView will refresh... if you want to do it inside ListItem you need some interaction with that specific item, for example, some button and if user press it fetch and change icon
i didn't know when your list refreshed , but you can try this this.forceUpdate() you can learn more here force component to re render

React - native StackNavigator refresh previous component after hitting back button

I'm stuck for weeks on this problem that I can't solve. I have been through a lot of different solution and none of them is working..
Let-s say I have component A and component B
Component A : contains a flatlist, when click on one item leads me to component B.
Component B: contains details of component A items, when clicking on a button update data, data that component A is using in state current, which make the clicked items turn to orange. I would like when hitting back button to update those data in component A and actually have the clicked items in orange, right now nothing is happening..
Component A :
async interventionList(){
const planningList = await getInterventionList(this.state.userToken, '2019-02-27', '2019-02-27');
this.setState({list: planningList});
}
renderItem = ({ item }) => (
<View>
<TouchableHighlight onPress={
() => this.props.navigation.navigate('InterventionStart', { getIntervention: () => this.interventionsList() })}>
<View style={[styles.block, this.state.current !== null && this.state.current.remoteInterventionId === item.num ? styles.began : styles.notbegan]}>
<Text> {SomeData} <Text>
</View>
</View>
</TouchableHighlight>
</View>
)
Component B :
componentWillUnmount() {
this.props.navigation.state.params.getIntervention();
}
But nothing happens. I tried to console log, to see if those functions where called after clickin on back button and they are... So I don't understand what I am doing wrong or is it not the way to do this at all ?
You can use willFocus method of react-navigation
in your componentDidMount or in your constructor
this.willFocus = this.props.navigation.addListener('willFocus', () => {
this.interventionList();
});
It will call your interventionList method whenever your component is about to be focused. Make sure you remove the listener on your componentWillUnmount
this.willFocus.remove();
For reference
https://reactnavigation.org/docs/en/navigation-events.html

ComponentWillMount only trigger for first time?

MainComponent:
<Tabs
initialPage={this.props.day}
tabBarUnderlineStyle={{ backgroundColor: '#5AF158' }}
renderTabBar={() => <ScrollableTab />}>
{this.renderTabHeader()}
</Tabs>
renderTabHeader() {
return (
this.props.dateArray.map((date, i) =>
<Tab
key={i}
heading={date.format('DD/MM')}
tabStyle={styles.tabStyling}
activeTabStyle={styles.activeTabStyle}
textStyle={styles.tabTextStyle}
activeTextStyle={styles.activeTabTextStyle}
>
<View style={{ backgroundColor: '#EEEEEE', flex: 1 }}>
<Content contentDate={date.format('YYYY-MM-DD')} />
</View>
</Tab>
)
);
}
Content Component:
class Content extends Component {
componentWillMount() {
console.log('Component Will Mount() ?');
this.props.loadTransactionByDate({ date: this.props.contentDate });
}
render() {
return (
<View><Text>{this.props.contentDate}</Text></View>
);
}
Basically, in MainComponent there is a collection of tabs. I've noticed something rather weird which Content will be mounted on the first time their tab being click or active?
Meaning for the first time, we can click on Tab index 2 and seeing the console log in componentWillMount, then we switch to another tab and if coming back to Tab index 2 again, componentWillMount will not be triggered anymore?
First I would like to point out you should not use componentWillMount life cycle method since it has been deprecated on last minor update of React 16.3
Heres list of deprecated life cycle methods,
(componentWillMount, componentWillReceiveProps, and componentWillUpdate). You can read more about deprecated life cycle methods here.
Secondary in your example life cycle works as expected. componentWillMount triggers only once since your component will be initial rendered/mounted only one time and that's how React works.
I would work this out with following method.
Add getDerivedStateFromProps life cycle to Content component, which will trigger when component receives new props and as well on initial mount.
static getDerivedStateFromProps(nextProps, prevState) {
console.log('will log on props change');
if( nextProps.contentDate !== prevState.contentDate ) {
return { contentDate: nextProps.contentDate };
// Notice we return plain object here to update state
}
return null;
// return null when changes are not needed
}
This example checks that contentDate has changed and if so pushes it into component -state. And on render method you get it by this.state.contentDate.
render() {
return (
<View><Text>{this.state.contentDate}</Text></View>
);
}
You could achieve similar behaviour with implementing this in componentDidUpdate but then you have much bigger risk to end up with infinite loops and much worse performance. But it's possible just have strong checks that data you have expected has really changed as you would expect. Then you can do setState and component re-renders.

react-native-keyboard-spacer how to use onToggle

I'm using react-native-keyboard-spacer.
I want to implement the feature of automatically popping up the keyboard.
The documentation says onToggle method is called when when keyboard toggles. Two parameters passed through, keyboardState (boolean, true if keyboard shown) and keyboardSpace (height occupied by keyboard)
Can anyone show me an example of how to accomplish this?
onToggle() is only called after the keyboard is toggled. To achieve the functionality you desire, just use the built in method in TextInput to focus an input when a component finishes mounting:
componentDidMount() {
this._myTextInput.focus();
}
render() {
return (
<TextInput
style={{height: 40}}
ref={component => this._myTextInput = component}
/>
);
}
onToggle get's called when the keyboard is either shown or hidden. If you want to pop up the keyboard without the user clicking anything, then you would need to focus() on a textInput.
handleOnToggle(keyboardState, keyboardSpace) {
// Do whatever you want with keyboardState
}
render() {
return <View>
<KeyboardSpacer onToggle={this.handleOnToggle} />
</View>
}