reactjs - عدم عمل معالج تغيير خانة الاختيار في React Storybook


أنا أقوم بإنشاء مكون خانة اختيار باستخدام React و Typescript و Storybook و Styled-Components، بعد اتباع هذا الدليل: building-a-checkbox-component-with-react-and-styled-components. كان عليّ تعديل الشيفرة حيث أنني أستخدم FunctionComponent، لكنني أواجه مشكلة مع دالة المعالجة للتغيير (change handler). لا أستطيع تفعيل أو إلغاء تفعيل خانة الاختيار والتي تبدو للقراءة فقط، ولست متأكدًا من مكان الخطأ الذي أقع فيه. إليك الشيفرة الخاصة بي:

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

الحل هو تغيير onChange إلى onClick في CheckboxProps في ملف Checkbox.tsx، كما يلي:

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

ولتبسيط CheckboxStateful في Checkbox.stories.js كما يلي:

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 وستظهر مربعات الاختيار بشكل صحيح.

الإجابة رقم 2

بدلاً من إنشاء مكوّن Stateful جديد، فإن النهج الأفضل بكثير هو استخدام الحالة في قالب المكوّنات.

مثال:

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

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

إليك رابط الإجابة الأصلية التي حصلت على هذا النهج منها: https://stackoverflow.com/a/64722559/10641401