2

I get by props array with objects and then I nedd to sort them and render, but now I get array and after sorting it I can't render sorted array. I use useEffect and there sorting an array and by setState put sorted array into variable but when I try to rended it I have error that array are empty. How can I fix it? Maybe I can somehow change props.friendsList with newFriends? it will be great!

type FriendsProps = {
    friendsList:
    {
        "id": number,
        "firstName": string,
        "lastName": string,
        "photoUrl": string,
        "online": boolean
    }[]
}

const Friends: React.FC<FriendsProps> = (props) => {
    const [friends, setFriends] = useState([{}]);

    useEffect(() => {
        const newFriends = props.friendsList.sort((friendA, friendB) => {
            return friendA.online === friendB.online ? 0 : friendA.online ? -1 : 1;
        })
        setFriends(newFriends)
    }, []);
    console.log(friends)
    
    return (
            <div className="friends-list">
                {friends.map((friendInfo, id) => {
                    return (
                        <h1>{friendInfo.firstName}</h1>
                    )
                })}
            </div>
    );
};

console.log (friends) show at first empty array and then fill

1 Answer 1

1

I think it would be better just to sort friends directly. The useEffect and state are unnecessary. To keep this optimised you should use useMemo, but you need to make sure props.friendsList is not changing on every render:

const Friends: React.FC<FriendsProps> = props => {
  const sortedFriends = React.useMemo(
    () =>
      props.friendsList.sort((friendA, friendB) => {
        return friendA.online === friendB.online ? 0 : friendA.online ? -1 : 1;
      }),
    [props.friendsList]
  );

  console.log({sortedFriends});

  return (
    <div className='friends-list'>
      {/* now map over your sortedFriends array */}
      {sortedFriends.map((friendInfo, id) => {
        // add a key when you're mapping over an array
        return <h1 key={id}>{friendInfo.firstName}</h1>;
      })}
    </div>
  );
};

Sign up to request clarification or add additional context in comments.

6 Comments

Thank you! and how can I add one more action like slice(0, 6)?
You can just chain it onto the end, if you want to do the slice after you sort. Or if you want to slice first and then sort you just put it before. All of these array methods return new arrays, so you can just keep chaining them :) - so in your case you could do props.friendsList.sort((friendA, friendB) => { return friendA.online === friendB.online ? 0 : friendA.online ? -1 : 1; }).slice(0, 6)
And if I want to do something with array after sorting in useMemo how can I realize it? Like after sorting by online I want to sort offline friends by ABC?
If your sorting is getting complex like this I'd look at a library like lodash and use their orderBy function: lodash.com/docs/4.17.15#orderBy . With this you can specify all the properties you want to order by, in order of priority, and either ascending or descending. So if you put import { orderBy } from 'lodash' and then in the useMemo you put orderBy(props.friendsList, ['online', 'firstName'], ['desc', 'asc'] ) Then it'll sort first by online descending, then firstName ascending. Just check how it sorts online, as I'm assuming it's a boolean and I haven't tried that
However Object.is([1, 2, 3], [1, 2, 3]) returns false, therefor sortedFriends would change on each render and thus useMemo would be useless here, right?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.