skip to Main Content

When clicking on a username, I want to display the information individually for that specific user.

I have tried using the handleShow function, which toggles from false to true, so I can display or hide the content.

The problem is when I click on a user al three divs are displayed and when the show state is false there is no content showing, which is good, but I have a black line coming from the div.

I have tried using display: none on the div, but then when I click on a username, no content is displayed.

What is the solution to display and hide the content only for a specific username and to have a display: none when the show state is false?

export default function App() {
  const [data, setData] = useState([]);
  const [isLoaded, setIsLoaded] = useState(false);
  const [show, setShow] = useState(false);

  const handleShow = () => {
    setShow((prevShow) => !prevShow);
  };

  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/users")
      .then((response) => {
        if (!response.ok) {
          throw new Error("Data failed to fetch");
        }
        return response.json();
      })
      .then((data) => {
        setData(data);
        setIsLoaded(true);
      });
  }, []);

  return (
    <div className="App">
      {isLoaded && (
        <>
          <Users data={data} handleShow={handleShow} />
          <Card data={data[0]} show={show} />
          <Card data={data[1]} show={show} />
          <Card data={data[2]} show={show} />
        </>
      )}
    </div>
  );
}



const Users = (props) => {
  const { data, handleShow } = props;

  return (
    <div>
      <p style={{ cursor: "pointer" }} onClick={handleShow}>
        {data[0].name}
      </p>
      <p style={{ cursor: "pointer" }} onClick={handleShow}>
        {data[1].name}
      </p>
      <p style={{ cursor: "pointer" }} onClick={handleShow}>
        {data[2].name}
      </p>
    </div>
  );
};

export default Users;



const Card = (props) => {
  const { data, show } = props;

  return (
    <div style={{ border: "1px solid black", textAlign: "center" }}>
      {show && (
        <>
          {" "}
          <h3>{data?.id}</h3>
          <h3>{data?.username}</h3>
          <h3>{data?.email}</h3>{" "}
        </>
      )}
    </div>
  );
};

export default Card;

5

Answers


  1. Don’t render anything if your show is false. Black line is shown because of the border.

    const Card = (props) => {
      const { data, show } = props;
    
      if (!show) return (<></>);
    
      return (
        <div style={{ border: "1px solid black", textAlign: "center" }}>
              {" "}
              <h3>{data?.id}</h3>
              <h3>{data?.username}</h3>
              <h3>{data?.email}</h3>{" "}
        </div>
      );
    };
    
    Login or Signup to reply.
  2. You need to extend your state to not only capture whether any user is shown but the selected index (-1 if no user shown). So handleShow should get a parameter for the index as well.

    The Card component should not know whether it is shown or not but you should embed the Card component only when a user is selected (i.e. selected index >= 0). When selected index is -1, output no Card component and if a user is selected embed just one. Pass the data of the user to show.

    Login or Signup to reply.
  3.     export default function App() {
          const [data, setData] = useState([]);
          const [isLoaded, setIsLoaded] = useState(false);
          const [show, setShow] = useState(null);
        
          const handleShow = (e) => {
            setShow(e);
          };
        
          useEffect(() => {
            fetch("https://jsonplaceholder.typicode.com/users")
              .then((response) => {
                if (!response.ok) {
                  throw new Error("Data failed to fetch");
                }
                return response.json();
              })
              .then((data) => {
                setData(data);
                setIsLoaded(true);
              });
          }, []);
        
          return (
            <div className="App">
              {isLoaded && (
                <>
                  {data.map((val,idx) =><> <Users data={val} handleShow={()=>handleShow(idx)} />
    <Card val={val} show={show} idx={idx}/></>
    )}
                  
                
                </>
              )}
            </div>
          );
        }
        
        
        
        const Users = (props) => {
          const { val, handleShow } = props;
        
          return (
            <div>
              <p style={{ cursor: "pointer" }} onClick={()=>handleShow()}>
                {val.name}
              </p>
              
            </div>
          );
        };
        
        export default Users;
        
        
        
        const Card = (props) => {
          const { val, show,idx } = props;
        
          return (
            <div style={{ border: "1px solid black", textAlign: "center",display:{`${idx}===show?block:none `}}}>
             
                  
                  <h3>{val.id}</h3>
                  <h3>{val.username}</h3>
                  <h3>{val.email}</h3>
                
            </div>
          );
        };
        
        export default Card;
    
    Login or Signup to reply.
  4. When you set "show", all your Card-Elements get the new value in the next render. So all Cards are always shown or not shown. You should instead give each card an index and set the Show-Variable to the index, that should be shown. If the index is -1 or null, no card is shown at all.
    To achieve this, you could map your array to the Cards:

    data.map((item, index) => {show === index && <Card data={item} />})
    

    Side note: When you set states with arrays or objects, you should always create a new instance to avoid side effects. So if you set your data-array, do it like this:

    setData([...data]);
    
    Login or Signup to reply.
  5. You can take the state "show" to a higher level in App component like this:

    return (
            <div className="App">
              {isLoaded && (
                <>
                  <Users data={data} handleShow={handleShow} />
                  {show && <Card data={data[0]} />}
                  {show && <Card data={data[1]} />}
                  {show && <Card data={data[2]} />}
                </>
              )}
            </div>
          );
    

    Then when show is false the component will not be displayed in its entirety.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search