自定义react-hook,用于动态设置CSS类

时间:2019-06-27 14:29:45

标签: reactjs typescript react-hooks

我目前正在玩和学习React的钩子。我想重新使用设置元素阴影的功能(使用bootstrap作为css-framework)。

这是我的App当前的样子:

export const App: React.FunctionComponent<IAppProps> = ({ }: IAppProps) => {
    // get shadow-classes for alert
    const [shadowClasses, setShadowClasses] = useShadow("none");

    // define callbacks when hovering the alert
    const handleMouseEnter = () => setShadowClasses("regular");
    const handleMouseOut = () => setShadowClasses("none");

    // return the markup to be used
    return (
        <Container>
            <Grid.Row>
                <Grid.Col>
                    <Alert color={Constants.Color.Danger} className={classNames(shadowClasses)} onMouseEnter={handleMouseEnter} onMouseOut={handleMouseOut} >{"This is some kind of an alert ..."}</Alert>
                </Grid.Col>
            </Grid.Row>
        </Container>
    );
}; 

我的目标是在Alert悬停时添加阴影。不幸的是,悬停时什么也没发生,我不知道为什么。

在下面找到我的“自定义钩子”的实现:

export function useShadow(initialType: "none"|"sm"|"regular"|"large"): [string[], (type: "none"|"sm"|"regular"|"large") => void] {
    // define the classes to be used
    const classNames: string[] = [];

    // get the shadow's current value
    const [shadowType, setShadow] = React.useState(initialType);

    // set depending on given type
    switch (shadowType) {
        case "none":
            classNames.push(`shadow-none`);
            break;
        case Constants.BreakpointSize.Small:
            classNames.push(`shadow-sm`);
            break;
        case "regular":
            classNames.push(`shadow`);
            break;
        case Constants.BreakpointSize.Large:
            classNames.push(`shadow-lg`);
            break;
    }

    // define the callback to change the shadow
    const handleChange = (type: Type) => () => setShadow(type);

    // return the class-names and the change-callback
    return [classNames, handleChange];
}

我什至不确定这是否是使用自定义钩子的正确方法。

**更新**

我创建了一个useSpacing钩子来设置元素的间距,其实现方式如下:

export function useSpacing(initialSpacingProps: ISpacingProps[] = []): [string[], (spacingProps: ISpacingProps[]) => void] {
    // get the state-value
    const [spacingProps, setSpacingProps] = React.useState(initialSpacingProps);

    // create the result holding the class-names
    const spacingClasses: string[] = [];

    // loop through given spacing-definitions
    for (let spacingProp of spacingProps) {
        // get the values
        const { breakpoint, property, side, size, negative } = spacingProp;

        // handle depending on breakpoint
        spacingClasses.push(`${property}${side}${breakpoint !== Constants.BreakpointSize.ExtraSmall ? `-${breakpoint}` : ``}-${negative && size !== Size.Auto ? `n` : ``}${size}`);
    }

    // define the callback when the value should be changed
    const handleChange = (newSpacingProps: ISpacingProps[]) => setSpacingProps(newSpacingProps);

    // return the classes
    return [spacingClasses, handleChange];
}

并以这种方式使用:

export const App: React.FunctionComponent<IAppProps> = ({ }: IAppProps) => {
    const initialSpacingProps = [
        {
            breakpoint: Constants.BreakpointSize.ExtraSmall,
            property: Spacing.Property.Margin,
            side: Spacing.Side.LeftRight,
            size: Spacing.Size.Two
        }
    ];

    const clickedSpacingProps = [
        {
            breakpoint: Constants.BreakpointSize.Small,
            property: Spacing.Property.Padding,
            side: Spacing.Side.TopBottom,
            size: Spacing.Size.Five
        }
    ];

    // get the classes to apply spacing accordingly
    const [spacingClasses, setSpacingClasses] = useSpacing(initialSpacingProps);

    // define the callback when jumbotron gets clicked
    const handleClick = React.useCallback(() => setSpacingClasses(clickedSpacingProps), []);

    // return the markup to be used
    return (
        <Container>
            <Grid.Row>
                <Grid.Col>
                    <Shadows.Shadow type={Constants.BreakpointSize.Large}>
                        <Jumbotron className={classNames(spacingClasses)} onClick={handleClick}>
                            <h1 className="display-4">Hello, world!</h1>
                        </Jumbotron>
                    </Shadows.Shadow>
                </Grid.Col>
            </Grid.Row>
        </Container>
    );
};

点击巨型机元素时,新间距将正确应用

1 个答案:

答案 0 :(得分:1)

您的handleChange函数正在返回另一个函数,删除第二个函数将对其进行修复。

const handleChange = (type: Type) => setShadow(type);

演示:https://codesandbox.io/s/youthful-gould-offv6