0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

reactでpropsを使用し、データの受け渡しを行う

Last updated at Posted at 2023-11-17

はじめに

個人開発メモ📝
(11/19更新)

今回の課題

コンポーネント間で役割を分けたので、データの受け渡しや処理の呼び出しを行えるようにする。

データの受け渡し設計と役割分担

メインコンポーネント⇨ ビューとフォームページの呼び出し
フォームコンポーネント⇨ フォーム入力、送信
機能コンポーネント⇨ バックエンドとのやり取り

(親)メインコンポーネント

カレンダーを表示し、フォームコンポーネントを呼び出す
フォームコンポーネントからレスポンスデータを受け取り、ビューに表示

  ⬆︎ (データを渡す)

(子)フォームコンポーネント

入力されたフォームデータを収集し、機能コンポーネントに渡す

  ⬇︎ (処理の呼び出し)

機能用コンポーネント

バックエンドとのリクエスト・レスポンスのやり取り

①フォーム送信イベント内で、別のコンポーネントの関数を呼び出す

※修正前 schedule.jsx(フォームコンポーネント)
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;
※修正後schedule.jsxx
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で値のやり取りせず、機能コンポーネント内の関数を呼び出す

※修正前 Feature.jsx(機能コンポーネント)
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;
※修正後 Feature.jsx
// 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のやり取りがなくなったので、余計な変数が無くなる

②フォームコンポーネントからメインコンポーネントにデータを渡す

Schedule.jsx (該当部分のみ)
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を使用し、レスポンスデータを渡す。

Calender.jsx (該当部分のみ)
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で処理の呼び出しを記述していましたが、呼び出すタイミングなど自分でも分からなくなっていたので、本当に使用する必要があるのか?とこれからはよく考えて記述しようと思います。
※コメントくださった方、ありがとうございました。

0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?