简体   繁体   中英

How to call a child method from the parent in React Native?

When a click event is fired within my parent component I need to call the method closeMenu() from the SearchBar child component. I have tried a couple of different ways to do that but none of them are working. Does anyone know how to do this?

class Products extends Component {

constructor(props) {
    super(props);

    this.state = { closeMenu: false};

    this.hideSearchBar = this.hideSearchBar.bind(this);
}

hideSearchBar(e) {
    console.log('e: ', React.Children)
    this.setState({closeMenu: true});
    this.refs.SearchBar.closeMenu();
    this.setState({closeMenu: false});        
}

componentWillMount() {
    this.props.dispatch(getProductList());
}

render() {
    const {isLoading, products} = this.props.products;

    if (isLoading) {
        return <Loader isVisible={true}/>;
    }

    return (
        <TouchableWithoutFeedback onPress={(e) => this.hideSearchBar(e)} style={{zIndex: 0}}>
            <View style={styles.wrapper}>
                <Header/>
                <View style={styles.bodyWrapper}>
                    <ScrollView style={styles.scrollView}>
                        <ProductsContainer data={{productsList: { results: products }}}/>
                    </ScrollView>
                    <SearchBar ref="SearchBar" style={styles.searchBar} />
                </View>
                <Footer/>
            </View>
        </TouchableWithoutFeedback>
    );
}

}

I also tried calling closeMenu() without refs:

hideSearchBar(e) {
    this.setState({closeMenu: true});
    this.SearchBar.closeMenu();
}

Here is the SearchBar component:

class SearchBar extends Component {
constructor(props) {
    super(props);
}

componentDidMount() {
    this.suggestions = [];
}

componentWillUpdate(nextProps, nextState) {
    console.log("COMPONENT WILL UPDATE");
    console.log(nextProps);
    console.log(nextState);
}

suggestionClick = (value) => {

}

getSuggestionText = (suggestion) => {

}

onChangeText = (value) => {
    this.selectedSuggestion = false
    this.props.dispatch(handleSearchItemText(value));
    console.log(this.props.products.searchResults);
}

onFocus() {
    const {height} = Dimensions.get('window');
    this.setState({
        contentOffset: {
            x: 0,
            y: height * 1 / 3
        }
    });
}

onBlur() {
    this.setState({
        contentOffset: {x: 0, y: 0}
    });
}

closeMenu = () => {
    this.props.products.searchResults = {};
}

componentWillReceiveProps() {
    if (!this.props.closeMenu) {
        this.props.closeMenu = false;
    }
}

renderSearches = () => {
    this.suggestions = this.props.products.searchResults;
    const suggestionTexts = Object.keys(this.props.products.searchResults || {})

    console.log(suggestionTexts);
    if (!suggestionTexts.length) {
        return null
    }
    // for android absolute element: https://github.com/facebook/react-native/issues/16951
    // https://gist.github.com/tioback/6af21db0685cd3b1de28b84981f31cca#file-input-with-suggestions-L54
    return (
        <View
            ref="suggestionsWrapper"
            style={autoStyles.suggestionsWrapper}
        >
            {
                this.suggestions.map((text, index) => (
                    <TouchableHighlight
                        key={index}
                        suggestionText={text}
                        activeOpacity={0.6}
                        style={autoStyles.suggestion}
                        onPress={this.suggestionClick(this.suggestions[text])}
                        underlayColor='white'
                    >
                        <Text style={autoStyles.suggestionText}>
                            {text}
                        </Text>
                    </TouchableHighlight>
                ))
            }
        </View>
    )
}

render() {
    const myIcon = (<Icon name="search" size={30} style={styles.searchIcon}/>);
    const slidersIcon = (<Icon name="sliders" size={30} style={styles.slidersIcon}/>);

    return (
        <TouchableWithoutFeedback style={{zIndex: 0}}>
            <View style={[styles.searchBar, this.props.style]}>
                <View style={styles.searchContainer}>
                    <View>
                        {slidersIcon}
                    </View>
                    <View style={styles.search}>
                        <View style={styles.searchSection}>
                            {myIcon}
                            <TextInput
                                style={styles.input}
                                placeholder="Search"
                                placeholderTextColor="rgba(0,0,0,0.7)"
                                onChangeText={(searchString) => {
                                    this.setState({searchString})
                                }}
                                underlineColorAndroid="transparent"
                                editable={true}
                                autoCorrect={false}
                                autoFocus={false}
                                autoCaptialize={'none'}
                                autoCorrect={false}
                                onChangeText={this.onChangeText}
                                enablesReturnKeyAutomatically={true}
                                onFocus={() => this.onFocus()}
                                onBlur={() => this.onBlur()}
                            />
                        </View>
                    </View>
                </View>
                {this.renderSearches()}
            </View>
        </TouchableWithoutFeedback>
    );
}

}

There are some issues which you should avoid:

Never mutate props : this.props.something = {} is an anti-pattern. Think about props as data that your component does not own and which are not mutable. If they change then only because the parent passed new props.

Also you have multiple handlers in your SeachBar that are not bound to this but use this . It will not work. Use arrow functions if you want to use this or bind them in the constructor .

You should overthink the architecture of your app. Maybe it is a good idea to split the search bar and the result list into two separate components. When the user types something to search for update your redux store and display the results in a separate component that you only render if there are search results.

I'm affraid it would exceed the length of a stackoverflow answer to solve all these issues. Maybe you should go back to the basics first and do the really good redux tutorial.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM