🐕

【React+Material UI】画像アップロード機能実装方法

2021/09/29に公開

概要

画像をアップロードする機能の実装方法について説明します。

サンプルコード

下記がサンプルコードになります。

まず、画像アップロードボタンを定義します。
仕組みは下記のようになっています。
<input>をcssで見えないようにする。
<label>htmlFor<input>と紐づけをする。
上記の結果、疑似的にボタンを押すとファイル選択画面が表示されるという仕組みになっています。

const useUploadButtonStyles = makeStyles((theme) =>
  createStyles({
    input: {
      display: 'none',
    },
  })
);
export const UploadButton = (props) => {
  const classes = useUploadButtonStyles();
  return (
    <label htmlFor={`upload-button-${props.name}`}>
      <input
        accept="image/*"
        className={classes.input}
        id={`upload-button-${props.name}`}
        name={props.name}
        multiple
        type="file"
        onChange={props.onChange}
      />
      <Button variant="contained" component="span" {...props}>
        {props.children}
      </Button>
      </label>
  );
};

<input>をcssで見えないようにする。

    input: {
      display: 'none',
    },

cssdisplay:'none'にすることで画面から表示されないようになります。

<label>htmlFor<input>と紐づけをする。

    <label htmlFor={`upload-button-${props.name}`}>
      <input
        accept="image/*"
        className={classes.input}
        id={`upload-button-${props.name}`}
        name={props.name}
        multiple
        type="file"
        onChange={props.onChange}
      />
      <Button variant="contained" component="span" {...props}>
        {props.children}
      </Button>
    </label>

<label>htmlFor<input>idが同じになるように設定するのがポイントです。
こうすることでボタンが押される(≒labelが押される)ファイル選択画面が表示されるようになります。

使い方

const Example = () => {
  const [postFileData, setPostFileData] = useState({})
  const changeUploadFile = async (event) => {
    const { name, files } = event.target;
    setPostFileData({
      ...postFileData,
      [name]: files[0],
    });
    event.target.value = '';
  };
return (
  <UploadButton
    className="primary"
    name="image"
    onChange={changeUploadFile}
  >
    アップロード
  </UploadButton>
)
}

上記が実際のアップロードボタンのコードになります。
ファイルがアップロードされるとchangeUploadFileが発火します。
changeUploadFileの処理内容について説明します。
file[0]にアップロードされた画像が入っています。
下記の行がないと同じファイル名のファイルをアップロードした時にonChangeイベントが発火されません。下記の行を追加することで同じファイル名のファイルをアップロードしても再度値をセットしなおされるようになります。

event.target.value = '';

送信方法

送信にはFormDataを使います。appendメソッドを使ってファイルを詰めてaxiosで送信します。

const formData = new FormData();
postData.append(
    'image',
    postFileData.image ? postFileData.image : ''
);
const response = axios.post('/image/store', params, {
    headers: {
      'Content-Type': 'multipart/form-data',
    },
});

更新の場合の注意点

更新の場合は注意が必要です。PUTメソッドで送ろうとするとこれはできません。

const response = axios.put('/image/update', params, {
    headers: {
      'Content-Type': 'multipart/form-data',
    },
});

下記のようにしないと送ることができません。注意してください。

postData.append('_method', 'PUT');
const response = axios.post('/image/update', params, {
    headers: {
      'Content-Type': 'multipart/form-data',
    },
});

以上です。読んでいただきありがとうございました。
誤字、脱字、間違い等ありましたらコメント頂ければ幸いです。

Discussion