menu

Questions & Answers

React is mixing state values passed in child component

I'm trying to figure out why does this happening.

I have one main component for page in react-router-dom which is called ComponentPage. In ComponentPage I have 3 others components: ComponentOne, ComponentTwo and ComponentThree.

The logic should be something like this:

ComponentPage on load calls callbackGetDates and set dates in dates state with useEffect hook.

ComponentThree is reading dates and redners the list of dates.

Event onClick in dates list sets selectedDate state.

On selectedDate state change, callback callbackGetBills is called and request is sent to the api and returned data is saved in bills state with useEffect hook.

ComponentOne and ComponentTwo then renders some output based on bills state.

When in components ComponentOne and ComponentTwo I try to print bills props in console i get result like this:

COMPONENT ONE ComponentOne.jsx:8

COMPONENT ONE BILLS ComponentOne.jsx:9

Array [ "2023-02", "2023-01" ]

COMPONENT ONE ComponentOne.jsx:8

COMPONENT ONE BILLS ComponentOne.jsx:9

Array [ {…}, {…} ]

Somehow I get dates state as props and after that I get bills state printed in the console. This is happening in both ComponentOne and ComponentTwo.

dates state should be:

Array [ "2023-02", "2023-01" ]

bills state should be:

Array [ {…}, {…} ]

React version is: 18.2.0.

ComponentPage:

export default function ComponentPage()
{

    import Api from "Some/Axios/Config/Folder";
    import ComponentOne from "components/ComponentOne";
    import ComponentTwo from "components/ComponentTwo";
    import ComponentThree from "components/ComponentThree";

    const [bills, setBills] = useState([]);
    const [dates, setDates] = useState([]);
    const [selectedDate, setSelectedDate] = useState("");

    const callbackGetBills = useCallback(function()
    {
        async function getBills()
        {
            const {data} = await Api.get(`endpoint/${selectedDate}`);
            setBills(data);
        }

        return getBills();
    }, [selectedDate]);

    const callbackGetDates = useCallback(function()
    {

        async function getDates()
        {
            const {data} = await Api.get("endpoint/");
            setDates(data);
        }

        return getDates();
    }, []);

       useEffect(function()
    {
        callbackGetDates();
    }, [callbackGetDates]);
    
    

    useEffect(function()
    {
        callbackGetBills();
    }, [callbackGetBills]);

    return <>
        <ComponentThree
            dates={dates}
            selectedDate={selectedDate}
            setSelectedDate={setSelectedDate}
        />
        <ComponentOne bills={bills} />
        <ComponentTwo bills={bills} />
    <>;
}

ComponentOne:

... imports
export default function ComponentOne({ bills })
{

    console.log("COMPONENT ONE");
    console.log("COMPONENT ONE BILLS");
    console.log(bills);

    ....
}

ComponentTwo:

... imports
export default function ComponentTwo({ bills })
{

    console.log("COMPONENT TWO");
    console.log("COMPONENT TWO BILLS");
    console.log(bills);

    ....
}

ComponentThree:

import ListGroup from "react-bootstrap/ListGroup";

export default function ComponentThree({dates, selectedDate, setSelectedDate})
{

    function renderDate(date, index) {
        return <ListGroup.Item
            key={index}
            onClick={() => {setSelectedDate(date)}}
            active={date === selectedDate}
        >
            {date}
        </ListGroup.Item>
    }

    return <ListGroup>
        {dates.map(renderDate)}
    </ListGroup>
}

index.js:

import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter, Routes, Route} from "react-router-dom";
import "bootstrap/dist/css/bootstrap.min.css";
... imports
import ComponentPage from "./pages/ComponentPage";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
    <React.StrictMode>
        <BrowserRouter>
            <Routes>
                ... routes
                <Route path="/test" element={<ComponentPage />} />
            </Routes>
        </BrowserRouter>
    </React.StrictMode>
);
Comments:
2023-01-21 23:25:07
The issue is that React is mixing state values passed in child component. This is happening because React is re-rendering the child components when the parent component is re-rendered. To fix this issue, you can use the useMemo hook to memoize the values passed to the child components. This will ensure that the child components will only be re-rendered when the values passed to them change.
Answers(0) :