前回までの記事 アプリ開発を楽しむ【#1:アプリの概要】 アプリ開発を楽しむ【#2:環境構築1(React+TypeScript)】 アプリ開発を楽しむ【#3:環境構築2 (ESLint+Prettier)】 アプリ開発を楽しむ【#4:ヘッダー】 アプリ開発を楽しむ【#5:MyTogoList】 アプリ開発を楽しむ【#6:Reduxで状態管理1】 アプリ開発を楽しむ【#7:Reduxで状態管理2】 アプリ開発を楽しむ【#8:Google Map API】 アプリ開発を楽しむ【#9:新規追加モーダルUI(togo)】 アプリ開発を楽しむ【#10:Google Mapから座標を取得】 アプリ開発を楽しむ【#11:Togoの追加】 アプリ開発を楽しむ【#12:Togoの編集1】

今回は、UpdateTogoModalをつくってきいきます。

1.StoreのtogoListの更新処理

frontend/app/src/redux/togoSlice.tsにtogoListを更新する処理を追記します。

~~~省略~~~

    addTogo(state: TogoState, action: PayloadAction<Togo>) {
      state.togoList = [...state.togoList, action.payload];
    },

    // ここから追加
    updateTogo(state: TogoState, action: PayloadAction<Togo>) {
      state.togoList = state.togoList.map((togo) => {
        if (togo.id === action.payload.id) {
          togo = {
            ...togo,
            ...action.payload,
          };
        }
        return togo;
      });
    },
    // ここまで追加

  },
});

// ここから修正
export const { getTogoList, updateTogoDone, deleteTogo, AddTogo, updateTogo } = togoSlice.actions;
// ここまで修正

2.UpdateTogoModal.tsxの作成

frontend/app/src/components/togo/UpdaetTogoModal.tsxを次のようにつくります。

import React, { useState, useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { Button, Dialog, DialogActions, DialogTitle } from '@mui/material';
import TogoForm from './TogoForm';
import { AppDispatch } from '../../redux/store';
import { updateTogo } from '../../redux/togoSlice';
import type { MapPosition } from '../../types/map';
import type { Togo } from '../../types/togo';

type UpdateTogoModalProps = {
  togoData: Togo;
  isOpenUpdateTogoModal: boolean;
  handleCloseUpdateTogoModal: () => void;
};

const UpdateTogoModal: React.FC<UpdateTogoModalProps> = ({
  togoData,
  isOpenUpdateTogoModal,
  handleCloseUpdateTogoModal,
}) => {
  const dispatch: AppDispatch = useDispatch();

  const [mapCenterPosition, setMapCenterPosition] = useState<MapPosition>(togoData.position);

  const [location, setLocation] = useState<string>(togoData.location);
  const [tag, setTag] = useState<string>(togoData.tag);
  const [mapMarkerPosition, setMapMarkerPosition] = useState<MapPosition>(togoData.position);

  const initializeTogoState = (isOpen: boolean) => {
    if (isOpen) {
      setLocation(togoData.location);
      setTag(togoData.tag);
      setMapMarkerPosition(togoData.position);
      setMapCenterPosition(togoData.position);
    }
  };

  useEffect(() => {
    initializeTogoState(isOpenUpdateTogoModal);
  }, [isOpenUpdateTogoModal]);

  const handleChangeLocation = (e: React.ChangeEvent<HTMLInputElement>) => {
    setLocation(e.target.value);
  };

  const handleChangeTag = (e: React.ChangeEvent<HTMLInputElement>) => {
    setTag(e.target.value);
  };

  const handleChangeMapMarkerPosition = (position: MapPosition) => {
    setMapMarkerPosition(position);
  };

  const handleChangeMapCenterPosition = (position: MapPosition) => {
    setMapCenterPosition(position);
  };

  const handleUpdateTogo = () => {
    if (!location || !tag) {
      return;
    }
    const updateTogoData: Togo = {
      id: togoData.id,
      done: togoData.done,
      location,
      tag,
      position: mapMarkerPosition,
    };
    dispatch(updateTogo(updateTogoData));
    handleCloseUpdateTogoModal();
  };

  return (
    <Dialog
      open={isOpenUpdateTogoModal}
      onClose={handleCloseUpdateTogoModal}
      fullWidth
      maxWidth="md"
    >
      <DialogTitle>TOGOの編集</DialogTitle>
      <TogoForm
        location={location}
        tag={tag}
        mapCenterPosition={mapCenterPosition}
        mapMarkerPosition={mapMarkerPosition}
        handleChangeLocation={handleChangeLocation}
        handleChangeTag={handleChangeTag}
        handleChangeMapMarkerPosition={handleChangeMapMarkerPosition}
        handleChangeMapCenterPosition={handleChangeMapCenterPosition}
      />
      <DialogActions sx={{ mb: 1, ml: 2, display: 'flex', justifyContent: 'flex-start' }}>
        <Button variant="contained" onClick={handleUpdateTogo}>
          編集
        </Button>
        <Button variant="outlined" onClick={handleCloseUpdateTogoModal}>
          キャンセル
        </Button>
      </DialogActions>
    </Dialog>
  );
};

export default UpdateTogoModal;

AddTogoModal.tsxとほぼ同じ内容となります。 AddTogoModalと異なる点は、

  • isOpenUpdateTogoModalのprops名
  • handleCloseUpdateTogoModalのprops名
  • handleAddTogoのメソッドをhandleUpdateTogoに変更しその処理内容
  • 登録ボタンを編集ボタンに変更とそのクリックイベントのメソッド名
  • storeからtogoListの取得をしていない

3.MyTogoListの修正

といっても、UpdaetTogoModalをimportするだけです。

import { getTogoList, updateTogoDone, deleteTogo, initialState } from '../../redux/togoSlice';
import AddTogoModal from './AddTogoModal';

// ここから追加
import UpdateTogoModal from './UpdateTogoModal';
// ここまで追加

import sampleTogoList from '../../sampleData/togo';
import type { Togo } from '../../types/togo';

これで、変更できるようになりました。

今回はここまでです。 次回は、AddTogoModalとUpdateTogoModalをカスタムフックを使って、もう少しコードをすっきりさせたいと思います。

コードはGitHubに置いてありますのでよければ参考にしてください。 mainブランチは常に最新のものになります。 今回の内容はblog_13のブランチを参照してください。 https://github.com/KINE-M/togo_app