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

javascript - Can't access state inside function in React Function Component - Stack Overflow

programmeradmin1浏览0评论

I have the following ponent in React:

import React, { useState, useEffect } from 'react';
import api from '../../services/api';

const Store = () => {
  const [products, setProducts] = useState([]);
  let pagination = null;

  const getProducts = async (page = 1) => {
    const { data } = await api.get('products', { params: { page } });

    setProducts([...products, ...data.products]);
    pagination = data.pagination;

    if (pagination.current < pagination.max) {
      document.addEventListener('scroll', loadMore);
    }
  };

  const loadMore = () => {
    const { scrollTop, clientHeight, scrollHeight } = document.documentElement;

    if (scrollTop + clientHeight >= scrollHeight - 300) {
      getProducts(pagination.current + 1);
      document.removeEventListener('scroll', loadMore);
    }
  };

  useEffect(() => {
    getProducts();
  }, []);

  useEffect(() => {
    console.log(products);
  }, [products]);

  return (
    <div>
      {products.map(product => (
        <p>{product.name}</p>
      ))}
    </div>
  );
};

export default Store;

My console.log inside the useEffect hook do print the products array correctly, and the ponent is also rendering the products titles correctly.

But when I try to access the products variable inside the getProducts function it doesn't get the updated products value, it gets the value I have set in the useState hook.

For example, if I start the state with one product, calling products within the getProducts function will always bring this one product, and not the ones loaded from the API fetch, that were correctly logged in the console.

So, when I try to add more products to the end of the array it actually just add the products to an empty array.

Any idea why this is happening? Being able to access the products state inside the useState hook but not inside the getProducts function?

I have the following ponent in React:

import React, { useState, useEffect } from 'react';
import api from '../../services/api';

const Store = () => {
  const [products, setProducts] = useState([]);
  let pagination = null;

  const getProducts = async (page = 1) => {
    const { data } = await api.get('products', { params: { page } });

    setProducts([...products, ...data.products]);
    pagination = data.pagination;

    if (pagination.current < pagination.max) {
      document.addEventListener('scroll', loadMore);
    }
  };

  const loadMore = () => {
    const { scrollTop, clientHeight, scrollHeight } = document.documentElement;

    if (scrollTop + clientHeight >= scrollHeight - 300) {
      getProducts(pagination.current + 1);
      document.removeEventListener('scroll', loadMore);
    }
  };

  useEffect(() => {
    getProducts();
  }, []);

  useEffect(() => {
    console.log(products);
  }, [products]);

  return (
    <div>
      {products.map(product => (
        <p>{product.name}</p>
      ))}
    </div>
  );
};

export default Store;

My console.log inside the useEffect hook do print the products array correctly, and the ponent is also rendering the products titles correctly.

But when I try to access the products variable inside the getProducts function it doesn't get the updated products value, it gets the value I have set in the useState hook.

For example, if I start the state with one product, calling products within the getProducts function will always bring this one product, and not the ones loaded from the API fetch, that were correctly logged in the console.

So, when I try to add more products to the end of the array it actually just add the products to an empty array.

Any idea why this is happening? Being able to access the products state inside the useState hook but not inside the getProducts function?

Share Improve this question asked Feb 28, 2020 at 19:33 Gabriel CastroGabriel Castro 1201 silver badge11 bronze badges 6
  • The products state won't be altered until the next render after setProducts is run. Within your getProducts function you need to use data.products to access the new values. Perhaps create a temp variable like const tempProducts = [...products, ...data.products]; and then use tempProducts to update the state setProducts(tempProducts); and also use tempProducts anywhere you need to access the updated value within getProducts. – WGriffing Commented Feb 28, 2020 at 19:36
  • I actually tried to create the temp variable like you said, but I just get the same result: ...products will bring me nothing, so I end up only with the fetched products. The solution I found was to set the state in the getProducts function like setProducts(previousProducts => ([...previousProducts, ...data.products])). It did work, but I still don't understand why the products variable is empty, even after the console.log(products) has showed me that the state was updated. – Gabriel Castro Commented Feb 28, 2020 at 19:52
  • I am 100% sure I am calling the products after the state finishes updating, as all the products are already being showed in the browser when the loadMore calls the getProducts again. – Gabriel Castro Commented Feb 28, 2020 at 19:55
  • 1 I think I did not explain it well. Check out this answer stackoverflow./a/58877875/10447393 from useState set method not reflecting change immediately. If that's not the same problem you are experiencing, then I apologize for misunderstanding. – WGriffing Commented Feb 28, 2020 at 20:09
  • Yeah, the answer actually did help a lot, thank you so much for linking it! :) – Gabriel Castro Commented Feb 28, 2020 at 20:15
 |  Show 1 more ment

1 Answer 1

Reset to default 4

This is happening because the getProducts is using the value products had when getProducts was being declared, not the one products has when the getProducts function is called. This is always the case when you want to access the most recent state directly in non-inline functions. Mostly, you will need to pass the updated value through the function arguments.

But this is not an option in your case. The only option in your case is to use the previous value as the argument from a callback passed to setState (in your case, setProducts).

Hope this helps someone else in future :).

发布评论

评论列表(0)

  1. 暂无评论