最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Cannot read properties of undefined (reading 'includes') error after refreshing page - Stack Overfl

programmeradmin1浏览0评论

I am trying to make a web app using reactjs and I have been stuck on this error... I'm trying to add a like button on the product card and if user liked the product, the like button will be filled. When I am already on the page on localhost and I make changes in the code (updated immediately because I am using nodemon) the changes show up and work fine. However, once I refresh the page, or if I try to open the page again while the changes are present, I will get this error:

TypeError: Cannot read properties of undefined (reading 'includes')

Here is my code:

function Product(props) {
  const { product } = props;

  const { state } = useContext(Store);
  const { userInfo } = state;

  const [{ loading, user }, dispatch] = useReducer(reducer, {
    loading: false,
    user: [],
  });

  useEffect(() => {
    const fetchUser = async () => {
      dispatch({type: 'FETCHUSER_REQUEST'});
      try {
        const user = await axios.get(
          '/api/users/profile', {
            headers: {Authorization: `Bearer ${userInfo.token}`},
          }
        );
        dispatch({type: 'FETCHUSER_SUCCESS', payload: user.data});
      } catch(err) {
        dispatch({type: 'FETCHUSER_FAIL'});
        toast.error(getError(err));
      }
    }
    fetchUser();
  }, []);

  const [favourites, setFavourites] = useState([]);

  const likesHandler = async(e) => {
    e.preventDefault();
    favourites.push(product._id);
    setFavourites(favourites => [...favourites, product._id]);
      const { data } = await axios.put(
        '/api/users/likes',
        { favourites },
        {
          headers: {Authorization: `Bearer ${userInfo.token}`},
        }
      );
  };

  console.log(user);
  console.log(user.favourites);

  return (
    <Card styles="1px solid grey">
      <Link to={`/product/${product.slug}`}>
        <img src={product.image} className="card-img-top" alt={product.name} />
      </Link>
      <Card.Body>
        <Link to={`/product/${product.slug}`}>
          <Card.Title>{product.name}</Card.Title>
        </Link>
        <Rating rating={product.rating} numReviews={product.numReviews} />
        <Card.Text>${product.price}</Card.Text>
        {product.stock === 0 ? (
          <Button variant="light" disabled>
            Out of stock
          </Button>
        ) : (
          <Button onClick={() => addToCartHandler(product)}>Add to cart</Button>
        )}
      </Card.Body>

      {user.favourites.includes(product._id) ? (
        <i class="fas fa-heart fa-lg card-icon-btm"></i>
      ) : (
        <span onClick={likesHandler}>
          <i class="far fa-heart fa-lg card-icon-btm"></i>
        </span>
      )}

    </Card>
  );
}
export default Product;

My API code:

userRouter.get(
  '/profile',
  isAuth,
  expressAsyncHandler(async (req, res) => {
    const user = await User.findById(req.user._id);
    res.send(user);
  })
);

userRouter.put(
  '/likes',
  isAuth,
  expressAsyncHandler(async(req, res) => {
    const user = await User.findById(req.user._id);

    if (user) {
      user.favourites.push(req.body.favourites[0])
    }
    await user.save();
  })
);

After refreshing, console.log(user) will return empty and user.favourites will return undefined. I know it is probably an issue with how my user data is populated, but I cannot figure out what is the issue... I'm populating user right at the start of the code. If anyone has any idea what the issue could be, would be very grateful!

I am trying to make a web app using reactjs and I have been stuck on this error... I'm trying to add a like button on the product card and if user liked the product, the like button will be filled. When I am already on the page on localhost and I make changes in the code (updated immediately because I am using nodemon) the changes show up and work fine. However, once I refresh the page, or if I try to open the page again while the changes are present, I will get this error:

TypeError: Cannot read properties of undefined (reading 'includes')

Here is my code:

