Home > OS >  Parent action inside child component react
Parent action inside child component react

Time:08-25

I am having two components, App and a panel. On button clcik, I add panel to the screen and all the actions corresponding actions inside of the panel is handled in the Panel component ( Actions are expand, collapse and close). Can I execute onClose method inside of the Panel component instead in App component. I am having a check of if cardBody is present in the parent component. For removing that card im setting its body to null inside App component. How can I do the same in Panel component.

https://codesandbox.io/s/basic-demo-card-6ywop7?file=/src/Panel.jsx:0-1022

import React, { useState } from "react";
import ReactDOM from "react-dom";
import Panel from "./Panel";
import "./styles.css";

function App() {
  const [card, setCard] = useState({
    cardId: "",
    cardBody: null
  });

  const handleClick = (cardId, cardBody) => {
    setCard({ cardId, cardBody });
  };

  const { cardId, cardBody } = card;

  return (
    <>
      <div className="main">
        <button onClick={() => handleClick("Panel 1", <h1>h1</h1>)}>
          Add Panel 1
        </button>
        <button onClick={() => handleClick("Panel 2", <div>div</div>)}>
          Add Panel 2
        </button>
      </div>
      {cardBody && (
        <div className="cards-container">
          <Panel
            key={cardId}
            cardId={cardId}
            cardBody={cardBody}
            onClose={() =>
              setCard({
                cardId: "",
                cardBody: null
              })
            }
          />
        </div>
      )}
    </>
  );
}

import React, { useState, useCallback } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
  faSquareMinus,
  faRectangleXmark
} from "@fortawesome/free-solid-svg-icons";

function Panel(props) {
  const [isMinimized, setIsMinimized] = useState(false);
  const { cardId, cardBody, onClose } = props;

  const onMaximize = useCallback(() => {
    setIsMinimized(!isMinimized);
  }, [isMinimized]);

  return (
    <>
      <div className={isMinimized ? "card-min" : "card"}>
        <div className="card-actions">
          <span onClick={onMaximize}>{cardId}</span>
          {!isMinimized && (
            <FontAwesomeIcon
              icon={faSquareMinus}
              onClick={() => {
                setIsMinimized(true);
              }}
            />
          )}
          <FontAwesomeIcon icon={faRectangleXmark} onClick={onClose} />
        </div>
        <div className="card-body">{cardBody}</div>
      </div>
    </>
  );
}

export default Panel;

CodePudding user response:

One workaround is to control the show/hide by display: 'none'/'block' inside the Panel component.

Panel component

import React, { useImperativeHandle, useState, useCallback } from 
"react";

import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
  faSquareMinus,
  faRectangleXmark
} from "@fortawesome/free-solid-svg-icons";

function Panel(props) {
  const [isMinimized, setIsMinimized] = useState(false);
  const { cardId, cardBody, setCard } = props;

  const onMaximize = useCallback(() => {
    setIsMinimized(!isMinimized);
  }, [isMinimized]);

  return (
    <>
      <div
        style={{ display: cardBody ? "block" : "none" }}
        className={isMinimized ? "card-min" : "card"}
      >
        <div className="card-actions">
          <span onClick={onMaximize}>{cardId}</span>
          {!isMinimized && (
            <FontAwesomeIcon
              icon={faSquareMinus}
              onClick={() => {
                setIsMinimized(true);
              }}
            />
          )}
          <FontAwesomeIcon
            icon={faRectangleXmark}
            onClick={() =>
              setCard({
                cardId: "",
                cardBody: null
              })
            }
          />
        </div>
        <div className="card-body">{cardBody}</div>
      </div>
    </>
  );
}

export default Panel;

App.js

import React, { useState, useRef } from "react";
import ReactDOM from "react-dom";
import Panel from "./Panel";
import "./styles.css";

function App() {
  const [card, setCard] = useState({
    cardId: "",
    cardBody: null
  });

  const handleClick = (cardId, cardBody) => {
    setCard({ cardId, cardBody });
  };

  const { cardId, cardBody } = card;

  return (
    <>
      <div className="main">
        <button onClick={() => handleClick("Panel 1", <h1>h1</h1>)}>
          Add Panel 1
        </button>
        <button onClick={() => handleClick("Panel 2", <div>div</div>)}>
          Add Panel 2
        </button>
      </div>
      <div className="cards-container">
        <Panel
          key={cardId}
          cardId={cardId}
          cardBody={cardBody}
          setCard={setCard}
        />
      </div>
    </>
  );
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

This is working example

Also, you can completely conditionally show and hide the inner content of the panel but you need some modifications in the style by moving the "card-min" and "card" class to an inner div instead of the root element on the component.

  • Related