reactjstypescriptantd

React + typescript + antd collapse. How to pass data between collapse's elements?


How to pass data from the first element to the second one by clicking the button?

If we open the second component by clicking on the panel, it must to stay empty.

It is welcomed if the answer is with items, and not with Collapse.Panel.

Also, I had to hardcode the activeKey value which is completely wrong and immobilizes the entire parent Collapse component.

interface ChildComponentProps {
    //activeKey: number;
    //setActiveKey: React.Dispatch<React.SetStateAction<string>>;
    setActiveKey: (newType: string) => void;
}



const Element1: React.FC<ChildComponentProps> = ({ setActiveKey }) => {
    // need to pass this 'car'
    const car: { type: string, model: string, year: number } = {
        type: "Toyota",
        model: "Corolla",
        year: 2009
    };

    const handleClick = (key: string) => {
        setActiveKey(key);
    }

    return (
        <div>
            <div>
                <Button
                    onClick={() => handleClick('2')}     // wrong hardcoding!
                >expandNextPanel
                </Button>
            </div>
        </div>
    );
}


const Element2 = () => {
    return (
        <div>
            <div>
                go back to the first component and click the button
            </div>
        </div>
    );
}



const CollapseComponent = () => {
    const [activeKey, setActiveKey] = useState<string>();

    return (
        <Collapse
            activeKey={activeKey}
            onChange={() => setActiveKey(activeKey)}
        >
            <Collapse.Panel header="Element1" key="1">
                <Element1
                    setActiveKey={setActiveKey}
                />
            </Collapse.Panel>

            <Collapse.Panel header="Element2" key="2">
                <Element2 />
            </Collapse.Panel>

        </Collapse>
    );
}


export default CollapseComponent;

Solution

  • To pass data from one Collapse.Panel (like Element1) to another (Element2) only when a button is clicked, and not when the panel is opened manually, you can use shared state at the parent level (CollapseComponent) and conditionally inject props only when the transition is triggered programmatically.

    You should also avoid hardcoding activeKey. Instead, update it dynamically based on interaction.

    Here’s a working approach using Ant Design Collapse, React, and TypeScript:


    🧩 Key Concepts:

    1. Manage activeKey in parent via useState.

    2. Store car data in parent temporarily when "Next" is clicked.

    3. Only pass car to Element2 when the transition is user-triggered (not manually expanded).

    4. Use items instead of <Collapse.Panel>.


    🧱 Full Example:

    import React, { useState } from 'react';
    import { Collapse, Button } from 'antd';
    import type { CollapseProps } from 'antd';
    
    interface Car {
      type: string;
      model: string;
      year: number;
    }
    
    interface Element1Props {
      onNext: (car: Car) => void;
    }
    
    const Element1: React.FC<Element1Props> = ({ onNext }) => {
      const car: Car = {
        type: "Toyota",
        model: "Corolla",
        year: 2009
      };
    
      return (
        <div>
          <Button onClick={() => onNext(car)}>Expand Next Panel</Button>
        </div>
      );
    };
    
    interface Element2Props {
      car?: Car;
    }
    
    const Element2: React.FC<Element2Props> = ({ car }) => {
      if (!car) {
        return <div>Go back to the first component and click the button</div>;
      }
    
      return (
        <div>
          <div><strong>Car Type:</strong> {car.type}</div>
          <div><strong>Model:</strong> {car.model}</div>
          <div><strong>Year:</strong> {car.year}</div>
        </div>
      );
    };
    
    const CollapseComponent: React.FC = () => {
      const [activeKey, setActiveKey] = useState<string | string[]>();
      const [sharedCar, setSharedCar] = useState<Car | undefined>(undefined);
    
      const handleNext = (car: Car) => {
        setSharedCar(car);
        setActiveKey("2");
      };
    
      const items: CollapseProps['items'] = [
        {
          key: '1',
          label: 'Element1',
          children: <Element1 onNext={handleNext} />
        },
        {
          key: '2',
          label: 'Element2',
          children: <Element2 car={sharedCar} />
        }
      ];
    
      const handleChange = (key: string | string[]) => {
        setActiveKey(key);
        // Optional: clear car data if user manually opens panel 2
        if (key !== '2') {
          setSharedCar(undefined);
        }
      };
    
      return (
        <Collapse activeKey={activeKey} onChange={handleChange} items={items} />
      );
    };
    
    export default CollapseComponent;
    

    🧠 Notes: