为什么在不同组件中渲染列表不适用于材质UI提供的“选择”组件?

Why does Rendering the List in a Different component doesn't work with `Select` Component provided by material UI?

提问人:Gaurav Rajput 提问时间:11/12/2023 更新时间:11/12/2023 访问量:39

问:

我写了两个组件。一个用于渲染列表,该列表在其托管 Material UI 提供的组件的父组件中使用。 两者的片段如下。Select

import React from 'react';
import './index.css';
import { LMFeedTopics } from '@likeminds.community/feed-js-beta';
import { Checkbox, MenuItem } from '@mui/material';
interface TopicListProps {
  list: LMFeedTopics[];
  checkedList: string[];
}
const TopicList = ({ list, checkedList }: TopicListProps) => {
  return (
    <>
      {list.map((topic: LMFeedTopics) => {
        return (
          <MenuItem key={topic.Id} value={topic.Id} role="option">
            <div className="topicTile">
              <Checkbox checked={checkedList.includes(topic.Id)} />
              <span>{topic.name}</span>
            </div>
          </MenuItem>
        );
      })}
    </>
  );
};

export default TopicList;

Parent 组件是

import React, { useCallback, useEffect, useState } from 'react';
import './index.css';
import { LMFeedTopics } from '@likeminds.community/feed-js-beta';
import { lmFeedClient } from '../../..';
import { Checkbox, FormControl, MenuItem, Select } from '@mui/material';
import TopicList from '../topic-list';

interface TopicFeedDropdownSelectorProps {}

const TopicFeedDropdownSelector = () => {
  const [topicList, setTopicList] = useState<any[]>([]);
  const [checkedTopicList, setCheckedTopicList] = useState<string[]>([]);
  const [page, setPage] = useState<number>(1);
  const [searchKey, setSearchKey] = useState<string>('');
  const getData = useCallback(async () => {
    // Used go get some data with an API call.
  }, [page, searchKey]);
  useEffect(() => {
    getData();
  }, []);
  return (
    <div>
      <Select
        multiple={true}
        IconComponent={() => (
          <svg
            width="12"
            height="16"
            viewBox="0 0 12 16"
            fill="none"
            xmlns="http://www.w3.org/2000/svg">
            <path
              d="M6.52567 15.7821L11.287 11.0208C11.5775 10.7303 11.5775 10.2591 11.287 9.96863C10.9964 9.67807 10.5254 9.67807 10.2349 9.96863L6.74356 13.4599L6.74356 0.743959C6.74356 0.333115 6.41044 0 5.9996 0C5.58882 0 5.25564 0.333115 5.25564 0.743959L5.25564 13.4599L1.76433 9.96875C1.47377 9.67819 1.00275 9.67819 0.712193 9.96875C0.567032 10.114 0.494303 10.3044 0.494303 10.4948C0.494303 10.6852 0.567032 10.8756 0.712193 11.0209L5.47353 15.7821C5.76409 16.0727 6.23511 16.0727 6.52567 15.7821Z"
              fill="#666666"
            />
          </svg>
        )}
        value={checkedTopicList}
        onChange={(e: any) => {
          console.log(e);
        }}>
        <TopicList list={topicList} checkedList={checkedTopicList} />
      </Select>
    </div>
  );
};

export default TopicFeedDropdownSelector;

问题是,只要列表在内部呈现,onChange 函数就不会被触发,但是如果我在父组件中编写逻辑,它就像一个魅力。

为什么会这样,我希望列表在不同的组件中单独呈现,我怎样才能实现?

reactjs material-ui 下拉菜单

评论


答:

0赞 Viiiinie 11/12/2023 #1

我不是 react 的专家,但我认为你必须将输入从渲染函数中剔除,因为你收集数据并且这些数据一次又一次地被重置。您必须创建一个静态组件。 希望能帮到你OnChange

评论

0赞 Gaurav Rajput 11/12/2023
不,我认为不是这样。
1赞 Obydul Islam Khan 11/12/2023 #2

如果您阅读 MUI Select children props 说明,则表示当 native 为 false 时,MenuItem 元素必须是直接后代。 (附截图)在此处输入图像描述

此外,最好为列表项创建组件,而不是为整个列表创建组件。 前任。

<Select
      multiple={true}
      IconComponent={() => (
        <svg
          width="12"
          height="16"
          viewBox="0 0 12 16"
          fill="none"
          xmlns="http://www.w3.org/2000/svg">
          <path
            d="M6.52567 15.7821L11.287 11.0208C11.5775 10.7303 11.5775 10.2591 11.287 9.96863C10.9964 9.67807 10.5254 9.67807 10.2349 9.96863L6.74356 13.4599L6.74356 0.743959C6.74356 0.333115 6.41044 0 5.9996 0C5.58882 0 5.25564 0.333115 5.25564 0.743959L5.25564 13.4599L1.76433 9.96875C1.47377 9.67819 1.00275 9.67819 0.712193 9.96875C0.567032 10.114 0.494303 10.3044 0.494303 10.4948C0.494303 10.6852 0.567032 10.8756 0.712193 11.0209L5.47353 15.7821C5.76409 16.0727 6.23511 16.0727 6.52567 15.7821Z"
            fill="#666666"
          />
        </svg>
      )}
      value={checkedTopicList}
      onChange={(e) => {
        console.log(e.target.value);
        setCheckedTopicList(e.target.value)
      }}>
      {
        topicList.map((topic) => <MenuItem key={topic.id} value={topic.id} role="option">
            <TopicItem name={topic.name} id={topic.id} checkedList={checkedTopicList} />
        </MenuItem>)
      }
    </Select>

TopicItem Component:

function TopicItem({id, name, checkedList}) {
return (
    <div className="topicTile">
        <Checkbox checked={checkedList.includes(id)} />
        <span>{name}</span>
    </div>
)}

Another Way:

const options = useMemo(() => {
    return topicList.map((topic) => <MenuItem key={topic.id} value={topic.id} role="option">
        <div className="topicTile">
        <Checkbox checked={checkedTopicList.includes(topic.id)} />
        <span>{topic.name}</span>
        </div>
    </MenuItem>)
}, [topicList, checkedTopicList])

And implement Select like below:

<Select
      multiple={true}
      IconComponent={() => (
        <svg
          width="12"
          height="16"
          viewBox="0 0 12 16"
          fill="none"
          xmlns="http://www.w3.org/2000/svg">
          <path
            d="M6.52567 15.7821L11.287 11.0208C11.5775 10.7303 11.5775 10.2591 11.287 9.96863C10.9964 9.67807 10.5254 9.67807 10.2349 9.96863L6.74356 13.4599L6.74356 0.743959C6.74356 0.333115 6.41044 0 5.9996 0C5.58882 0 5.25564 0.333115 5.25564 0.743959L5.25564 13.4599L1.76433 9.96875C1.47377 9.67819 1.00275 9.67819 0.712193 9.96875C0.567032 10.114 0.494303 10.3044 0.494303 10.4948C0.494303 10.6852 0.567032 10.8756 0.712193 11.0209L5.47353 15.7821C5.76409 16.0727 6.23511 16.0727 6.52567 15.7821Z"
            fill="#666666"
          />
        </svg>
      )}
      value={checkedTopicList}
      onChange={(e) => {
        console.log(e.target.value);
        setCheckedTopicList(e.target.value)
      }}>
      {options}
    </Select>

I hope this helps you understand how MUI Select works. Let me know if you have any questions.