はじめに
個人開発メモ📝
(11/19更新)
今回の課題
コンポーネント間で役割を分けたので、データの受け渡しや処理の呼び出しを行えるようにする。
データの受け渡し設計と役割分担
メインコンポーネント⇨ ビューとフォームページの呼び出し
フォームコンポーネント⇨ フォーム入力、送信
機能コンポーネント⇨ バックエンドとのやり取り
(親)メインコンポーネント
カレンダーを表示し、フォームコンポーネントを呼び出す
フォームコンポーネントからレスポンスデータを受け取り、ビューに表示
⬆︎ (データを渡す)
(子)フォームコンポーネント
入力されたフォームデータを収集し、機能コンポーネントに渡す
⬇︎ (処理の呼び出し)
機能用コンポーネント
バックエンドとのリクエスト・レスポンスのやり取り
①フォーム送信イベント内で、別のコンポーネントの関数を呼び出す
const ScheduleForm = () => {
// フォームデータ変数定義
const [scheduleFormData, setScheduleFormData] = useState({
date: '',
requirement: '',
memo: '',
});
// フォーム送信イベントの制御
const [submitEvent, setSubmitEvent] = useState(false);
// 入力内容の反映
const handleChange = (event) => {
const { name, value } = event.target;
setScheduleFormData({ ...scheduleFormData, [name]: value});
};
// props経由で関数を使用し、Feature.jsxに値を渡す
const handleInputSubmit = async(event) => {
event.preventDefault();
handleAddEvent(scheduleFormData);
setSubmitEvent(true);
};
// 機能コンポーネントから渡ってきたデータを取得する
const handleAddEvent = async(data) => {
console.log('渡ってきたデータ:', data);
};
// ビュー部分
return(
<div>
<div className={ Schedule.schedule }>
<form className={ Schedule.schedule__form }
onSubmit={ handleInputSubmit }
>
以下省略
{/* 機能コンポーネントにフォームデータをまとめて渡す */}
<FeatureOfForm formData={ scheduleFormData } handleAddEvent={ handleAddEvent } submitEvent={ submitEvent } />
</form>
</div>
</div>
);
};
export default ScheduleForm;
import React, { useState } from 'react';
import Schedule from "../scss/schedule.module.scss";
import { postFormData } from './Feature';
const ScheduleForm = ({ passToResponseData }) => {
// フォームデータ変数定義
const [scheduleFormData, setScheduleFormData] = useState({
date: '',
requirement: '',
memo: '',
});
// 入力内容の反映
const handleChange = (event) => {
const { name, value } = event.target;
setScheduleFormData({ ...scheduleFormData, [name]: value});
};
// Feature.jsxにあるpostFormData()を呼び出す
const handleInputSubmit = async(event) => {
event.preventDefault();
// csrfトークン取得
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
// responseに、バックエンドからのレスポンスが代入される
const response = await postFormData({
csrfToken,
data: scheduleFormData,
});
if(response !=null) {
console.log('渡ってきたデータ:', response);
await passToResponseData(response);
} else {
console.log('データがありません');
}
};
return(
<div>
<div className={ Schedule.schedule }>
<form className={ Schedule.schedule__form }
onSubmit={ handleInputSubmit }
>
<label className={ Schedule.schedule__label }>
日付:
<input type="date"
name="date"
placeholder="日付の選択をしてください"
className={ Schedule.schedule__content }
onChange={ handleChange }
/>
</label>
<label className={ Schedule.schedule__label }>
要件:
<input type="text"
name="requirement"
placeholder="内容を入力してください"
className={ Schedule.schedule__content }
onChange={ handleChange }
/>
</label>
<label className={ Schedule.schedule__label }>
メモ:
<textarea className={ Schedule.schedule__content }
name="memo"
onChange={ handleChange }
>
</textarea>
</label>
<div>
<input type="submit"
value="作成"
/>
</div>
</form>
</div>
</div>
);
};
export default ScheduleForm;
修正点
・propsで値のやり取りせず、機能コンポーネント内の関数を呼び出す
const FeatureOfForm = ({ formData, handleAddEvent, submitEvent }) => {
// レスポンスデータを格納する変数定義
const [updateEvents, setUpdateEvents] = useState('');
// csrfトークン取得
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
// APIルート
const scheduleApiUrl = '/api/schedule';
// フォームデータの送信・レスポンスの取得
const handleSubmit = async() => {
try {
const response = await fetch(scheduleApiUrl, {
method: 'POST',
headers: {
'CONTENT-TYPE': 'application/json',
'X-CSRF-TOKEN': csrfToken,
},
body: JSON.stringify(formData)
});
if(!response.ok) {
throw new Error('エラーが出ました');
}
const data = await response.json();
setUpdateEvents(data);
// 子(Schedule.jsx)コンポーネントの関数を使用する
handleAddEvent(data);
} catch(error) {
console.log(error);
}
};
// Schedule.jsxで送信イベントが行われた場合のみ、バックエンドとのやり取りを行う
useEffect(() => {
handleSubmit(formData);
}, [submitEvent]);
};
export default FeatureOfForm;
// APIルート
const scheduleApiUrl = '/api/schedule';
// フォームデータの送信・レスポンスの取得
export const postFormData = async({ csrfToken, data }) => {
try {
const response = await fetch(scheduleApiUrl, {
method: 'POST',
headers: {
'CONTENT-TYPE': 'application/json',
'X-CSRF-TOKEN': csrfToken,
},
body: JSON.stringify(data)
});
if(!response.ok) {
throw new Error('エラーが出ました');
};
return response.json();
} catch(error) {
console.log(error);
return undefined;
};
};
修正点
・propsのやり取りがなくなったので、余計な変数が無くなる
②フォームコンポーネントからメインコンポーネントにデータを渡す
const ScheduleForm = ({ passToResponseData }) => {
省略
const handleInputSubmit = async(event) => {
event.preventDefault();
// csrfトークン取得
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
// responseに、バックエンドからのレスポンスが代入される
const response = await postFormData({
csrfToken,
data: scheduleFormData,
});
if(response !=null) {
console.log('渡ってきたデータ:', response);
await passToResponseData(response);
} else {
console.log('データがありません');
}
};
省略
メインコンポーネント(親)のpassToResponseDataを使用し、レスポンスデータを渡す。
const CalenderUserPage = React.memo(function() {
省略
// Schedule.jsxから値が返ってくるので取得・更新し、フォームを閉じる
const [responseViewData, setResponseViewData] = useState(null);
const passToResponseData = async(data) => {
setResponseViewData(data);
setOpenForm(!openForm);
};
省略
{/* 取得したデータを反映させる */}
<div className={ Calender.calender__content }>
{ responseViewData && (
<p className={ Calender.calender__detail }>{ responseViewData.validate.requirement }</p>
)}
</div>
省略
{/* 予定作成フォームコンポーネントの呼び出し */}
<div>
<button className={ Calender.calender__btn }
onClick={ handleClick }
>+
</button>
{ openForm && <ScheduleForm passToResponseData={ passToResponseData } />}
</div>
};
フォームコンポーネントから渡ってきた値を変数にセットし、ビューに反映させる。
useEffectで処理の呼び出しを記述していましたが、呼び出すタイミングなど自分でも分からなくなっていたので、本当に使用する必要があるのか?とこれからはよく考えて記述しようと思います。
※コメントくださった方、ありがとうございました。