ReactのClass Componentをstateless Componentに置き換える。
【所要時間】
測るの忘れた。5時間くらい。
【概要】
- 以前作ったアプリ→https://astatsuya.github.io/transfer/ではクラスコンポーネントをいくつか使っていたが、全てステートレスコンポーネントで書けるはずだったので、書き直した。
- Reduxを忘れたくない。のともっと慣れたい。
- もっと直したいところあるけど、とりあえずここだけ。
- レポジトリ→ https://github.com/astatsuya/transfer
【要約・学んだこと】
Formのページを修正
元々Reactのstateで保持していた要素を、Reduxのactionとreducerに新しいobject要素を追加。
そしてFormの修正はこれが出発点。→https://github.com/astatsuya/transfer/commit/e4d38df52668755cfd4df82879eaa3b90dc4e24b
このときmapStateToPropsと、mapDispatchToPropsを別のファイルに移した。他のファイルでもその都度mapStateToPropとmapDispatchToProps を宣言していたが、MapToProps.jsというファイルに全て移した。→https://github.com/astatsuya/transfer/blob/cccc19bb41482082574cc91ea5dbb7b9158d84f9/src/components/Search.js
- 苦戦した箇所。
Formではname, age, genderなど複数の要素を送信するので、どのように記述するといいか考えた。
// Form.jsconst handleChange = (event) => { const { name, type } = event.target;
let value; type === 'number' ? value = parseInt(event.target.value, 10) : { value } = event.target; updateForm({
name,
value,
});...return (
<form
className="form"
onSubmit={handleSubmit}
>
<label htmlFor="name" style={{ backgroundColor: nameAlertColor }}>
Name
<br />
{nameEmpty}
<input
type="text"
name="name"
id="name"
value={name}
onChange={handleChange}
style={{ backgroundColor: nameAlertColor }}
/>
</label>
<br />
<label htmlFor="age">
Age
<br />
<input
type="number"
name="age"
id="age"
value={age}
onChange={handleChange}
/>
</label>
<br />
<label htmlFor="gender"> {// eslint-disable-line
}
<br />
<select
id="gender"
name="gender"
onChange={handleChange}
value={gender}
>
<option value="Male">Male</option>
<option value="Female">Female</option>
<option value="Others">Others</option>
</select>
</label>
<br /> ...
まずevent.targetのname, type, valueを取得。
Formではnumberがstringに変換されるので、number属性のvalueはparseIntでnumberにする。そしてupdateFormをdispatch。
const { name, type } = event.target;
let value;type === 'number' ? value = parseInt(event.target.value, 10) : { value } = event.target;updateForm({
name,
value,
});
actionは
export const changeForm = form => ({
type: CHANGE_FORM,
name: form.name,
value: form.value,
});
reducerは
const updateForm = (state = initialState, action) => {
switch (action.type) {
case UPDATE_FORM:
return {
...state,
formContents: {
...state.formContents,
[action.object]: action.value,
},
};
こう書いた。
- PropTypesでちょっと苦戦した。
ConnectedForm.propTypes = {
addInfo: PropTypes.func.isRequired,
updateForm: PropTypes.func.isRequired,
alertForm: PropTypes.func.isRequired,
clearForm: PropTypes.func.isRequired,
formContents: PropTypes.shape(formTypes).isRequired,
};Datbaseページを修正
このformContentsではこのようなデータだ。
PropTypes.object.isRequiredとするとESLintが警告を出すので、
PropTypes.objectOf(oneOfType([PropTypes.string, PropTypes.number]).isRequired
のような感じで書けばいいのかと思ったが、下記のようにした。
formContents: PropTypes.shape(formTypes).isRequired,export const formTypes = () => {
const PropTypes = 'PropTypes';
return (
{
age: PropTypes.number,
arrival: PropTypes.number,
arrivalAlertColor: PropTypes.string,
department: PropTypes.string,
gender: PropTypes.string,
id: PropTypes.number,
leave: PropTypes.number,
location: PropTypes.string,
name: PropTypes.string,
nameAlertColor: PropTypes.string,
nameEmpty: PropTypes.string,
position: PropTypes.string,
wrongArrival: PropTypes.string,
});
};
Reactの公式ページをもうほんのちょっと下まで読んだらしっかり書いてあった。
// An object taking on a particular shape optionalObjectWithShape: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
}),
Databaseページを修正
基本的には先ほどと同じ。mapStateToPropsとmapDispatchToPropsを他のファイルに移した。また、mapStateToPropsで取得したデータをソートする関数もMapToProps.jsに移した。
見た目に関するコード以外の多くが別ファイルになり、見通しがよくなった。
SeachFormとSearchも同様に修正
同様に修正した。
【わからなかったこと】
特になし。
【感想】
自分が書いたコードでも修正しようとすると妙に難しかった。おそらくReduxを使う時は今回のようにmapStateToPropsとmapDispatchToPropsは一箇所にまとめて書くのが楽(これを作っている時そのやり方がわからなかった)なので、次回からはそうしたい。
今回はクラスコンポーネントをReduxに置き換えることにフォーカスしたが、イケてないコードが多々あったので、いい感じにできるか考えていきたい。