1

I am trying to change the style of individual TouchableOpacity components that have been returned from a map function.

Here is the component:

Example = ({ props }) => {  
    return (
        <View>
            {props.listExample.map(({ id }) => {
                return (
                    <React.Fragment key={id}>
                        <TouchableOpacity
                            style={styles.button}
                            onPress={() => console.log(id)}>
                            <Image source={require('example.jpg')} />
                        </TouchableOpacity>
                    </React.Fragment>
                );
            })}
        </View>
    );
};

Let TouchableOpacity = TO.

The map function returns about 30 TOs with unique IDs. When I click the TOs, I can see their unique ID in the console log. I want to know how I can modify the style of an individual TO.

Here is my render function which uses the functional component Example.

render() {
    return (
        <View style={styles.body}>
            <ScrollView>
                <View style={styles.column}>
                    <this.Example props={{ listExample: this.getList() }} />
                </View>
            </ScrollView>
        </View>
    );
}

What I have tried:

referencing this stackoverflow post, I tried to create a function which changed the style of the TO when it is clicked. But the result of this changed all the TOs in the UI since of the way it is mapped. I tried something like the following.

Example = ({ props }) => {  
    return (
        <View>
            {props.listExample.map(({ id }) => {
                let buttonStyle = this.state.pressed ? styles.button : styles.buttonClicked
                return (
                    <React.Fragment key={id}>
                        <TouchableOpacity
                            style={buttonStyle}
                            onPress={() => console.log(id)}>
                            <Image source={require('example.jpg')} />
                        </TouchableOpacity>
                    </React.Fragment>
                );
            })}
        </View>
    );
};

But as previously stated, this changed all of the Touchable Opacitys. Is there a way to only change one?

Thanks

Edit - to show entire class

class Page extends Component {

    constructor(props) {
        super(props)
    }

    MyButton = ({ onButtonPressed = () => {} }) => {
        const [isPressed, setIsPressed] = useState(false);
        const onPressed = () => {
          setIsPressed(!isPressed);
          onButtonPressed();
       }
       return (<TouchableOpacity style={isPressed ? styles.pressedButton: styles.button}
                   onPress={onPressed}>
                   <Image source={require('example.jpg')} />
                </TouchableOpacity>
       );
    }

    Example = ({ props }) => {
        return (
            <View>
                {props.listExample.map(({ id }) => {
                    return (
                        <MyButton key={id}/>
                    );
                })}
            </View>
        );
    };

    render() {
        return (
            <View style={styles.body}>
                <ScrollView>
                    <View style={styles.column}>
                        <this.Example props={{ listExample: this.getList()}} />
                    </View>
                </ScrollView>
            </View>
        );
    }

}
ghDev
  • 170
  • 1
  • 12
  • You can assign an id if you want to simply style it in the css `id={id}`, or you can access the target of the click in the onClick function via the implicitly passed `event`, or you can update state onClick and conditionally style the relevant element on rerender. – pilchard Oct 31 '20 at 21:31
  • If I create the TouchableOpacity like this: ```` then how would I modify the style for just that TouchableOpacity? I see that it would have a unique ID I am just not sure how to access that in styling. – ghDev Oct 31 '20 at 22:41

1 Answers1

1

It is easier to separate the component inside map to a separate component and then handle style changes on press there

const MyButton = ({ onButtonPressed = () => {} }) => {
    const [isPressed, setIsPressed] = useState(false);
    const onPressed = () => {
      setIsPressed(!isPressed);
      onButtonPressed();
   }
   return (<TouchableOpacity style={isPressed ? styles.pressedButton: styles.button}
               onPress={onPressed}>
               <Image source={require('example.jpg')} />
            </TouchableOpacity>
   )
}

so you can use in the map like this

Example = ({ props }) => {  
    return (
        <View>
            {props.listExample.map(({ id }) => {
                return (
                    <MyButton key={id} />
                );
            })}
        </View>
    );
};
duc mai
  • 1,412
  • 2
  • 10
  • 17
  • So I would embed this component (MyButton) inside the map where I currently have the other TouchableOpacity? This seems like a good solution and I understand how it can solve my problem, but I cannot seem to figure out how to embed it into the map function. Would it be something like `` `` ? – ghDev Oct 31 '20 at 22:00
  • Thanks for the update and yes this is what I tried. But I have an issue. If I define it as you have said ``const MyButton``, it shows unexpected token. I think this is because I cannot define something like this inside a JavaScript class. However, if I remove the ``const``, it cannot find variable ``MyButton``. I have also tried `` `` and it said it was undefined. My apologies if this is trivial, I am quite new to RN and JS – ghDev Oct 31 '20 at 22:19
  • Can you show me your complete code that you have tried so far? – duc mai Oct 31 '20 at 22:22
  • All of my code is inside a class like: ``class Ex extends component { ... }``. So how am I to define this const MyButton? I probably should have stated this more clearly in the original post. – ghDev Oct 31 '20 at 22:22
  • define the MyButton completely outside of Example, they are equally same level – duc mai Oct 31 '20 at 22:23
  • I have updated the original post to show my code. I omitted some parts like imports and some helper functions which should not be a factor here. You can see I just have ``MyButton = ...`` not ``const MyButton``. It is defined outside of ``Example``. – ghDev Oct 31 '20 at 22:29
  • better to move out Example and MyButton the same level as PAge and use Example without this. – duc mai Oct 31 '20 at 22:36
  • I moved MyButton outside of the class Page and imported useState and it is now working. Thanks for following up with me. – ghDev Oct 31 '20 at 22:48