ReactのClass Componentをstateless Componentに置き換える。

Tatsuya Asami
9 min readJan 27, 2019

--

【所要時間】

測るの忘れた。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

最終的にはこうした。→https://github.com/astatsuya/transfer/blob/bd88c2a3d3e27a9f2aae63981367f97cac30dabc/src/components/Form.js

このとき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に置き換えることにフォーカスしたが、イケてないコードが多々あったので、いい感じにできるか考えていきたい。

--

--

Tatsuya Asami
Tatsuya Asami

Written by Tatsuya Asami

Front end engineer. React, TypeScript, Three.js

No responses yet