오늘 작업은 비밀번호 reset form이었다.
그동안 너무 막 그때그때 필요한 컴포넌트를 만들면서 했는데, 이번 기회에 재사용 가능하게 만들어보고 싶어서 그리했고, 마음에 드는 결과물이 나온 것 같아서 자랑(?)해본다.
// form의 textfield 등의 input 재사용
import React, { createElement } from 'react';
import PropTypes from 'prop-types';
import { Controller } from 'react-hook-form';
import { ErrorMessage } from '@hookform/error-message';
import ReactCodeInput from 'react-code-input';
import { TextField, InputLabel } from '@material-ui/core';
import { Container } from './styles';
// 부모 컴포넌트에서 useForm을 정의해서 control, errors 등을 내려준다.
const ControlledInput = ({
control,
name,
rules,
errors,
defaultValue,
renderComponent,
inputLabel,
componentProps,
...arg
}) => {
const COMPONENT_TYPE = {
TextField,
ReactCodeInput,
};
const Component = COMPONENT_TYPE[renderComponent] || renderComponent;
// 이부분에서 많이 헤맸다. Component Dynamic Naming 하는 법
return (
<Container>
<InputLabel htmlFor={name} className="input-label">
{inputLabel}
</InputLabel>
<Controller
control={control}
name={name}
rules={rules}
defaultValue={defaultValue}
{...arg}
render={({ field: { onChange, name, value } }) => {
//console.log(value);
return (
<Component
name={name}
onChange={onChange}
defaultValue={defaultValue && defaultValue}
value={defaultValue || value}
variant="outlined"
{...componentProps}
/>
);
}}
/>
<div className="error">
<ErrorMessage errors={errors} name={name}>
{({ messages }) =>
messages &&
Object.entries(messages).map(([type, message]) => (
<p key={type}>{message}</p>
))
}
</ErrorMessage>
</div>
</Container>
);
};
// label, input, error 메시지를 하나의 컴포넌트에서 관리할 수 있게 되었다.
ControlledInput.propTypes = {
renderComponent: PropTypes.string.isRequired,
inputLabel: PropTypes.string,
control: PropTypes.any,
name: PropTypes.string,
rules: PropTypes.object,
errors: PropTypes.object,
defaultValue: PropTypes.any,
componentProps: PropTypes.object,
};
export default ControlledInput;