react自定义hook复用state,实现多层抽屉效果

431 阅读1分钟

hook作为react的新特性,解决了在组件之间复用状态逻辑很难的问题,无需修改组件结构的情况下,复用状态逻辑。
此处通过自定义hook,useOpenInsideCard实现多个子组件的开关复用一个state,实现多层抽屉效果。

在线效果 codesandbox.io/s/zi-ding-y…

QQ20220427-140333-HD.gif

父组件 (第一层抽屉)

import { useState } from "react";
import { Card } from "antd";
import { CaretDownOutlined, CaretUpOutlined } from "@ant-design/icons";
import "./styles.css";
import FirstCardOne from "./FirstCardOne";
import FirstCardTwo from "./FirstCardTwo";

// 第一层只打开一个抽屉
export default function App() {
    const [openCardId, setOpenCardId] = useState(null);
    return (
        <div className="App">
        <Card
            title="第一层(1)"
            bodyStyle={{ display: `${openCardId === 1 ? "block" : "none"}` }}
            extra={
                <span style={{ fontSize: "20px" }}>
                {openCardId === 1 ? (
                    <CaretUpOutlined onClick={() => setOpenCardId(null)} />
                    ) : (
                    <CaretDownOutlined onClick={() => setOpenCardId(1)} />
                )}
                </span>
            }
        >
            <FirstCardOne showCard={openCardId === 1} />
            <FirstCardTwo showCard={openCardId === 1} />
        </Card>
        <Card
            title="第一层(2)"
            bodyStyle={{ display: `${openCardId === 2 ? "block" : "none"}` }}
            extra={
                <span style={{ fontSize: "20px" }}>
                {openCardId === 2 ? (
                    <CaretUpOutlined onClick={() => setOpenCardId(null)} />
                    ) : (
                    <CaretDownOutlined onClick={() => setOpenCardId(2)} />
                )}
                </span>
            }
        >
            第二层
        </Card>
        <Card
            title="第一层(3)"
            bodyStyle={{ display: `${openCardId === 3 ? "block" : "none"}` }}
            extra={
                <span style={{ fontSize: "20px" }}>
                {openCardId === 3 ? (
                    <CaretUpOutlined onClick={() => setOpenCardId(null)} />
                    ) : (
                    <CaretDownOutlined onClick={() => setOpenCardId(3)} />
                )}
                </span>
            }
        >
            第二层
        </Card>
        </div>
    );
}

自定义hook, useOpenInsideCard

import { useState, useEffect } from "react";

export default function useOpenInsideCard(showCard) {
    const [openInsideCard, setOpenInsideCard] = useState(false);

    useEffect(() => {
        if (!showCard) {
            setOpenInsideCard(false);
        }
     }, [showCard]);
     
    return [openInsideCard, setOpenInsideCard];
}

子组件 第二层抽屉
第一层关闭后,第二次里面的抽屉全部关闭
父组件卡片关闭,所有的子组件里面的所有的卡片需要关闭。并且子组件也可以单独控制自己的开关。
子组件使用以上自定义hook,useOpenInsideCard,实现开关控制
(做多层抽屉时,原理一样,可同样处理)

import { Card } from "antd";
import { CaretDownOutlined, CaretUpOutlined } from "@ant-design/icons";
import useOpenInsideCard from "./useOpenInsideCard";

export default function FirstCardOne(prop) {
    const { showCard } = prop;
    const [openInsideCard, setOpenInsideCard] = useOpenInsideCard(showCard);

    return (
        <Card
            title="第二层(1)"
            bodyStyle={{ display: `${openInsideCard ? "block" : "none"}` }}
            extra={
            <span
            style={{ fontSize: "20px" }}
            onClick={() => {
                const newOpenTime = !openInsideCard;
                setOpenInsideCard(newOpenTime);
                }}
                >
                {openInsideCard ? <CaretUpOutlined /> : <CaretDownOutlined />}
                </span>
            }
        >
        this is a test 1.1
        </Card>
    );
}