Search code examples
javascriptreact-nativeonbluronfocustouchablehighlight

how to focus / blur event on button list react native


I'm trying to emulate focus/ blur event in react native with no success. I have two components, Home and Button. In home i render a list of buttons(category1, category2 and category3). Here is my code:

---HOME COMPONENT----

state = {
    categories: ['category1', 'category2', 'category3']
};

renderCategories() {
    return this.state.categories.map((category, index) => (
        <Button onPress={() => this.getCategories(category)} key={index}>
            {category}
        </Button>
    ));
}

render() {
    return (
        <View>
            <ScrollView horizontal showsHorizontalScrollIndicator={false} style={{marginBottom: 5}}>
                {this.renderCategories()}
            </ScrollView>
        </View>

    )
}

---BUTTON COMPONENT---

class Button extends Component {
    constructor(props) {
        super(props);
        this.state = { pressStatus: false };
    }

    _onHideUnderlay() {
        this.setState({ pressStatus: false });
        console.log('unpressed')
    }
    _onShowUnderlay() {
        this.setState({ pressStatus: true });
        console.log('pressed')
    }

    render () {

        const {buttonStyle, buttonPressedStyle, textStyle} = styles;
        return (
            <TouchableHighlight onPress={this.props.onPress}
                                underlayColor={'#fff000'}
                                activeOpacity={1}
                                style={[buttonStyle, this.state.pressStatus ? {backgroundColor: '#fff000'} : {backgroundColor: '#1D36FF'}]}
                                // onHideUnderlay={this._onHideUnderlay.bind(this)}
                                onShowUnderlay={this._onShowUnderlay.bind(this)}>
                <Text style={textStyle}>
                    {this.props.children}
                </Text>
            </TouchableHighlight>
        );
    }


}

const styles = {
    buttonStyle: {
        marginTop:10,
        paddingTop:15,
        paddingBottom:25,
        marginLeft:10,
        // marginRight:10,
        paddingLeft: 15,
        paddingRight: 15,
        backgroundColor:'rgba(99,99,99,0.99)',
        borderRadius:10,
        borderWidth: 1,
        borderColor: '#fff'
    },
    buttonPressedStyle: {
        marginTop:10,
        paddingTop:15,
        paddingBottom:25,
        marginLeft:10,
        // marginRight:10,
        paddingLeft: 15,
        paddingRight: 15,
        backgroundColor:'rgba(15,15,15,0.99)',
        borderRadius:10,
        borderWidth: 1,
        borderColor: '#fff'
    },
    textStyle: {
        color:'#fff',
        textAlign:'center',
        fontSize: 16
    },
};

This code works partially. When i click first button(category1) it changes the background color as expected, but when i click second button(category2) then the button category1 should take the initial style(lost focus).

Please help. Thanks


Solution

  • @Aramillo, You are facing this issue because you are using same property value pressStatus for all the three buttons.

    Do it in some different manner.

    Please try below code -

    in App.js

    import React, { Component } from "react";
    import { ScrollView, Text, View } from "react-native";
    import Button from "./Button";
    
    class App extends Component {
      constructor(props) {
        super(props);
        this.state = {
          pressedButton: null,
          categories: ["category1", "category2", "category3"]
        };
      }
    
      getCategories = (category, index) => {
        this.setState({ pressedButton: index });
      };
    
      renderCategories() {
        return this.state.categories.map((category, index) => (
          <Button
            onPress={() => this.getCategories(category, index)}
            buttonId={index}
            pressedButton={this.state.pressedButton}
            key={index}
          >
            <Text>{category}</Text>
          </Button>
        ));
      }
    
      render() {
        return (
          <View>
            <ScrollView
              horizontal
              showsHorizontalScrollIndicator={false}
              style={{ marginBottom: 5 }}
            >
              {this.renderCategories()}
            </ScrollView>
          </View>
        );
      }
    }
    
    export default App;
    

    In Button.js

    import React, { Component } from "react";
    import { TouchableHighlight, Text } from "react-native";
    
    class Button extends Component {
      constructor(props) {
        super(props);
        this.state = { pressStatus: false };
      }
    
      onHideUnderlay() {
        this.setState({ pressStatus: false });
        console.log("unpressed");
      }
      _onShowUnderlay() {
        this.setState({ pressStatus: true });
        console.log("pressed");
      }
    
      render() {
        const { buttonStyle, textStyle } = styles;
        return (
          <TouchableHighlight
            onPress={this.props.onPress}
            underlayColor={"#fff000"}
            activeOpacity={1}
            style={[
              buttonStyle,
              this.props.buttonId === this.props.pressedButton
                ? { backgroundColor: "#fff000" }
                : { backgroundColor: "#1D36FF" }
            ]}
            // onHideUnderlay={this._onHideUnderlay.bind(this)}
            onShowUnderlay={this._onShowUnderlay.bind(this)}
          >
            <Text style={textStyle}>{this.props.children}</Text>
          </TouchableHighlight>
        );
      }
    }
    
    export default Button;
    
    const styles = {
      buttonStyle: {
        marginTop: 10,
        paddingTop: 15,
        paddingBottom: 25,
        marginLeft: 10,
        // marginRight:10,
        paddingLeft: 15,
        paddingRight: 15,
        backgroundColor: "rgba(99,99,99,0.99)",
        borderRadius: 10,
        borderWidth: 1,
        borderColor: "#fff"
      },
      buttonPressedStyle: {
        marginTop: 10,
        paddingTop: 15,
        paddingBottom: 25,
        marginLeft: 10,
        // marginRight:10,
        paddingLeft: 15,
        paddingRight: 15,
        backgroundColor: "rgba(15,15,15,0.99)",
        borderRadius: 10,
        borderWidth: 1,
        borderColor: "#fff"
      },
      textStyle: {
        color: "#fff",
        textAlign: "center",
        fontSize: 16
      }
    };
    

    Working example here - https://codesandbox.io/s/empty-currying-cikw4