Home > Software engineering >  Dynamically change styling of multiple Text components based on content?
Dynamically change styling of multiple Text components based on content?

Time:09-08

I am trying to figure out a way to change the styling of multiple words each wrapped in a Text component in React Native, using an onPress event on each word.

I know how to do this in vanilla Javascript by running .split(" ") on a string to separate the words, and then mapping through them and wrapping them all in HTML elements like span tags with the word (in lowercase) as the class name and adding an onclick event that passes in the word .toLowerCase() as an argument to a function, which adds the word to an array of highlighted words, and then toggles adding or removing a class which will result in changing the styling of each instance of that word in a page.

The function would be something like this:

function exampleFunction(theWord) {

  let temp = document.getElementsByClassName(theWord)

  for (i = 0; i < temp.length; i  ) {
    if (temp[i].classList.contains("highlighted")) {
      if (i === 0) {
        let filteredArray = highlightedWords.filter((e) => e !== theWord)

        highlightedWords = filteredArray
      }

      temp[i].classList.remove("highlighted")
    } else {
      if (i === 0) {
        highlightedWords.push(theWord)
      }

      temp[i].classList.add("highlighted")
    }
  }
}

But the problem is that React Native doesn't seem to use classes. And I am very new to React Native. So I am lost as to how to approach this issue.

Any help is greatly appreciated.

CodePudding user response:

React uses a declarative instead of an imperative API as used in the DOM. Therefore you should declare state which is the index of currently highlighted word (you can use a negative value to indicate that no word is highlighted). Then add the class highlighted only when the index of the word and the index in your state match. If one clicks on the same value again set the highlighted to a negative value again. React will automatically re-re-render whenever you update the state using setHighlighted().

const Sentence = ({ words }) => {
  const [highlighted, setHighlighted] = React.useState(-1);
  
  return (
    <React.Fragment>
      {words.map((word, index) => (
        <p key={word} 
           onClick={() => setHighlighted(highlighted === index ? -1: index)} 
           className={index === highlighted && "highlighted"}
           >
           {word}
        </p>
      ))}
    </React.Fragment>
  );
};

ReactDOM.render(<Sentence words={["some ", "random ", "words."]}/>, document.getElementById('root'));
.highlighted {
  color: blue;
  background: red;
}
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<div id="root"></div>

CodePudding user response:

For react native , umm you cant do like that.

https://snack.expo.dev/ug8zEbrWZ

Please check working example above, and also do check out code here

import * as React from 'react';
import { Text, View, StyleSheet } 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';

function getRandomColor() {
  var letters = '0123456789ABCDEF';
  var color = '#';
  for (var i = 0; i < 6; i  ) {
    color  = letters[Math.floor(Math.random() * 16)];
  }
  return color;
}

export default function App() {

  const [fC,setFc] = React.useState(getRandomColor())
  const [sC,setSc] = React.useState(getRandomColor())
  const [tC,setTc] = React.useState(getRandomColor())
  const [zC,setZc] = React.useState(getRandomColor())

  return (
    <View style={styles.container}>
    <View style={{flexDirection:'row'}}>
      <Text 
      onPress={() => setFc(getRandomColor())}
      style={[styles.eachStyle,{
        color:fC
      }]} >hey</Text>
      <Text
       onPress={() => setSc(getRandomColor())}
        style={[styles.eachStyle,{
        color:sC
      }]}>this</Text>
      <Text 
       onPress={() => setTc(getRandomColor())}
       style={[styles.eachStyle,{
        color:tC
      }]}>is</Text>
      <Text 
       onPress={() => setZc(getRandomColor())}
       style={[styles.eachStyle,{
        color:zC
      }]}>great</Text>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({

  eachStyle:{
    marginHorizontal:3
  },

  container: {
    flex: 1,
    justifyContent: 'center',
    paddingTop: Constants.statusBarHeight,
    backgroundColor: '#ecf0f1',
    padding: 8,
  },
  paragraph: {
    margin: 24,
    fontSize: 18,
    fontWeight: 'bold',
    textAlign: 'center',
  },
});

  • Related