iT邦幫忙

0

( 已解決 ) react-select / asyncSelect 動態改變選項

  • 分享至 

  • xImage
  • 2023-07-21 更新 / 感謝 @alien663 提點 問題已解決

  • 2023-07-17 更新 / 附上完整程式

各位好 最近剛學 react 配合 react-select 套件

一些需求

  • 選擇部門後更新人員選項
  • 因為用公司做好的 api 來拿到名單所以用 asyncSelect

目前頁面長這樣:
目前頁面

code

npm

  • react: ^18.2.0
  • react-select: ^5.7.3

結構部分

結構

function

part-1
part-2

問題來了

我選了部門之後,改變了 state 拿到了正確的人員選項,但我的select 拿到正確 function 卻沒有更新成正確選項

結果圖

log狀態
console.log

補充說明
隨意打個字(就算不在選項內),他就會顯示正確選項了,但刪掉又會不見...
怪東西
爬了很多文章好像是說,套件內部會用 inputValue 做 filter,那我要怎麼在不打字的情況正確顯示啊

可以請問這是為什麼,還有要怎麼解決嗎

第一次發問,盡量把問題打清楚了,如果還有缺什麼資訊,可以跟我反應,感謝各位


補充完整程式碼

import { Main } from "@/layouts/main";
import AsyncSelect from "react-select/async";
import { useCallback, useMemo, useState } from "react";

const QAQ = () => {
  console.count("render");
  // ! 設定 dept state
  const [dept, setDept] = useState<string>("0");
  console.log({ dept });

  // ! 員工清單
  const employee = useMemo(
    () => [
      { name: "a", dept: "1" },
      { name: "b", dept: "1" },
      { name: "c", dept: "2" },
      { name: "d", dept: "2" },
      { name: "x", dept: "3" },
      { name: "y", dept: "3" },
      { name: "z", dept: "3" },
    ],
    []
  );

  // ! fetch 部門的選項
  async function getDeptOptions() {
    return new Promise((resolve) => {
      resolve([
        { label: "dept-1", value: "1" },
        { label: "dept-2", value: "2" },
        { label: "dept-3", value: "3" },
      ]);
    });
  }

  // ! filter 人員的公司 拿到正確的名單
  const getDeptEmployee = useCallback(
    function (dept: string) {
      const empInThisDept = employee.filter((e) => e.dept === dept);

      return empInThisDept.map((i) => {
        return { label: i.name, value: i.name };
      });
    },
    [employee]
  );

  // ! fetch 人員的選項
  const getEmpOptions = useCallback(
    async function () {
      return new Promise((resolve, reject) => {
        resolve(getDeptEmployee(dept));
      });
    },
    [dept, getDeptEmployee]
  );
  console.log("options", getEmpOptions());

  // ! 選了部門改變 state
  function handleChange(d: { label: string; value: string }) {
    console.log(d);
    setDept(d.value);
  }
  return (
    <Main>
      <div className='flex items-center gap-4'>
        部門
        <AsyncSelect
          defaultOptions
          loadOptions={getDeptOptions as any}
          onChange={handleChange as any}
          autoFocus
          openMenuOnFocus
        />
        人員
        <AsyncSelect
          defaultOptions
          loadOptions={getEmpOptions as any}
          autoFocus
          openMenuOnFocus
        />
      </div>
    </Main>
  );
};

圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 個回答

1
alien663
iT邦研究生 5 級 ‧ 2023-07-17 08:44:41

https://ithelp.ithome.com.tw/upload/images/20230717/201539827cjeRtXMO1.jpg

WinnieS iT邦新手 5 級 ‧ 2023-07-17 11:04:38 檢舉

感謝 馬上更新!!

alien663 iT邦研究生 5 級 ‧ 2023-07-20 10:23:18 檢舉

最近終於有時間幫你看了。
問題很簡單,你第一層select的handleChange沒有觸發第二層Select的行為,所以只有在輸入input時才會去Load第二層的資料。

其實這樣,不如在選擇第一層資料時就把第二層資料選擇好,一併送到Component裡面,以下是我修改完的結果。

import AsyncSelect from "react-select/async";
import { useMemo, useState } from "react";

const DoubleSelect = (props) => {
    const { handleChange, loadLV1Options, LV2Options } = props
    return (
        <div className='flex items-center gap-4'>
            部門
            <AsyncSelect
                defaultOptions
                loadOptions={loadLV1Options}
                onChange={handleChange}
                autoFocus
                openMenuOnFocus
            />
            人員
            <AsyncSelect
                defaultOptions = {LV2Options}
                autoFocus
                openMenuOnFocus
            />
        </div>
    );
};

const QAQ = () => {
    const [dept, setDept] = useState("0");
    const [emp, setEmp] = useState([])
    // ! 員工清單
    const employee = useMemo(
        () => [
            { name: "a", dept: "1" },
            { name: "b", dept: "1" },
            { name: "c", dept: "2" },
            { name: "d", dept: "2" },
            { name: "x", dept: "3" },
            { name: "y", dept: "3" },
            { name: "z", dept: "3" },
        ],[]
    );

    // ! fetch 部門的選項
    const  getDeptOptions = async () => {
        return new Promise((resolve) => {
            resolve([
                { label: "dept-1", value: "1" },
                { label: "dept-2", value: "2" },
                { label: "dept-3", value: "3" },
            ]);
        });
    }

    const getEmpOptions = async (__value) => {
        const empInThisDept = employee.filter((e) => e.dept === __value);
        return new Promise((resolve, reject) => {
            resolve(
                empInThisDept.map(item => {
                    return {label: item.name, value: item.name }
                })
            )
        })
    }

    const handleChangeL1Select = (d) => {
        setDept(d)
        getEmpOptions(d.value)
            .then(res => {
                setEmp(res)
            }
        )
    }

    return(
        <DoubleSelect
            handleChange={handleChangeL1Select}
            loadLV1Options={getDeptOptions}
            LV2Options={emp}>
        </DoubleSelect>
    )
}

export default QAQ

WinnieS iT邦新手 5 級 ‧ 2023-07-21 11:42:04 檢舉

非常感謝 使用起來都正常了 /images/emoticon/emoticon07.gif

我要發表回答

立即登入回答