Home > Net >  React Native isPressed changes style for all the elements in the loop. How to change only one elemen
React Native isPressed changes style for all the elements in the loop. How to change only one elemen

Time:09-09

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" },
                ]}

CodePudding user response:

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 ...

CodePudding user response:

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

Hey you can do something like this :

enter image description here

CodePudding user response:

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;
  • Related