反应故事书复选框更改处理程序不起作用

Posted

技术标签:

【中文标题】反应故事书复选框更改处理程序不起作用【英文标题】:React Storybook Checkbox change handler not working 【发布时间】:2020-07-05 19:42:21 【问题描述】:

在遵循本教程之后,我正在使用 React、Typescript、Storybook 和 Styled-Components 创建一个复选框组件:building-a-checkbox-component-with-react-and-styled-components。在使用 FunctionComponent 时,我不得不调整代码,但我遇到了更改处理程序的问题。我无法选中或取消选中似乎是只读的复选框,而且我不确定我哪里出错了。这是我的代码:

Checkbox.tsx

import React from 'react';
import styled from 'styled-components';
import  FunctionComponent  from 'react';

type CheckboxProps = 
    checked?: boolean;
    onChange: (e: React.ChangeEvent<htmlInputElement>) => void;
;

const CheckboxContainer = styled.div`
    display: inline-block;
    vertical-align: middle;
`;

const Icon = styled.svg`
    fill: none;
    stroke: white;
    stroke-width: 2px;
`;

const HiddenCheckbox = styled.input.attrs( type: 'checkbox' )`
    border: 0;
    clip: rect(0 0 0 0);
    clippath: inset(50%);
    height: 1px;
    margin: -1px;
    overflow: hidden;
    padding: 0;
    position: absolute;
    white-space: nowrap;
    width: 1px;
`;

const StyledCheckbox = styled.div`
    display: inline-block;
    width: 16px;
    height: 16px;
    background: $(props: CheckboxProps) => (props.checked ? 'green' : 'white');
    border-color: 'dark gray';
    border-width: 1px;
    border-style: solid;
    border-radius: 2px;

    $HiddenCheckbox:focus + & 
        box-shadow: 0 0 0 3px grey;
    

    $Icon 
        visibility: $(props: CheckboxProps) => (props.checked ? 'visible' : 'hidden');
    
`;

const Checkbox: FunctionComponent<CheckboxProps> = ( onChange, checked, ...props ) => 
    return (
        <CheckboxContainer>
            <HiddenCheckbox checked=checked ...props onChange=onChange />
            <StyledCheckbox data-testid="styledcheckbox" checked=checked ...props onChange=onChange>
                <Icon viewBox="0 0 24 24">
                    <polyline points="20 6 9 17 4 12" />
                </Icon>
            </StyledCheckbox>
        </CheckboxContainer>
    );
;

export default Checkbox;

Checkbox.stories.js

// Checkbox.stories.js
import React,  useState, useRef  from 'react';
import Checkbox from '@components/Checkbox/Checkbox';
import  action  from '@storybook/addon-actions';
import  storiesOf  from '@storybook/react';

// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
const CheckboxStateful = props => 
    const [value, setValue] = useState(props);
    const valRef = useRef(value);
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
    const onChange = event => 
        setValue(event.target.value);
        valRef.current = event.target.value;
    ;

    return (
        <Checkbox
            value=value
            onChange=event => 
                onChange(event);
            
        ></Checkbox>
    );
;
storiesOf('Checkbox', module)
    .add('with checked', () => 
        const value = true;
        // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
        const onChange = event => setValue(event.target.value);
        return <CheckboxStateful value=value onChange=onChange></CheckboxStateful>;
    )
    .add('with unchecked', () => 
        const value = false;
        // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
        const onChange = event => setValue(event.target.value);
        return <CheckboxStateful value=value onChange=onChange></CheckboxStateful>;
    );

由于我是 React 和 Storybook 的新手,我可能需要一些专家的意见来确定我的更改处理程序代码是否正确。我看过其他示例,但没有一个使用 Typescript。任何帮助将不胜感激。

【问题讨论】:

【参考方案1】:

解决方法是在Checkbox.tsx中将CheckboxProps中的onChange改为onClick,如下:

onClick: (event: React.MouseEvent<HTMLElement, MouseEvent>) => void;

并将 Checkbox.stories.js 中的 CheckboxStateful 简化如下:

