フロントを React バックエンドを PHP で作成していて、ファイルのアップロードを試してみたのでメモ
React では、<input type="file" />
は値がユーザだけが設定できるものでありプログラムでは操作できないため、常に非制御コンポーネントです。
cf. 非制御コンポーネント – React
input[type="file"]
の value はプログラムで設定できないので値は FileAPI を使って取得する必要があるトノコト。
input[type="file"]
の value は設定できないけど、onChange で選択されたファイルについては files[0]
で取得できる Fileオブジェクト を state として持つことはできるっぽい
function InputFile() {
const [file, setFile] = useState(null);
const onChangeHandler = useCallback((e) => {
const file = e.target.files[0];
setFile(() => {
return file ? file : null;
});
}, []);
return <input type="file" accept="image/*" onChange={onChangeHandler} />
}
state でファイルオブジェクトを持ってしまうので、公式リファレンスにあるように useRef を使って必要なときだけ ファイルオブジェクトを取り出すようにした方がメモリ効率は良いのかも知れない。
File を含むデータを axios で送信する
以前書いた記事 JavaScript (SPA) PHP axios でフォームデータを送る時に気をつけること - かもメモ でバックエンドの PHP で $_POST
でフォームデータを取得できるようにするには URLSearchParams
形式で送れば OK と書いていたのですが、URLSearchParams
で送った場合 $_FILES
は null
になってしまいうまく取得できませんでした。
ファイルを含むフォームデータは FormData
形式の Content-Type: 'multipart/form-data'
で送るのが良いみたいです。
フロント
function PostForm() {
const ref = useRef(null);
const onPostForm = useCallback(async(data) => {
try {
const params = new FormData();
Object.keys(data).forEach(function(key) {
params.append(key, this[key]);
}, data);
const res = await axios.post(API_URL, params, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
console.log(res);
} catch(err) {
console.log(err);
}
}, []);
const onSubmitHandler = useCallback((e) => {
e.preventDefault();
onPostForm({
file: ref.current.files[0],
});
}, [onPostForm]);
return (
<form onSubmit={onSubmitHandler}>
<input type="file" accept="image/*" ref={ref} />
{}
</form>
);
}
バックエンド (PHP)
<?php
$file = $_FILES['file'];
header('Content-Type: application/json; charset=utf-8', true, 200);
echo json_encode([
'file_name' => $file['name'],
'tmp_file' => $file['tmp_name'],
'error' => $file['error'],
], JSON_UNESCAPED_UNICODE);
FormData
形式・Content-Type: 'multipart/form-data'
で送信すれば PHP の $_FILES
で送られたファイルデータを取得することができました!
₍ ᐢ. ̫ .ᐢ ₎ ヤッタネ!!
[参考]