如何解决当父组件的状态发生变化时,子组件不会重新渲染
我有以下问题:我有一个在其中呈现其他组件的组件。其中一个组件获取我的父组件的状态变量作为参数并积极使用它们,但是当父组件的状态发生变化时它们不会重新渲染。我面临的另一个问题是我的列表中有一个额外的项目,当用户具有特殊的角色 ID 时,它会被激活。状态的更改完全正常,但在这种情况下,只有在我更改了 url 的路径参数后,附加项才会可见。
父组件:
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,'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;
子组件(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;
解决方法
首先,在你的父组件中做
setItems(items)
您实际上并未修改状态,因为 items
已经存储在状态中。 React 将检查您传递的值,如果该值已存储在状态中,则不会导致重新渲染。当你用 splice 修改你的数组时,它仍然是“相同”的数组,只是内容不同。
解决此问题的一种方法是执行 setItems([...items])
,它将使用包含相同项目的 new 数组调用 setItems
。
其次,在您的子类中,以下内容目前无效:
useEffect(() => {
setSelected(defaultactive);
},[])
由于依赖数组为空,所以只会在第一次渲染时调用。如果您希望在 defaultactive 更改时随时调用它,则需要这样做:
useEffect(() => {
setSelected(defaultactive);
},[defaultactive])
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。