【React＋MUI】検索ボックス実装の例

## まずAutocompleteを使えないか検討してみる。

こんなの↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3674898/6a91e9ce-f641-d511-dbba-83bd1ca7158b.png)
[AutoComplete（MUI公式）](https://mui.com/material-ui/react-autocomplete/)

MUIはそれぞれのライブラリに豊富なサンプルコードがあるので、そちらを参考にしながら実装してみましょう。

## Autocompleteが使えそうにない場合

例えば
- 入力フォームとリストを横並びにしたい
- 入力フォームに文字を入力してもリストはずっと表示しておきたい
など
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3674898/38d13efc-32ef-166b-98de-5845398374a6.png)

作りたいアプリの仕様上自作する必要がある時、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>
  )}

```

実際の動作
![検索ボックス.mp4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3674898/ba186c8f-1fc4-a427-3876-67584df29c5d.gif)

### 注意点

今回リストの中身が50件程ということもあり問題なく動作しています。
しかしリストの件数が100件、1000件…と増える場合やmapでリターンする内容がもっとリッチな場合は、onChangeをただ走らせているだけだとパフォーマンスに影響が出る恐れがあります。


 ### onChangeのパフォーマンス改善案
https://qiita.com/nakakobiz0281/items/6acecb0e29824b463fb4

https://qiita.com/nakakobiz0281/items/2cf4138dadb5a1edc7b9