Home > Software engineering >  React Native - Get number of lines of a text (before it is rendered)
React Native - Get number of lines of a text (before it is rendered)

Time:11-13

Question

How can I get the number of lines of a text before it is rendered?

I have implemented my own "CollapsibleText" (the typical read more/less text), but I am experiencing a bug because of calculating the number of lines with the "onLayout" prop.

I just want to render a short version of the original text with a "read more button"... but, to work with the "onLayout" prop, the full text has to be rendered before hidden it.

My current code works... but I need to avoid rendering the full text before the total lines calculation... is it possible?

Take a look at this snack, to notice the bug (test on iOS or Android devices, not in web).

Code

export default function CollapsibleText({
  children = "",
  numberOfLines = 3,
  ellipsizeMode = "tail",
  containerStyle,
  textStyle = styles.text,
  readMoreButtonStyle = styles.readMoreButton,
  readMoreTextStyle = styles.readMoreText,
}) {
  const { colors } = useTheme();

  const isMounted = useIsMounted();

  const { t } = useLanguage();

  const measured = useRef(false);

  const [isCollapsed, setIsCollapsed] = useState(false);
  const [showReadMoreButton, setShowReadMoreButton] = useState(false);

  const toggleIsCollapsed = () => {
    setIsCollapsed((prevIsCollapsed) => !prevIsCollapsed);
  };

  const handleOnTextLayout = useCallback(
    ({ nativeEvent: { lines } }) => {
      if (isMounted() && !measured.current && lines.length > numberOfLines) {
        measured.current = true;
        setIsCollapsed(true);
        setShowReadMoreButton(true);
      }
    },
    [isMounted]
  );

  const renderReadMoreButton = () => (
    <TouchableOpacity
      activeOpacity={0.75}
      onPress={toggleIsCollapsed}
      style={readMoreButtonStyle}
    >
      <Text style={[{ color: colors.silverChalice }, readMoreTextStyle]}>
        {t(`collapsibleText.${isCollapsed ? "readMore" : "readLess"}`)}
      </Text>
    </TouchableOpacity>
  );

  return (
    <View style={containerStyle}>
      <Text
        numberOfLines={isCollapsed ? numberOfLines : undefined}
        ellipsizeMode={ellipsizeMode}
        onTextLayout={handleOnTextLayout}
        style={textStyle}
      >
        {children}
      </Text>

      {showReadMoreButton && renderReadMoreButton()}
    </View>
  );
}

CodePudding user response:

How about... you just initialize the isCollapsed state with true?

const [isCollapsed, setIsCollapsed] = useState(true);

CodePudding user response:

You need to hide the All the text

function truncate(str, n){
return str?.length . n ? str.substr(0, n - 1)   "..." : str;
}

<Text>{truncate(movie?.overview, 150            
  • Related