I am trying to create a simple website that map through an array called Data. This array has a lot of objects and long text.
const [click,setClick] = useState(false)
{Data.Data.map((data, index) =>{
return(
<Content>
<p className="first-content">
<BigContainer imgStart={data.imgStart}>
<Wrapper key={index}>
<Solution>{data.Solution}</Solution>
<Client>{data.Client}</Client>
<ShowText>{data.ShowText}</ShowText>
<HideTextWrapper NeedToHide={data.NeedToHide} >
<HiddenText click={click}>
{data.HiddenText}
</HiddenText>
<ReadButton NeedButton={data.NeedButton} click={click} onClick={()=>{setClick(!click)}}>
{ click ? 'Read Less' : 'Read More' }
</ReadButton>
</HideTextWrapper>
</Wrapper>
<ImageWrapper>
<Image src={data.img} NeedImage={data.NeedImage}/>
</ImageWrapper>
</BigContainer>
</p>
</Content>
)}
I want to create "read more"/"read less" button which is <ReadButton>
to hide/show the <HiddenText>
. As you can see I used useState click
which will be changed by <ReadButton>
. Then, I changed the <HiddenText>
display with styled component.
export const HiddenText = styled.div`
line-height: 1.5;
font-size: 17px;
color: #fff;
background: blue;
display: ${({click}) =>(click ? 'block' : 'none' )};
`
The problem is I want just the clicked <HiddenText>
to be hidden but right now it affects all other<HiddenText>
as well because it uses the same click
. Any idea how to solve this problem?
CodePudding user response:
Just create child component with own state
const Content = () => {
const { text } = props;
const [show, setShow] = useState(false);
const toggle = () => setShow(!show); // Change state show true/false
return (
<HideTextWrapper>
{show && <HiddenText onClick={toggle}>{text}</HiddenText>}
<ReadButton NeedButton={show} onClick={toggle}>
{show ? "Read Less" : "Read More"}
</ReadButton>
</HideTextWrapper>
);
};
In array render Content
{items.map((data, index) => <Content key={index} text={data.HiddenText} />)}
CodePudding user response:
Try doing this with the useState hook.
const [click,setClick] = useState(false);
const [hidden,setHidden] = useState(false);
in your return block:
return (
{ click && (
return (
<div>
*** if click is true, render this code block***
</div>
)}
)
Its a little weird looking but what your doing is your telling the return block that IF click is true, render whats in-between the "{}". you can do the same with !click if you want something else to render if click is false. and of course you need toggling logic for click and hidden which could be as simple as:
<button onClick={(e)=> setClick(!click)}> Toggle click state </button>
CodePudding user response:
your component is to big in my opinion. create smaller components and you will fix your problem by itself.
but to fix it quickly you can refactor in this direction (not tested) do give it appropriate names. I do not know your domain
{Data.Data.map((data, index) =>{
return(
<Content key={index}>
<YourDataComponent data={data} />
</Content>
)}
then YourDataComponent is something like this:
const [click,setClick] = useState(false);
return (<p className="first-content">
<BigContainer imgStart={data.imgStart}>
<Wrapper key={index}>
<Solution>{data.Solution}</Solution>
<Client>{data.Client}</Client>
<ShowText>{data.ShowText}</ShowText>
<HideTextWrapper NeedToHide={data.NeedToHide} >
<HiddenText click={click}>
{data.HiddenText}
</HiddenText>
<ReadButton NeedButton={data.NeedButton} click={click} onClick={()=>{setClick(!click)}}>
{ click ? 'Read Less' : 'Read More' }
</ReadButton>
</HideTextWrapper>
</Wrapper>
<ImageWrapper>
<Image src={data.img} NeedImage={data.NeedImage}/>
</ImageWrapper>
</BigContainer>
</p>)
you should not be afraid of creating smaller components, they are your friend. as a suggestion, I would create a separate component for the read more behaviour.