Search code examples
reactjslistmenurenderrerender

Why I can not re-render a component when click on Menu item sort


This is my code, I have a list Contacts to render view ListContact, in that view, I have Menu sort have 2 item: "Tên(A-Z)" to inscrease and "Tên(Z-A)" to descrease and list.map. Why I can not re-render that view when click on Menu item sort. I tried to use UseState and UseEffect but it not work. I use menu of @headlessui/react.

function ViewListFriend() {

    const [contacts, setContacts] = useState([....]);

    contacts.sort((a, b) => a.name.localeCompare(b.name));
    const [selectedOptionName, setSelectedOptionName] = useState('ins');

    useEffect(() => {
        // const sortedContacts = [...contacts].sort((a, b) => {
        //     if (selectedOptionName === 'ins') {
        //         return a.name.localeCompare(b.name);
        //     } else {
        //         return b.name.localeCompare(a.name);
        //     }
        // });
        // setContacts(sortedContacts);
    }, [selectedOptionName]);

    function ListContact({ list }) {
        return (

            <Menu as="div">
                <div>
                    <Menu.Button>
                        <p>{selectedOptionName === 'ins' ? 'Tên(A-Z)' : 'Tên (Z-A)'}</p>
                    </Menu.Button>
                </div>
                <Menu.Items>
                    <div>
                        <Menu.Item>
                            {({ active }) => (
                                <button
                                    onClick={() => {
                                        setSelectedOptionName('ins')
                                        const sortedContacts = [...contacts].sort((a, b) => a.name.localeCompare(b.name));
                                        setContacts(sortedContacts);
                                    }}>
                                    Tên (A-Z)
                                </button>
                            )}
                        </Menu.Item>
                        <Menu.Item>
                            {({ active }) => (
                                <button
                                    onClick={() => {
                                        setSelectedOptionName('des')
                                        const sortedContacts = [...contacts].sort((b, a) => a.name.localeCompare(b.name));
                                        setContacts(sortedContacts);
                                    }}>
                                    Tên (Z-A)
                                </button>
                            )}
                        </Menu.Item>
                    </div>
                </Menu.Items>
            </Menu>    

            {
            list.map(item => (
                ...render item
            ))
        }
        </div >
    )
    }

    return (
        <div className="flex flex-1 flex-col">
            <ListContact list={contacts} />
        </div>
    )
}
export default ViewListFriend;

How to render a view when click on Menu item.


Solution

  • In your code. The reason why the sort function does not work is every time you click on sort button Tên (A-Z) or Tên (Z-A)

    The component will rerender and this line will run again

    contacts.sort((a, b) => a.name.localeCompare(b.name));

    and the result will always be affected by the first sorted

    Try this

    import React, { useState } from 'react';
    
    
    export function App(props) {
      const [contacts, setContacts] = useState([{ name: "b" }, { name: "a" }, { name: "c" }]);
      const [selectedOptionName, setSelectedOptionName] = useState('ins');
    
      function ListContact({ list }) {
        return (
          <div>
            <div>
              <div>
                <button>
                  <p>{selectedOptionName === 'ins' ? 'Tên(A-Z)' : 'Tên (Z-A)'}</p>
                </button>
              </div>
              <div>
                <div>
                  <div>
                    <button
                      onClick={() => {
                        setSelectedOptionName('ins')
                        const sortedContacts = [...contacts].sort((a, b) => a.name.localeCompare(b.name));
                        setContacts(sortedContacts);
                      }}>
                      Tên (A-Z)
                    </button>
                  </div>
                  <div>
                    <button
                      onClick={() => {
                        setSelectedOptionName('des')
                        const sortedContacts = [...contacts].sort((b, a) => a.name.localeCompare(b.name));
                        setContacts(sortedContacts);
                      }}>
                      Tên (Z-A)
                    </button>
                  </div>
                </div>
              </div>
            </div>
            {list.map((item, index) => <p key={index} style={{ color: 'red' }}>{item.name}</p>)}
          </div>
        )
      }
    
      return (
        <div className="flex flex-1 flex-col">
          <ListContact list={contacts} />
        </div>
      );
    }