This sounds like a good use case for memoization. If you want to prevent rendering of the list and its elements, unless styles change, you need to apply this in two places, the <View/> wrapper containing el and the entire list itself. Below is how I would apply it.
import React, { useState, memo, useEffect } from "react";
import { Text, View, StyleSheet } from "react-native";
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
blackText: {
color: "black",
},
redText: {
color: "red",
},
blueText: {
color: "blue",
},
});
const stylesAreEqual = (prevProps, nextProps) => {
//we only compare styles since we assume el prop wont change
return (
prevProps.redText === nextProps.redText &&
prevProps.blueText === nextProps.blueText
);
};
//this component only re-renders if redText or blueText change.
//if el changes, it doesnt re-render. If you want this behavior to change,
//remove the stylesAreEqual function from the memo callback
const ViewItem = ({ el, redText, blueText }) => {
//responds to any styles passed into the component
const propStyle = redText.includes(el)
? styles.redText
: blueText.includes(el)
? styles.blueText
: styles.blackText;
//if you want to control the styles indiviually for each view item without needing
// to change redText, or blue Text props. It can managed locally here
const [style, setStyle] = useState(propStyle);
const onPressEvent = () => {
//write any change to style on a press
setStyle({ color: "black" });
};
useEffect(() => {
//if you want to respond to changed passed from a higher up component.
// though consider using useContext for this if your handling anything other
// than primary types (i.e strings, boolean, etc.)
setStyle(propStyle);
}, [propStyle]);
return (
<View style={styles.container}>
<Text onPress={onPressEvent} style={style}>
{el}
</Text>
</View>
);
};
const MemoViewItem = ({ el, redText, blueText }) =>
memo(
<ViewItem el={el} redText={redText} blueText={blueText} />,
stylesAreEqual
);
const MemoList = ({ arr, redText, blueText }) =>
//this means that unless the props passed into this component change,
// it will not re-render, even if a component above it does for any case.
memo(
<>
{arr.map((el) => {
return <MemoViewItem el={el} redText={redText} blueText={blueText} />;
})}
</>
);
export default function App() {
let [redText, setRedText] = useState(["This", "That"]);
let [blueText, setBlueText] = useState(["The", "Other"]);
let str = "This That And The Other";
let arr = str.split(" ");
let componentsArr = null;
function firstRender() {
componentsArr = [];
componentsArr.push(
<MemoList arr={arr} blueText={blueText} redText={redText} />
);
return componentsArr;
}
return (
<View style={styles.container}>
{componentsArr ? componentsArr : firstRender()}
</View>
);
}
Since I'm unsure if you want to change styles from onpress events, or from a general state coming from a higher component, I've included both in this example. In addition, depending on your use case, you can modify this above, and test where you need memoization or not since adding it does add extra overhead if its not necessary.
As a note though, the only way to prevent the list from re-rendering at all (only once on mount), is to manage the styles in a local component
In this case, removing redText and blueText from the App component, and removing the props on every component down the tree. From there, you can manage the styles inside the ViewItem component. Should this be the case, you can also remove the memo function. Below is an example.
import React, { useState, memo } from "react";
import { Text, View, StyleSheet } from "react-native";
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
blackText: {
color: "black",
},
redText: {
color: "red",
},
blueText: {
color: "blue",
},
});
const ViewItem = ({ el }) => {
//if you want to control the styles indiviually for each view item without needing
// to change redText, or blue Text props. It can managed locally here
const [redText, setRedText] = useState(["This", "That"]);
const [blueText, setBlueText] = useState(["The", "Other"]);
const style = redText.includes(el)
? styles.redText
: blueText.includes(el)
? styles.blueText
: styles.blackText;
//const [styles, setStyles] = useState({});
const onPressEvent = () => {
//write any change to style on a press
setRedText("Cool");
};
return (
<View style={styles.container}>
<Text onPress={onPressEvent} style={style}>
{el}
</Text>
</View>
);
};
//prevent list from re-rendering unless app prop changes
const MemoList = ({ arr }) => memo(
<>
{arr.map((el) => (
<ViewItem el={el} />
))}
</>
);
export default function App() {
let str = "This That And The Other";
let arr = str.split(" ");
let componentsArr = null;
function firstRender() {
componentsArr = [];
componentsArr.push(<MemoList arr={arr} />);
return componentsArr;
}
return (
<View style={styles.container}>
{componentsArr ? componentsArr : firstRender()}
</View>
);
}