The child component remains static and does not update when the parent component's state is modified

I am encountering a particular issue with one of my components. This component is responsible for rendering other components within it. One of these inner components takes state variables from its parent component as parameters and actively uses them, but fails to re-render when the state of the parent component changes. Additionally, I have another problem where there is an extra item in my list that should only be visible to users with a special roleID. While the state change works correctly, this additional item only becomes visible after I manually update the path parameter in the URL.

Parent component:

import React, { useEffect, useState } from 'react';
import {Row, Col} from 'react-bootstrap';
import 'bootstrap/dist/css/bootstrap.min.css';
import '../../App.css';
import ProfileSettings from './profileSettings';
import SettingsChooser from './settingsChooser';
// import SettingRoutings from '../settingRoutings';
import {BrowserRouter as Router, useHistory, useLocation, useParams} from 'react-router-dom';
// import Routings from '../Routings.js';
import UserRequests from './userRequests';
import useAuth from '../../API/useAuthentification';
import { CONTROLLERS, useBackend } from '../../hooks/useBackend';

function UserSettings({user}) {

    const {title: path} = useParams();
    const [acst, setAcst] = useState(localStorage.accessToken);
    const [rft, setRft] = useState(localStorage.refreshToken);
    const history = useHistory();
    const [items, setItems] = useState(['Profile', 'Requests','Log Out', 'Delete Account']);
    const [authError, setAuthError] = useState(false);
    const [userValues, authentificate] = useBackend(authError, setAuthError, user);
    const [component, setComponent] = useState(<></>);
    const [defaultItem, setDefaultItem] = useState(0);
    

    useEffect(() => {
        console.log('render');
        authentificate(CONTROLLERS.USERS.getUserByAccessToken());
    }, [acst, rft]);

    window.addEventListener('storage', () => localStorage.accessToken !== acst ? setAcst(localStorage.accessToken) : '');
    window.addEventListener('storage', () => localStorage.refreshToken !== rft ? setRft(localStorage.refreshToken) : '');

    useEffect(() => {
        if(userValues?.roleID === 1) {
            items.splice(0, 0, 'Admin Panel');
            setItems(items);
        }
        console.log(items);
    }, [userValues]);

    useEffect(() => {
        // if(path==='logout') setDefaultItem(2);
        // else if(path==='deleteAccount') setDefaultItem(3);
        // else if(path==='requests') setDefaultItem(1);
    }, [])

    const clearTokens = () => {
        localStorage.accessToken = undefined;
        localStorage.refreshToken = undefined;
    }
    useEffect(() => {
        console.log(path);
        if(path ==='logout' && !authError) {
            setDefaultItem(2);
            clearTokens();
        }
        else if(path === 'deleteaccount') {
            setDefaultItem(3);
            if(userValues?.userID && !authError) {
             authentificate(CONTROLLERS.USERS.delete(userValues.userID));
             }
            clearTokens();
            history.push('/movies/pages/1');
        }
        else if(path==='requests') {
            setDefaultItem(1);
            setComponent(<UserRequests user={userValues} setAuthError={setAuthError} authError={authError}/>);
        } else {
            setComponent(<ProfileSettings user={userValues} setAuthError={setAuthError} authError={authError}/>);
        }
    }, [path]);

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

    return (
            <div >
            <Row className="">
            <Col className="formsettings2"   md={ {span: 3, offset: 1}}>
                <SettingsChooser  items={items} headline={'Your Details'} defaultpath='userSettings' defaultactive={defaultItem} />
            </Col>
           <Col  className="ml-5 formsettings2"md={ {span: 6}}>
                     {authError ? <p>No Access, please Login first</p> : component}
            </Col>
            </Row>
            </div>
    );
}

export default UserSettings;

Child component (settingsChooser):

import React, {useEffect, useState} from 'react';
import {Card, Form, Button, Nav, Col} from 'react-bootstrap';
import 'bootstrap/dist/css/bootstrap.min.css';
import { LinkContainer } from 'react-router-bootstrap';
import '../../App.css'

function SettingsChooser({items, headline, defaultpath, defaultactive}) {

    const [selected, setSelected] = useState(defaultactive);
   

    const handleClick = (e, key) => {
        setSelected(key);
    }

    useEffect(() => console.log("rerender"), [items, defaultactive]);

    useEffect(() => {
        setSelected(defaultactive);
    }, [])

    return(
        <>
        <Card className="shadow-sm">
            <Card.Header className="bg-white h6 ">{headline}</Card.Header>
        {items.map((item, idx) =>{
            return(
              <LinkContainer to={`/${defaultpath}/${(item.replace(/\s/g,'').toLowerCase())}`}><Nav.Link onClick={(e) => handleClick(this, idx)}  className={'text-decoration-none text-secondary item-text ' + (selected === idx? 'active-item' : 'item')}>{item}</Nav.Link></LinkContainer>
            );           
        })}
        </Card>
        </>
    );
}

export default SettingsChooser;

Answer №1

Initially, when updating the items in your parent component using

setItems(items)

it does not actually change the state as items is already stored in the state. React checks the value passed and avoids re-rendering if it's the same. However, by using setItems([...items]), a new array can be created with the same items.

Additionally, the useEffect function in your child class currently has no impact:

useEffect(() => {
    setSelected(defaultactive);
}, [])