const CheckboxStateful = () => 
const [value, setValue] = useState(false);
return <Checkbox checked=value onClick=() => setValue(!value)></Checkbox>;

;

现在完整的更新代码如下:

Checkbox.tsx

import * as React from 'react';
import styled from 'styled-components';
import  FunctionComponent  from 'react';

type CheckboxProps = 
    checked?: boolean;
    onClick: (event: React.MouseEvent<HTMLElement, MouseEvent>) => void;
;

const CheckboxContainer = styled.div`
    display: inline-block;
    vertical-align: middle;
`;

const Icon = styled.svg`
    fill: none;
    stroke: white;
    stroke-width: 2px;
`;

const HiddenCheckbox = styled.input.attrs( type: 'checkbox' )`
    border: 0;
    clip: rect(0 0 0 0);
    clippath: inset(50%);
    height: 1px;
    margin: -1px;
    overflow: hidden;
    padding: 0;
    position: absolute;
    white-space: nowrap;
    width: 1px;
`;

const StyledCheckbox = styled.div`
    display: inline-block;
    width: 16px;
    height: 16px;
    background: $(props: CheckboxProps) => (props.checked ? 'green' : 'white');
    border-color: 'dark gray';
    border-width: 1px;
    border-style: solid;
    border-radius: 2px;

    $HiddenCheckbox:focus + & 
        box-shadow: 0 0 0 3px grey;
    

    $Icon 
        visibility: $(props: CheckboxProps) => (props.checked ? 'visible' : 'hidden');
    
`;

const Checkbox: FunctionComponent<CheckboxProps> = ( onClick, checked, ...props ) => 
    return (
        <CheckboxContainer>
            <HiddenCheckbox checked=checked ...props />
            <StyledCheckbox checked=checked ...props onClick=onClick data-testid="styledcheckbox">
                <Icon viewBox="0 0 24 24">
                    <polyline points="20 6 9 17 4 12" />
                </Icon>
            </StyledCheckbox>
        </CheckboxContainer>
    );
;

export default Checkbox;

Checkbox.stories.js

/* eslint-disable @typescript-eslint/explicit-function-return-type */
// Checkbox.stories.js
import * as React from 'react';
import  useState  from 'react';
import Checkbox from '@components/Checkbox/Checkbox';
import  action  from '@storybook/addon-actions';
import  storiesOf  from '@storybook/react';

export default 
    title: 'Checkbox',
    component: Checkbox,
;

const CheckboxStateful = () => 
    const [value, setValue] = useState(false);
    return <Checkbox checked=value onClick=() => setValue(!value)></Checkbox>;
;

storiesOf('Checkbox', module)
    .add('with checked', () => 
        const value = true;
        return <Checkbox checked=value onClick=action('checked')></Checkbox>;
    )
    .add('with unchecked', () => 
        const value = false;
        return <Checkbox checked=value onClick=action('checked')></Checkbox>;
    )
    .add('stateful', () => 
        return <CheckboxStateful />;
    );

创建 React 项目并添加 Storybook 后,只需运行 yarn storybook,复选框就会正确显示。

【讨论】:

我不会将其称为修复,而是称为 hack。复选框有一个onChange 函数。【参考方案2】:

与其创建新的有状态组件,更好的方法是在组件模板中使用状态。

一个例子:

const Template: ComponentStory<typeof MyComponent> = (args) => 
  const [state, setState] = useState('');

  return (
    <MyComponent
      prop1=args.prop1
      prop2=args.prop2
      onChange=() => setState('Change')
    />
  );
;

这是我从以下方法获得的原始答案的链接: https://***.com/a/64722559/10641401

【讨论】:

以上是关于反应故事书复选框更改处理程序不起作用的主要内容,如果未能解决你的问题,请参考以下文章

next-i18next 翻译在故事书中不起作用,控制台日志丢失键

带有旋钮的角故事书(storybookjs/addons/knobs)带有select()的对象数组不起作用

Docker 创建反应应用程序热重载不起作用

复选框的Vue更改事件不起作用

闪亮/ rscript - 使用checkboxGroupInput整数列表的反应图不起作用

更改复选框时的ajax发布表单jquery ajax不起作用