skip to Main Content

I have written two component. One for rendering a list which is used inside it’s parent component hosting the Select component provided by Material UI.
THe snippets for the both are below.

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;

The Parent component is

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;

The problem is that the onChange function isn’t getting triggered as long as the list is being rendered inside but if i write the logic inside the parent component it works like a charm.

Why is it so, I want the list to get rendered separately in different component, how can i achieve so?

2

Answers


  1. I am not a pro in react but I think you have to put the input OnChange out of the render function because you collect data and these data were been reset again and again. You have to create a static component.
    I hope that I help you

    Login or Signup to reply.
  2. If you read the MUI Select children props description, it is saying that The MenuItem elements must be direct descendants when native is false. (attaching Screenshot)
    enter image description here

    Also it is better to create a component for List Item instead of the whole List.
    Ex.

    <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>
    

    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 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search