Checkboxのコンポーネントを作るになんでこれだけのコード量が必要になるのだろうか...
Hooksもふんだんに使われている。
github.com
import React, { useCallback, useEffect, useRef, useState } from "react";
import styled from "styled-components";
import {
CheckBoxIcon,
CheckBoxOutlineBlankIcon,
} from "components/atoms/IconButton";
import Text from "components/atoms/Text";
import Flex from "components/layout/Flex";
export interface CheckBoxProps
extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "defaultValue"> {
label?: string;
}
const CheckBoxElement = styled.input`
display: none;
`;
const Label = styled.label`
cursor: pointer;
margin-left: 6px;
user-select: none;
`;
const CheckBox = (props: CheckBoxProps) => {
const { id, label, onChange, checked, ...rest } = props;
const [isChecked, setIsChecked] = useState(checked);
const ref = useRef<HTMLInputElement>(null);
const onClick = useCallback(
(e: React.MouseEvent) => {
e.preventDefault();
ref.current?.click();
setIsChecked((isChecked) => !isChecked);
},
[ref, setIsChecked]
);
useEffect(() => {
setIsChecked(checked ?? false);
}, [checked]);
return (
<>
<CheckBoxElement
{...rest}
ref={ref}
type="checkbox"
checked={isChecked}
readOnly={!onChange}
onChange={onChange}
/>
<Flex alignItems="center">
{}
{checked ?? isChecked ? (
<CheckBoxIcon size={20} onClick={onClick} />
) : (
<CheckBoxOutlineBlankIcon size={20} onClick={onClick} />
)}
{}
{label && label.length > 0 && (
<Label htmlFor={id} onClick={onClick}>
<Text>{label}</Text>
</Label>
)}
</Flex>
</>
);
};
export default CheckBox;
個人的にはこれぐらいでよいのではと感じる。propでUIコンポーネントが受け取るパラメータをtypeで定義して代入する。場合によっては、useEffectやuseStateをonChangeに仕込むなりしたらいい。
weev.media
type Props = {
id: string;
value: boolean;
text: string;
onChange: () => void;
};
export const Checkbox = ({ id, value, text, onChange }: Props) => {
return (
<div>
<label htmlFor={id}>
<div>
<input
type="checkbox"
id={id}
checked={value}
onChange={() => {
onChange();
}}
/>
</div>
<div>
{text}
</div>
</label>
</div>
);
};