0
{user.anotherUser.followers &&
  user.anotherUser.followers.map((a) => {
    if (user.user._id === a._id) {
      return console.log("following button");
    } else {
      return console.log("follow button");
    }
})}

Data:

{
  "username": "John",
  "followers": [],
}

The problem is that return console.log("follow button"); does not run when the followers array is empty.

When the array is not empty, the return console.log("following button") successfully runs which is good.

When not empty, the followers array contains objects of different users (populated it on the backend to access ObjectID properties) like this:

{
  "username": "John",
  "followers": [
     "_id": "123123123",
     "username": "David"
  ],
}

What did I do wrong?

The user.user._id is my id which is 123123123 in this case.

EDIT:

       {user.anotherUser.followers &&
        user.anotherUser.followers.length > 0 ? (
            user.anotherUser.followers.map((a) => {
                if (user.user._id === a._id) {
                    return <Button>Following</Button>;
                } else {
                    return <Button>Follow</Button>;
                }
            })
        ) : (
            <Button>Follow</Button>
        )}

With this, both Following and Follow buttons are displayed. Only one button should be display by logic.

EDIT2:

       {user.anotherUser.followers &&
        user.anotherUser.followers.length > 0 ? (
            user.anotherUser.followers.map((a) => {
                if (user.user._id === a._id) {
                    return <Button>Following</Button>;
                }
            })
        ) : (
            <Button>Follow</Button>
        )}

Now the Follow button does not appear if the length > 0, because someone else's id is in the array, although mine (user.user._id) is not there. The Follow button should appear if the array length > 0 and if my user.user._id is not inside it either.

EDIT3:

I could use a different approach because user.user has a following array field in the database.

let userFollowing =
  user.user.following && user.user.following.map((a) => a._id);

And then display one button like this:

            {user.user.following &&
                userFollowing.includes(user.anotherUser._id) && (
                    <Button className="follow-true">Following</Button>
                )}
            {user.user.following &&
                !userFollowing.includes(user.anotherUser._id) && (
                    <Button className="follow-false">Follow</Button>
                )}

EDIT4: better and final solution:

Above the return()

let anotherUserFollowers =
        user.anotherUser.followers &&
        user.anotherUser.followers.map((a) => a._id);

In the return()

           {user.anotherUser.followers &&
                anotherUserFollowers.includes(user.user._id) && (
                    <Button
                        onClick={() =>
                            props.follow({
                                id: user.anotherUser._id,
                            })
                        }
                        className="follow-true"
                    >
                        Following
                    </Button>
                )}
            {user.anotherUser.followers &&
                !anotherUserFollowers.includes(user.user._id) && (
                    <Button
                        onClick={() =>
                            props.follow({
                                id: user.anotherUser._id,
                            })
                        }
                        className="follow-false"
                    >
                        Follow
                    </Button>
                )}
3
  • using in JSX? If yes than you've to return JSX there because it requires JSX to render and convert to HTML. Another thing you can't map empty array. Commented Jul 21, 2020 at 6:41
  • But I think I do return it in the conditional, and yes this is in the JSX Commented Jul 21, 2020 at 6:42
  • @David empty arrays can't be mapped. Commented Jul 21, 2020 at 6:43

4 Answers 4

2

You can return early if there are no followers, optional chaining helps make this easier:

if (!user?.anotherUser?.followers?.length) return <Button>Follow</Button>

return user.anotherUser.followers.map(a =>
 (user.user._id === a._id) ? <Button>Following</Button> : <Button>Follow</Button>);
Sign up to request clarification or add additional context in comments.

Comments

1

.map executes the given function for each element in the array

That means if your array does not have any elements in your array, no code will be executed. And that's the expected behaviour.

If you want to do something when the array is empty, you should do something else outside the .map callback.

Comments

1

Well, you just set a condition on your JSX like user.anotherUser.followers && ... so whenever you got "followers": [], the Array#map won't run, on the other hand, if the condition doesn't block the Array#map execution it won't run either, because you can't do a map over an empty array.

Here is an example for more illustration:

const arr = [];

const newArr = arr.map(el => console.log('first console', el))
console.log('second console', newArr)

So to fix this you can implement it in some other way like ternary operation.

const user = {
  anotherUser: {
    followers: []
  }
};

(user.anotherUser.followers && user.anotherUser.followers.length > 0 && user.user._id) ?
user.anotherUser.followers.map((a) => {
    if (user.user._id === a._id) {
      console.log("following button");
    }
  }):
  console.log("No followers found!");

4 Comments

I made another edit for this one. I'm trying to solve it. I think this is another small issue, not really related to the original question.
@David If you just want to check if user.user._id in your array exist or not you can chain another simple condition to your ternary condition like this like this: (user.anotherUser.followers && user.anotherUser.followers.length > 0 && user.user._id) ? ...
I used another approach but I will try this one too. See my edit (that's working).
@David Optional chaining is very Good and useful but you need a polyfill for it since the support coverage does not include old browsers. Also as you said earlier your second question was different from the OP and my first answer covered the OP. So I hope you mark this one as an answer.
0

Above the return()

let anotherUserFollowers =
        user.anotherUser.followers &&
        user.anotherUser.followers.map((a) => a._id);

In the return()

       {user.anotherUser.followers &&
            anotherUserFollowers.includes(user.user._id) && (
                <Button
                    onClick={() =>
                        props.follow({
                            id: user.anotherUser._id,
                        })
                    }
                    className="follow-true"
                >
                    Following
                </Button>
            )}
        {user.anotherUser.followers &&
            !anotherUserFollowers.includes(user.user._id) && (
                <Button
                    onClick={() =>
                        props.follow({
                            id: user.anotherUser._id,
                        })
                    }
                    className="follow-false"
                >
                    Follow
                </Button>
            )}

Comments

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.