💭
MUIのAutoCompleteの候補に過去に入力した値を表示する
検証環境
- mui v6.3.1
- react v18.3.1
MUI Autocompleteの基本的な使い方
オプションを配列で渡してあげるとAutoCompleteの候補として表示してくれます。
FormSample.tsx
export const FormSample = (): JSX.Element => {
const SubmitButton = styled(Button)<ButtonProps>(() => ({
"&:hover": {
backgroundColor: [700],
},
}));
return (
<>
<Box>
<Typography variant="h4" textAlign={"center"} mb={"24px"}>
Form Sample
</Typography>
<Autocomplete
disablePortal
options={[
"The Shawshank Redemption",
"The Godfather",
"The Dark Knight",
]}
sx={{ width: 300 }}
renderInput={(params: any) => <TextField {...params} label="Movie" />}
/>
<SubmitButton
variant="contained"
sx={{ marginTop: 4 }}
onClick={() => {}}
>
登録
</SubmitButton>
</Box>
</>
);
};
実現したいこと
AutoCompleteの候補に過去に入力したInput内容を表示したい。
方法
LocalStorageを利用し、過去のInput履歴を保存、取得する方法を考えました。
- 検索実装ボタンが押下された際にInput内容をLocalStorageにPush
- 検索画面を表示し直した際にInputの履歴を取得し、動的にAutoCompleteの候補に渡す
実装
以下のようにコードを修正しました。
- MovieSearchHistoryというキーを設定。このキーでLocalStorageの内容を取得したり更新したりします
- useEffectでLocalStorageのMovieSearchHistoryに紐づくデータを取得し、配列に変換してAutocompleteのoptionsに設定
- 検索ボタン押下時にuseEffectで取得したデータの配列にinputの入力値を追加。同時に重複チェックと件数チェック(ここではLocalStorageに保持する履歴はMax3件としています)を行い、LocalStorageのMovieSearchHistoryを更新する
- [リファクタリング]データ取得などのロジックとビューを切り分けました。
コンポーネント全体
FormSample.tsx
import {
Autocomplete,
Box,
Button,
type ButtonProps,
TextField,
Typography,
styled,
} from "@mui/material";
import { useEffect, useState } from "react";
interface FormSampleProps {
options: string[];
pushLocalStorage: () => void;
inputValue: string;
setInputValue: (value: string) => void;
}
const FormSampleProvider = ({
options,
pushLocalStorage,
setInputValue,
inputValue,
}: FormSampleProps): JSX.Element => {
const SubmitButton = styled(Button)<ButtonProps>(() => ({
"&:hover": {
backgroundColor: [700],
},
}));
return (
<>
<Box>
<Typography variant="h4" textAlign={"center"} mb={"24px"}>
Form Sample
</Typography>
<Autocomplete
freeSolo
sx={{ width: 300 }}
autoComplete={true}
options={options}
inputValue={inputValue}
onInputChange={(_event, newInputValue) =>
setInputValue(newInputValue)
}
renderInput={(params) => <TextField {...params} label="Movie" />}
/>
<SubmitButton
variant="contained"
sx={{ marginTop: 4 }}
onClick={() => {
pushLocalStorage();
}}
>
登録
</SubmitButton>
</Box>
</>
);
};
export const FormSample = (): JSX.Element => {
const [inputValue, setInputValue] = useState("");
const [options, setOptions] = useState<string[]>([]);
// LocalStorageのキー
const LOCAL_STORAGE_KEY = "MovieSearchHistory";
// LocalStorageから履歴を取得
useEffect(() => {
const storedHistory = localStorage.getItem(LOCAL_STORAGE_KEY);
if (storedHistory) {
setOptions(JSON.parse(storedHistory));
}
}, []);
// 検索実行ボタンのクリック時に履歴を更新
const pushLocalStorage = () => {
if (!inputValue.trim()) return;
const updatedHistory = [...new Set([inputValue, ...options])].slice(0, 3); // 重複を排除し最大3件まで
setOptions(updatedHistory);
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(updatedHistory));
};
return (
<FormSampleProvider
options={options}
pushLocalStorage={pushLocalStorage}
inputValue={inputValue}
setInputValue={setInputValue}
/>
);
};
Discussion