まずAutocompleteを使えないか検討してみる。
こんなの↓
AutoComplete(MUI公式)
MUIはそれぞれのライブラリに豊富なサンプルコードがあるので、そちらを参考にしながら実装してみましょう。
Autocompleteが使えそうにない場合
例えば
作りたいアプリの仕様上自作する必要がある時、MUIのTextFieldとListを使って実装ができます。
参考コード
SearchBoxDemo.js
import {
Avatar,
Box,
Grid,
List,
ListItem,
ListItemAvatar,
ListItemText,
TextField,
} from "@mui/material";
import { nameListData } from "../data/NameSample";
import { useState } from "react";
export function SearchBoxDemo() {
const [nameList, setNameList] = useState(nameListData);
const filteringName = (inputValue) => {
if (inputValue) {
const filteredNames = nameListData.filter((name) =>
name.toLowerCase().includes(inputValue.toLowerCase())
);
setNameList(filteredNames);
} else {
setNameList(nameListData);
}
};
return (
<Box sx={{ display: "flex", justifyContent: "center" }}>
<Grid container spacing={2}>
<Grid item xs={2}>
<Box sx={{ height: "50vh", padding: "15px" }}>
<TextField
margin="normal"
fullWidth
onChange={(e) => filteringName(e.currentTarget.value)}
/>
</Box>
</Grid>
<Grid item xs={2}>
<Box sx={{ height: "30vh", padding: "15px", overflow: "auto" }}>
<List>
{nameList.length > 0 ? (
nameList.map((name) => (
<ListItem key={name}>
<ListItemAvatar>
<Avatar>{name.substr(0, 1)}</Avatar>
</ListItemAvatar>
<ListItemText>{name}</ListItemText>
</ListItem>
))
) : (
<ListItem>
<ListItemText>検索結果が見つかりませんでした</ListItemText>
</ListItem>
)}
</List>
</Box>
</Grid>
</Grid>
</Box>
);
}
nameListData.js
export const nameListData = [
"John Smith",
"Emily Johnson",
"Michael Williams",
"Olivia Brown",
"William Jones",
"Ava Davis",
"James Wilson",
"Emma Taylor",
"Alexander Martinez",
"Sophia Anderson",
"Daniel Thomas",
"Chloe Garcia",
"Matthew Hernandez",
"Grace Moore",
"David Martin",
"Ella Rodriguez",
"Andrew Miller",
"Madison White",
"Joseph Lee",
"Abigail Harris",
"Nicholas King",
"Samantha Clark",
"Tyler Lewis",
"Natalie Hall",
"Christopher Young",
"Lily Allen",
"Ryan Scott",
"Hannah Green",
"Brandon Walker",
"Avery Perez",
"Justin Lopes",
"Victoria Hill",
"Ethan Baker",
"Zoe Carter",
"Jonathan Nguyen",
"Mia Rivera",
"Christian Ward",
"Isabella Cooper",
"Dylan Gonzales",
"Aria Wright",
"Gabriel Torres",
"Sofia Murphy",
"Benjamin Powell",
"Aaliyah Butler",
"Samuel Long",
"Hailey Foster",
"Jackson Russell",
"Penelope Perry",
];
解説
TextFieldにテキストが入力されたらonChangeイベントが発火し、該当する要素をフィルターする。
今回の例はあいまい検索をしていますが、前方一致、後方一致、完全一致など実装に合わせて適宜.filter()の中の条件を変えて下さい。
また、テキストが何も入力されない場合は初期値をセットしてます。
SearchBoxDemo.js
const filteringName = (inputValue) => {
if (inputValue) {
const filteredNames = nameListData.filter((name) =>
name.toLowerCase().includes(inputValue.toLowerCase())
);
setNameList(filteredNames);
} else {
setNameList(nameListData);
}
};
フィルターした結果条件と一致する要素がなかった場合は検索結果が見つからないというメッセージを表示。
SearchBoxDemo.js
{nameList.length > 0 ? (
nameList.map((name) => (
<ListItem key={name}>
<ListItemAvatar>
<Avatar>{name.substr(0, 1)}</Avatar>
</ListItemAvatar>
<ListItemText>{name}</ListItemText>
</ListItem>
))
) : (
<ListItem>
<ListItemText>検索結果が見つかりませんでした</ListItemText>
</ListItem>
)}
注意点
今回リストの中身が50件程ということもあり問題なく動作しています。
しかしリストの件数が100件、1000件…と増える場合やmapでリターンする内容がもっとリッチな場合は、onChangeをただ走らせているだけだとパフォーマンスに影響が出る恐れがあります。
onChangeのパフォーマンス改善案