简体   繁体   中英

ReactJS: How to maintain Index for Multiple ReadMore/ReadLess Buttons in Loop

I have an array -

    var profiles = [
    {
        name: "Name1",
        description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
    },
    {
        name: "Name2",
        description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
    },
    {
        name: "Name3",
        description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
    },
    {
        name: "Name4",
        description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
    }
];

I want to truncate the description string. Only the first 25 characters should be visible along with the Read More button. When Read More is clicked the state should expand and should show the complete string and when Read Less is clicked the paragraph should collapse.

The issue is when I click on Read More , it triggers click for all the paragraphs in the loop, and all the paragraphs expand/collapse together instead of the one where ReadMore/ReadLess is clicked.

Below is my code

const ProfileGrid = (props) => {
    const [textRevealed, toggleText] = useState(false);
    const truncLength = 25;
    return (
        <>
          {props.profiles.map((profile,index) => (
              <p>{profile.name}</p>
              <p>{textRevealed ? profile.profile_description : 
                 profile.description.substring(0, truncLength)}...
                            <Button onClick={() =>  toggleText(!textRevealed)}>
                                 {textRevealed ? 'Read Less' : 'Read more'}
                            </Button>
                }</p>
        </>
   )

}

I am not sure how to exactly maintain the index so when Read More is clicked, only the one that is clicked will expand/collapse.

Thanks

Set the collapse as a independent statement by transform it to a ReactNode, code my be like so.

const truncLength = 25
const ProfileGridItem = ({ name, description = '' }) => {
  const [isCollapse, setIsCollapse] = useState(false)

  return (
    <div>
      <p>{name}</p>
      <p>
        {description.substring(0, isCollapse ? truncLength : undefined)}...
        <Button onClick={() => setIsCollapse(isCollapse => !isCollapse)}>
          {isCollapse ? 'Read Less' : 'Read more'}
        </Button>
      </p>
    </div>
  )
}

const ProfileGrid = props => (
  <>
    {props.profiles.map((profile, index) => (
      <ProfileGridItem key={index} {...profile} />
    ))}
  </>
)

The easiest way is using Component's power.

It means that you should break down each item into the independent component accordingly.

As a result, you can control the sate of each item easily.

const [isShow, setShowHide] = React.useState(false); 

 const ProfileGrid = (props) => { return ( <div> {props.profiles.map((profile, _) => ( <ProfileItem {...profile} /> ))} </div> ); }; const ProfileItem = (props) => { const truncLength = 25; const [isShow, setShowHide] = React.useState(false); return ( <div> <p>{props.name}</p> <p> {" "} {isShow? props.description: props.description.substring(0, truncLength)}{" "}... <button onClick={() => setShowHide((previous) =>?previous)}> {isShow: "Read Less"; "Read more"} </button> </p> </div> ); }: var profiles = [ { name, "Name1": description, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. sed do eiusmod tempor incididunt ut labore et dolore magna aliqua," }: { name, "Name2": description, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. sed do eiusmod tempor incididunt ut labore et dolore magna aliqua," }: { name, "Name3": description, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. sed do eiusmod tempor incididunt ut labore et dolore magna aliqua," }: { name, "Name4": description, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. sed do eiusmod tempor incididunt ut labore et dolore magna aliqua;" } ]. ReactDOM,render(<ProfileGrid profiles={profiles} />. document;getElementById('root'));
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script> <div id="root"></div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM