skip to Main Content

The below code changes style to itemStyles.listItemPressed to all the elements in the Item loop. I need to have only one element change the style on pressing the container. Down below i have my second way of tryng to do that. But in the second try the pressed styles apply and stay there after i let go of my finger. I need the style to change back to default after i dont press on the screen.

const [isPressed, setIsPressed] = React.useState(false);

const [selectBtn, setSelectBtn] = React.useState(null);
    
function onPressIn() {
    setIsPressed(true);
}

function onPressOut() {
    setIsPressed(false);
}

 <View>
                    {options.map((option) => (
                        <Pressable
                            onPress={onPress}
                            onPressIn={onPressIn}
                            onPressOut={onPressOut}
                            style={[
                                itemStyles.listItem,
                                isPressed && itemStyles.listItemPressed,
                            ]}
                        >
                            <Item
                                checked={option.value === value}
                                key={option.value}
                                label={option.label}
                                disabled={disabled}
                                onPress={() => onChange(option.value)}
                            />
                        </Pressable>
                    ))}
                </View>

Second try

       return (
            <View style={style}>
                <View>
                    {options.map((option, index) => (
                        <Pressable
                            style={[
                                itemStyles.listItem,
                                { backgroundColor: selectBtn === index ? 'red' : 'gray' },
                            ]}
                            onPressIn={() => {
                                setSelectBtn(index);
                            }}
                            onPressOut={null}
                            onPress={onPress}
                        >
                            <Item
                                checked={option.value === value}
                                key={option.value}
                                label={option.label}
                                disabled={disabled}
                                onPress={() => onChange(option.value)}
                            />
                        </Pressable>
                    ))}
                </View>
            </View>
        );
    }

My options array

 options={[
                    { label: "Value", value: "value" },
                    { label: "Value", value: "value2" },
                    { label: "Value", value: "value3" },
                    { label: "Value", value: "value4" },
                    { label: "Value", value: "value5" },
                ]}

3

Answers


  1. Im assuming you know which elements index you want to change style when onPressed

    Hey you can do something like this :
    UPDATED LINK
    https://snack.expo.dev/uRUZuvibJ check out this

    import {React,useState} from 'react';
    import { Text, View, StyleSheet,Pressable } from 'react-native';
    import Constants from 'expo-constants';
    
    // You can import from local files
    import AssetExample from './components/AssetExample';
    
    // or any pure javascript modules available in npm
    import { Card } from 'react-native-paper';
    
    const data = ["hey","india","anime","manga","arsenal"]
    
    export default function App() {
    
      const [selected,setSelect] = useState([])
    
      const handlePress = (index) => {
        let existingState = [...selected];
        if(existingState.includes(index)){
          existingState = existingState.filter(item => item !== index)
          setSelect(existingState)
        } else {
          existingState.push(index)
          setSelect(existingState)
        }
      }
    
      const renderItem = (item,index) => {
        const isSelected = selected.includes(index)
        return(
          <Pressable style={isSelected?styles.press:styles.unpress}  onPressIn={() => handlePress(index)} onPressOut={() => handlePress(index)} >
          <Text>{item}</Text>
          </Pressable>
       )
      }
    
      return (
        <View style={styles.container}>
         {data.map((item,index) => {
           return renderItem(item,index)
         })}
        </View>
      );
    }
    
    const styles = StyleSheet.create({
      container: {
        flex: 1,
        justifyContent: 'center',
        paddingTop: Constants.statusBarHeight,
        backgroundColor: '#ecf0f1',
        padding: 8,
      },
      paragraph: {
        margin: 24,
        fontSize: 18,
        fontWeight: 'bold',
        textAlign: 'center',
      },
       unpress:{
         height:40,
         width:'100%',
         backgroundColor:'red',
         flex:1
       },
       press:{
         height:40,
         width:'100%',
         backgroundColor:'green',
         flex:1
       }
    });

    Hope it helps 🙂

    enter image description here

    Login or Signup to reply.
  2. You could use some other logic for this.

    But what have done with a similar problem where. I had to change color of an element in a loop on hover.

    I made a separate component for the item inside the loop on which i had to apply changes.

    Then in that separate component i had a state like isPressed. Now what it does is that each element in the loop have its own personal state for isPressed so i can check it for each individual item without affecting other elements in the loop.

    For Example:
    App.js

    function App(){
      return <div>
      {someArray.map((item)=><Component ...props... />)}
    </div>
    }
    

    Component.js

    function Component(){
    const [isPressed, setIsPressed] = useState(false);
    return 
     <someTag onClick={()=>setIsPressed(true)}  style={{color:isPressed ? 'blue' : 'red'}} >....</somTag>
    
    }
    

    You can also handle function on click in App.js then you have to pass function as a prop to Component and onClick in Component it will call props.sentFunction …

    Login or Signup to reply.
  3. I’d approach this problem that have elements with multiple properties and states by using useReducer: https://snack.expo.dev/@zvona/state-of-multiple

    Here’s the full code from the snack of handling state through useReducer:

    import { useState, useReducer } from 'react';
    import { Text, Pressable, View, StyleSheet } from 'react-native';
    
    const options = [{ value: 'first' }, { value: 'second' }, { value: 'third' }];
    const initialState = { ...options };
    
    const App = () => {
      const selectedReducer = (state, { type, index }) => {
        const { selected, pressed } = state[index];
        const newState = { ...state };
    
        switch (type) {
          case 'pressIn':
            newState[index].pressed = true;
            break;
          case 'pressOut':
            newState[index].pressed = false;
            break;
          case 'press':
            newState[index].selected = !selected;
            break;
          default:
            console.warn('invalid type');
            break;
        }
    
        return newState;
      };
    
      const [state, dispatch] = useReducer(selectedReducer, initialState);
    
      const getStyling = (index) => [
        styles.pressableStyle,
        state[index].selected && styles.listItemSelected,
        state[index].pressed && styles.listItemPressed,
      ];
    
      return (
        <View style={styles.container}>
          <View>
            {options.map((option, index) => (
              <Pressable
                onPressIn={() => dispatch({ type: 'pressIn', index })}
                onPressOut={() => dispatch({ type: 'pressOut', index })}
                onPress={() => dispatch({ type: 'press', index })}
                style={getStyling(index)}>
                <Text>{option.value}</Text>
              </Pressable>
            ))}
          </View>{' '}
        </View>
      );
    };
    
    const styles = StyleSheet.create({
      container: {
        flex: 1,
        justifyContent: 'center',
        backgroundColor: '#ecf0f1',
        padding: 8,
      },
    
      pressableStyle: {
        backgroundColor: 'white',
        padding: 10,
        marginBottom: 10,
        borderColor: 'black',
        borderWidth: 1,
      },
    
      listItemPressed: {
        backgroundColor: 'blue',
      },
    
      listItemSelected: {
        backgroundColor: 'green',
      },
    });
    
    export default App;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search