I have the following issue: I have an Component that renders other components in it. One of this component gets state variables of my parent component as parameter and are using them actively, but they don't rerender when the state of the parent component changes. Another problem that I am facing is that I have an additional item in my list that navigates that is activated when the user has a special roleID. The changing of the state works completely fine, but in this situation the additional item only gets visible after I changed the path param of my 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;