1

I'm a beginner in React Native and struggling in passing and executing functions as props from parent to child component. Here's the code:

MainMap

import React from 'react';
import { 
    TouchableWithoutFeedback,
    StyleSheet,
    View,
    Button,
    FlatList,
    Dimensions
} from 'react-native';

import PlaceInput from '../components/PlaceInput';

const INCREMENT = 1;
const HEIGHT = Dimensions.get('window').height
const WIDTH = Dimensions.get('window').width

class MainMap extends React.Component{
    constructor(props){
        super(props);
        this.state={
            numOfInput:[],
            counter: 0,
        }
        this.onAddSearch = this.onAddSearch.bind(this)
        this.onDeleteSearch = this.onDeleteSearch.bind(this)
    }

    onAddSearch(){
        this.setState((state) => ({
            counter: state.counter + INCREMENT,
            numOfInput: [...state.numOfInput, state.counter]
        }))
    }

    onDeleteSearch(inputId){
        const items = this.state.numOfInput.filter(item => item.id !== inputId)
        this.setState({
            numOfInput: items
        })
    }
    render(){
            return(
                <TouchableWithoutFeedback onPress={this.hideKeyboard} >
                    <View style={styles.container} >

                        <Button title='Add a location' onPress={this.onAddSearch} />
                        <View style={{height: HEIGHT/2 }}>
                            <FlatList
                                data={this.state.numOfInput}
                                keyExtractor={(item, index) => item.id}
                                renderItem={itemData => {
                                    return(
                                        <PlaceInput
                                            key={itemData.item.id}
                                            // id={itemData.item.id}
                                            onDelete={this.onDeleteSearch}
                                            showDirectionOnMap={this.showDirectionOnMap}
                                            userLatitude={userLatitude}
                                            userLongitude={userLongitude}
                                        />
                                    )
                                }}
                            />
                        </View>
                    </View>
                </TouchableWithoutFeedback>
            )
        }
    }

export default MainMap;

const styles = StyleSheet.create({
    container:{
        flex: 1
    },
})

Here's the PlaceInput component

class PlaceInput extends React.Component{
    constructor(props){
        super(props);
        ... // These lines have no relation to what I'm asking so don't mind them
  }
    ...
    render(){
        return(
            <View style={styles.buttonContainer} >
                    <View style={{flex: 1, alignItems: 'center'}}>
                        <Text style={{fontSize: 8}}>{'\u25A0'}</Text>
                    </View>
                    <View style={{flex: 4}}>
                        <TextInput 
                            autoCorrect={false}
                            autoCapitalize='none'
                            style={styles.inputStyle}
                            placeholder='Search your places'
                            onChangeText={(input) => {
                                this.setState({destinationInput: input});
                                this.getPlacesDebounced(input);
                            }}
                            value={this.state.destinationInput}
                        />
                        {/* {predictions} */}
                    </View>
                    <View style={styles.rightCol}>
                        <TouchableOpacity onPress={this.props.onDelete.bind(this, this.props.id)}>
                            <Ionicons name='md-car' size={25} style={{alignSelf: 'center'}} />
                        </TouchableOpacity>
                    </View>
                </View>
        )
  }
}

What I'm trying to do:

  • Define a function to execute in MainMap.js (in FlatList --> PlaceInput for specific) , which is to delete an search bar( the whole PlaceInput in the FlatList) every time I click the right symbol of that search bar. The function is onDeleteSearch

  • The right symbol is styled in a TouachableOpacity as you can see in the PlaceInput.js component. I put it in the last View pair

  • However, When I click, the screen deletes all the search bars, not the one I click. Is it the problem of the id of the component PlaceInput ? Or with the way I call the props?...

Please help me !

4 Answers 4

2
<TouchableOpacity onPress={this.props.onDelete.bind(this, this.props.id)}>
     <Ionicons name='md-car' size={25} style={{alignSelf: 'center'}} />
</TouchableOpacity>

Don't bind, just call this.props.onDelete(this.props.id);

Sign up to request clarification or add additional context in comments.

2 Comments

Really appreciate your comment @Kailash Vele . But it still doesn't change. The screen just deletes all the search bars when I click 1 of them, not the one expected
You are refereing to this.props.id for unique id of the list item but your id prop is commented in the example shared above.
1

In MainMap, try this:

<PlaceInput
  key={itemData.item.id}
  // id={itemData.item.id}
  onDelete={() => this.onDeleteSearch(itemData.item.id)} // here
  showDirectionOnMap={this.showDirectionOnMap}
  userLatitude={userLatitude}
  userLongitude={userLongitude}
/>

1 Comment

Really appreciate your comment @vaz . But it still doesn't change. The screen just deletes all the search bars when I click 1 of them, not the one expected
1

Assuming the function:

onPressed(optionalArgument = false) {
   // do something
}

You can pass a function to onPress if it does not require any arguments, i.e

onPress={onPressed} // - would work if no arguments required.
onPress={onPressed(argument)} // - will get fired on component render
onPress={()=> onPressed(argument)} // - will work as expected on button press
onPress={()=> { // - will work as expected on button press
    // Multiple lines of code
    onPressed(argument);
    anotherFunction();
    }
};

In your MainMap you are doing everything correctly, just uncomment the

// id={itemdata.item.id}

In PlaceInput, just one small change:

<TouchableOpacity onPress={() => this.props.onDelete(this.props.id)}>
   <Ionicons name='md-car' size={25} style={{alignSelf: 'center'}} />
</TouchableOpacity>

If you don't add ()=> to your onPress, the function gets called immediately, that's why you see such behaviour.

2 Comments

Really appreciate your comment @Dmitri Borohhov . But it still doesn't change. The screen just deletes all the search bars when I click 1 of them, not the one expected
This is something you need to debug - you are probably passing some wrong parameters to the FlatList renderItem property. Just set up some breakpoints in the debugger and see what happens when you press the button.
1

Your numOfInput is just a list of numbers, so instead of using item.id-s use item directly.

Here:

const items = this.state.numOfInput.filter(item => item !== inputId)

And here

<PlaceInput
  key={itemData.item}
  // id={itemData.item}
  ...
/>

2 Comments

Thanks. I'll check it. But do I need to change the way I call the function onDelete in PlaceInput ?
You don't need to bind there. bind specifies what you mean by this inside the function. You want this to mean the parent component, even when the child is calling the function. Kailash already pointed that out.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.