🤕
フォームを作る過程でつまずいたこと
はじめに
React
を使ってフォームを作成するにあたってTypescript
による型や動作などでつまずいたことを以下にまとめます。スタイルにはMaterial-Ui
を用いてます。
ファイル構成
├── src/
├── components/
└── Form/
└──Form.tsx
└── index.tsx
└──App.tsx
App.tsx
import { createMuiTheme, makeStyles, ThemeProvider } from '@material-ui/core';
import { green, purple } from '@material-ui/core/colors';
import React from 'react';
import Form from '../components/Form';
const theme = createMuiTheme({
palette: {
primary: {
main: purple[500],
},
secondary: {
main: green[500],
},
background: {
default: '#f4f5fd',
},
},
overrides: {
MuiAppBar: {
root: {
transform: 'translateZ(0)',
},
},
},
props: {
MuiIconButton: {
disableRipple: true,
},
},
});
const useStyles = makeStyles({
appMain: {
paddingLeft: '320px',
width: '100%',
},
});
function App() {
const classes = useStyles();
return (
<ThemeProvider theme={theme}>
<div className={classes.appMain}>
<Form />
</div>
</ThemeProvider>
);
}
export default App;
imputタグに文字が表示されない
問題のコードはForm.tsxファイルにありました。
Form.tsx
import React from 'react';
import { Grid, makeStyles, Paper, TextField } from '@material-ui/core';
const useStyles = makeStyles((theme) => ({
root: {
'& .MuiFormControl-root': {
width: '80%',
margin: theme.spacing(1),
},
},
pageContent: {
margin: theme.spacing(5),
padding: theme.spacing(3),
},
}));
export interface FormValue {
id: number;
fullName: string;
email: string;
}
const formValue: FormValue = {
id: 0,
fullName: '',
email: '',
};
const Form = () => {
const classes = useStyles();
return (
<Paper className={classes.pageContent}>
<form className={classes.root} autoComplete="off">
<Grid container>
<Grid item xs={6}>
<TextField
variant="outlined"
label="お名前"
name="fullName"
value={formValue.fullName}
/>
<TextField
variant="outlined"
label="メールアドレス"
name="email"
value={formValue.email}
/>
</Grid>
</Grid>
</form>
</Paper>
);
};
export default Form;
Material-Ui
のおかげでエフェクトもかっこいいです。
しかし問題となったのはテキストフィールド上に文字が反映されていないということです。
これはテキストフィールドのプロパティであるvalue属性に空文字が設定されているためです。(こんな単純なことになんで動かへんねん?と数十分かかりました。。。)改善策として、onChange属性に関数(handleInputChange)を割り当てて、その関数内でuseStateを使うという手段を取りました。
改善したForm.tsxのコードを一部表示します。
Form.tsxの一部
const Form = () => {
const classes = useStyles();
const [values, setValues] = useState(formValue);
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = event.target;
setValues({
...values,
[name]: value,//fullName:value,email:valueの省略形
});
};
return (
<Paper className={classes.pageContent}>
<form className={classes.root} autoComplete="off">
<Grid container>
<Grid item xs={6}>
<TextField
variant="outlined"
label="お名前"
name="fullName"
value={values.fullName}//formValueからvaluesに変更
onChange={handleInputChange}
/>
<TextField
variant="outlined"
label="メールアドレス"
name="email"
value={values.email}//formValueからvaluesに変更
onChange={handleInputChange}
/>
</Grid>
</Grid>
</form>
</Paper>
);
};
少しコードを解説します。
handleInputChange
内event.targetにはvariant,label,name,value属性が内包されていますが、必要なname属性とvalue属性を分割代入によって取り出しています。
またイベントオブジェクトを引数に取っていますが、どのような型を指定するべきか分からなかったため、Qiita
の記事( any型で諦めない React.EventCallback)にて参考にさせてもらいました。
以上コードの改善により、無事テキストフィールドに文字が反映されました!
Discussion