Because the dependency array is empty, this code only runs on initial render. To make it run whenever defaultactive changes, update the code like this:

useEffect(() => {
    setSelected(defaultactive);
}, [defaultactive])

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the correct way to configure an API request utilizing the useEffect hook in React?

I have encountered an issue with my component where the correct data is showing up in the console under "data", but when attempting to run a map function on it, I am receiving an error message stating that "map is not a function." The console shows 16 item ...

The Nextjs framework is experiencing a high total blocking time in its *****.js chunk

As I analyze the performance of next.js in my project, I am noticing a high total blocking time. Specifically, the "framework" chunk consistently takes more than 50ms. It seems that this chunk corresponds to the react and react-dom JavaScript files. Does ...

Function for testing global variable stub in JavaScript

Currently, I am in the process of writing Unit tests for a React application. Within the page header, the tracking library 'mixpanel' is inserted between <script> tags as outlined in their documentation: . The documentation states that "Th ...

Tips for sending an email to an address from a user input field in React.js/Express.js

I am currently developing an email application that allows users to send emails to any recipient of their choice. The challenge I'm facing is that I need a way to send emails to user-specified email addresses without requiring passwords or user.id det ...

ES6 scoping confusion: unraveling the mystery

I stumbled upon these two syntax methods for exporting functions. Let's say we have files named actions.js and app.js. The first method looks like this: in actions.js export function addTodo() {} export function deleteTodo() {} and in app.js I have ...

Drawer component from Material-UI placed on top of the sidebar

Currently, I am working on a project where I am using React TypeScript along with Material-UI. The issue that I am encountering is related to the width of the Drawer component provided by Material-UI. By default, the Drawer takes up the entire screen wid ...

Get the cookies from the NodeJs API using Next.js version 13.4

Could you please review my code? I have a Next.js and Node API app, and I'm facing an issue with obtaining the cookie from my API in my Next app. The signInUser API that I created should return a generated JWT cookie. However, when I use it in my Next ...

I am encountering an issue with the useRef function not properly detecting visibility

I'm looking to incorporate a fade-in animation into my React div as I scroll and reach a specific section. Unfortunately, the useEffect function that is supposed to detect the scrolling behavior seems to be malfunctioning and I can't figure out w ...

Issue with rendering HTML entities in Material UI when passing as props

Encountered a problem with the radio buttons in Material UI. Currently, Material UI accepts value as a prop for the FormControlLabel component. When passing a string with an HTML entity like below, it gets parsed correctly. <FormControlLabel value="fem ...

Can a unique class name generator be implemented for styled components in MaterialUI?

Currently, I am working on a create-react-app project that uses MaterialUI. In an attempt to switch from JSS to Styled Components, everything is functioning properly but the generated class names are not easily understandable. I came across information su ...

Preserve the checkbox state upon refreshing the page

I am facing an issue with keeping the checkbox state saved after a page reload. Currently, I have stored my unchecked checkboxes in localStorage, but I am unsure about what steps to take next. In simple terms, I want the checkbox to remain unchecked when I ...

Using React with Typescript: Anticipating child component with particular props

I'm currently developing a component that necessitates the use of two specific child components. These two components are exported using dot notations from the main component and have defaultProps for identification within the main component: export ...

Using Cookies with Next.js and Vercel

I am facing an issue with my NextJs app deployed on Vercel where the cookie is not being set. Upon checking the console in Network, I can see that the request returns a 200 status and the set-cookie value is present without any warning. However, when I loo ...

Updating state on a component that has been unmounted using context and hooks in React Native

UPDATE: I've implemented the code provided by the instructor in this post, however, despite using the state isMounted and the cleanup function in useEffect, I am still facing the same issue. The code appears to be functioning correctly, but I consiste ...

Generating data types based on the output of functions

I'm currently working on optimizing my typescript react code by reducing repetition. I'm curious to know if there's a way to generate a type based on the return type of a known function? For example: const mapStateToProps = (state: StoreSt ...

React class component experiencing issues with Material UI popover functionality

I'm new to using Material UI and find that all its documentation is based on function components, which I am not familiar with. I'm having trouble getting the popover to work - whenever I hover over the text, the function triggers but the popover ...

The browser is unable to access localhost:3000

Backend: Utilizing an Express server, created with the npx create-express-api command Frontend: Using Next.js, set up with npx create-react-app in the frontend directory Having executed these commands in the root folder, I attempted to run npm start xxx ...

Tips for incorporating a Font Awesome icon <i> within a select dropdown and customizing its appearance

I am facing an issue while trying to insert an icon into a select option. The error message I received is: Warning: validateDOMNesting(...): cannot appear as a child of <option> To indicate that certain fields are required, I am using asterisk ic ...

What is the solution for the error message "Unhandled Runtime Error" with the description "TypeError: videoRef.current.play is not a function"?

I am currently working on implementing custom controls for a video on a Nextjs website. When using a standard HTML <video> component, the code functions as expected and clicking the custom play button successfully plays the video. However, when I swi ...

Unable to minimize or hide the ace editor widget with Cypress

Today marks the beginning of my journey into posting on this platform, and I am eager to get it right. In my current project using Cypress for writing integration tests, I encountered a challenge while attempting to click on an Ace editor widget within a ...