Andiana
Andiana

Reputation: 1952

React functional component state change does not trigger child component to re-read its props

I'm having this React functional component. We know that since v16.8, functional component has kind of "state". It uses useEffect to "setState" to state variable products. Then I pass product as prop for the child component *ProductGrid". I have the ProductOfCategory as parent component, it will fetch data from an URL and set the result to state variable "products". I want the child component ProductGrid to be able to read that data (change), so I made it looks like this.

Parent:

    export default function ProductOfCategory() {

    let { categoryId } = useParams();
    const [products, setProducts] = useState([]);

    useEffect(() => {
        fetch('/products/cat/' + categoryId)
            .then(response => response.json())
            .then(data => {
                setProducts(data);
                console.log("Fetch me: ", data);
            });
    }, [categoryId]);


    return (
        <div>
            <h3>ID: {categoryId}</h3>
            <ProductGrid products={products} />
        </div>
    );
}

Child:

class ProductGrid extends Component {

    constructor(props) {
        super(props);
        this.state = { products: this.props.products};
        console.log("ProductGrid.props.products: ", this.props);
    }

    componentDidUpdate(prevProps, prevState, snapshot) {
        console.log("Grid did update, products: ", this.state.products);
    }
}

Result: When the data in parent changes, I can see (in the console) that the child component (ProductGrid) is re-rendered also, but its prop variable "products" is NOT. It's always an empty array. What is the reason of this? Does it mean that functional component's state is different from legacy state? Is there someway to overcome this?

Many thanks.

Upvotes: 0

Views: 2237

Answers (1)

ggovan
ggovan

Reputation: 1927

You problem is on the line

console.log("Grid did update, products: ", this.state.products);

Here you are logging the state of the child component. When you construct the child component you copy the prop.products to state.products. Then when prop.product changes you don't update the state to reflect that change, you continue to print the initial value of products that was passed to the component.

The solution here would be to use this.props.products instead of this.state.products.

Upvotes: 1

Related Questions