0

I am trying to find a way to have show more/less text if there are more than 3 lines of text. I have tried the react-show-more-text package but it was very buggy so the closest I have been able to get is the top answer in this post. The main issue is that if there are only 3 lines its showing the read more/less text also. It should be show if there would actually be another line of text when you hit the button. My code.

import React, { useCallback, useState } from 'react';
import { Text } from 'react-native';

const ReadMoreText = ({ readMoreStyle, text, textStyle }) => {
  const [textShown, setTextShown] = useState(false);
  const [lengthMore, setLengthMore] = useState(false);

  const toggleNumberOfLines = () => {
    setTextShown(!textShown);
  };

  const onTextLayout = useCallback((e) => {
    setLengthMore(e.nativeEvent.lines.length >= 3);
  }, []);

  return (
    <>
      <Text onTextLayout={onTextLayout} numberOfLines={textShown ? undefined : 3} style={textStyle}>
        {text}
      </Text>

      {lengthMore ? (
        <Text onPress={toggleNumberOfLines} style={readMoreStyle}>
          {textShown ? 'Read Less' : 'Read More'}
        </Text>
      ) : null}
    </>
  );
};

export default ReadMoreText;

2 Answers2

0

The issue is that the number of lines needs to be updated in state. With what I was previously doing it was being overwritten to three every time.

const ReadMoreText = ({ readMoreStyle, text, textStyle }) => {
  const [showMoreButton, setShowMoreButton] = useState(false);
  const [textShown, setTextShown] = useState(false);
  const [numLines, setNumLines] = useState(undefined);

  const toggleTextShown = () => {
    setTextShown(!textShown);
  };

  useEffect(() => {
    setNumLines(textShown ? undefined : 3);
  }, [textShown]);

  const onTextLayout = useCallback(
    (e) => {
      if (e.nativeEvent.lines.length > 3 && !textShown) {
        setShowMoreButton(true);
        setNumLines(3);
      }
    },
    [textShown],
  );

  return (
    <>
      <Text onTextLayout={onTextLayout} numberOfLines={numLines} style={textStyle} ellipsizeMode="tail">
        {text}
      </Text>

      {showMoreButton ? (
        <Text onPress={toggleTextShown} style={readMoreStyle}>
          {textShown ? 'Read Less' : 'Read More'}
        </Text>
      ) : null}
    </>
  );
};
0

This is one rabbit hole that react native never bothers with. There are some options out there for react native, but even the most popular isn't done in typescript and lacks a lot of care.

So I made my own solution: https://www.npmjs.com/package/@rntext/more-or-less

I would appreciate it if you tried it and let me know if it fits your model and if not, maybe how to improve it.

Ren
  • 4,594
  • 9
  • 33
  • 61