function Product(props) {
  const { product } = props;

  const { state } = useContext(Store);
  const { userInfo } = state;

  const [{ loading, user }, dispatch] = useReducer(reducer, {
    loading: false,
    user: [],
  });

  useEffect(() => {
    const fetchUser = async () => {
      dispatch({type: 'FETCHUSER_REQUEST'});
      try {
        const user = await axios.get(
          '/api/users/profile', {
            headers: {Authorization: `Bearer ${userInfo.token}`},
          }
        );
        dispatch({type: 'FETCHUSER_SUCCESS', payload: user.data});
      } catch(err) {
        dispatch({type: 'FETCHUSER_FAIL'});
        toast.error(getError(err));
      }
    }
    fetchUser();
  }, []);

  const [favourites, setFavourites] = useState([]);

  const likesHandler = async(e) => {
    e.preventDefault();
    favourites.push(product._id);
    setFavourites(favourites => [...favourites, product._id]);
      const { data } = await axios.put(
        '/api/users/likes',
        { favourites },
        {
          headers: {Authorization: `Bearer ${userInfo.token}`},
        }
      );
  };

  console.log(user);
  console.log(user.favourites);

  return (
    <Card styles="1px solid grey">
      <Link to={`/product/${product.slug}`}>
        <img src={product.image} className="card-img-top" alt={product.name} />
      </Link>
      <Card.Body>
        <Link to={`/product/${product.slug}`}>
          <Card.Title>{product.name}</Card.Title>
        </Link>
        <Rating rating={product.rating} numReviews={product.numReviews} />
        <Card.Text>${product.price}</Card.Text>
        {product.stock === 0 ? (
          <Button variant="light" disabled>
            Out of stock
          </Button>
        ) : (
          <Button onClick={() => addToCartHandler(product)}>Add to cart</Button>
        )}
      </Card.Body>

      {user.favourites.includes(product._id) ? (
        <i class="fas fa-heart fa-lg card-icon-btm"></i>
      ) : (
        <span onClick={likesHandler}>
          <i class="far fa-heart fa-lg card-icon-btm"></i>
        </span>
      )}

    </Card>
  );
}
export default Product;

My API code:

userRouter.get(
  '/profile',
  isAuth,
  expressAsyncHandler(async (req, res) => {
    const user = await User.findById(req.user._id);
    res.send(user);
  })
);

userRouter.put(
  '/likes',
  isAuth,
  expressAsyncHandler(async(req, res) => {
    const user = await User.findById(req.user._id);

    if (user) {
      user.favourites.push(req.body.favourites[0])
    }
    await user.save();
  })
);

After refreshing, console.log(user) will return empty and user.favourites will return undefined. I know it is probably an issue with how my user data is populated, but I cannot figure out what is the issue... I'm populating user right at the start of the code. If anyone has any idea what the issue could be, would be very grateful!

Share Improve this question asked Jul 29, 2022 at 10:40 OkayOkay 832 gold badges2 silver badges8 bronze badges 1
  • Based on your useReducer call, the initial value of user is []. That means your unconditional code user.favorites.includes fails, because arrays don't have a favorites property. So there are two separate issues (at least): 1. You're not allowing for the fact you don't have a user yet in the initial render. 2. You're either using the wrong value for the initial state of user, or you should be using user as an array (the name user suggests it's that [] is the wrong initial value, you probably want null ["no user"], or {}, or maybe {favorites: []} instead). – T.J. Crowder Commented Jul 29, 2022 at 10:45
Add a ment  | 

2 Answers 2

Reset to default 3

I believe that error occurs because it you load your page form "fresh" start you have empty user array until it gets fetched from API - you have to check if it has properties you want to obtain.

In your case you can secure from this error by adding question mark before checking for object that may not exist when you looking for it.

{user?.favourites?.includes(product._id) ? (
    <i class="fas fa-heart fa-lg card-icon-btm"></i>
  ) : (
    <span onClick={likesHandler}>
      <i class="far fa-heart fa-lg card-icon-btm"></i>
    </span>
  )}

If it is not defined code fill simply return false and return to "else" block of this instruction.

Part of the issue you describe could be solved by using the optional chaining (?.) operator. In your case: ?.includes(product._id) instead of ?.includes(product._id). At least you could stop getting that error like that.

In my case, I was getting the same error in my javascript project because I was using .includes(); to check a variable that was sometimes 'undefined'. I solved it by using ?.includes(); .

I finished understanding it after reading this article, which states:

The optional chaining (?.) operator can also be used to avoid getting an error because if the reference is equal to undefined or null, it short-circuits returning undefined.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论