Javascript ReactJS:在重新渲染期间,类型数组的状态正在分解为元素
我想做的事 我有一个带有一系列“配置文件”的主组件。对于每个概要文件,我有两个不同的条件组件(一次只显示一个)。这两个组件中的每一个都有一个按钮,用于在单击时切换组件。因此,我将状态提升到主组件,使用“useState”钩子创建组件状态(这是一个数组,其中每个索引都是一个字符串,表示profiles数组中每个元素要显示的子组件),我为这些单击创建了两个事件处理函数,并将它们作为渲染道具传递到其子组件中 它们从第一个子组件开始 问题&我是如何发现的Javascript ReactJS:在重新渲染期间,类型数组的状态正在分解为元素,javascript,reactjs,react-hooks,react-component,react-state,Javascript,Reactjs,React Hooks,React Component,React State,我想做的事 我有一个带有一系列“配置文件”的主组件。对于每个概要文件,我有两个不同的条件组件(一次只显示一个)。这两个组件中的每一个都有一个按钮,用于在单击时切换组件。因此,我将状态提升到主组件,使用“useState”钩子创建组件状态(这是一个数组,其中每个索引都是一个字符串,表示profiles数组中每个元素要显示的子组件),我为这些单击创建了两个事件处理函数,并将它们作为渲染道具传递到其子组件中 它们从第一个子组件开始 问题&我是如何发现的 const Peers = props =>
const Peers = props => {
let dummyPeer = {
_id: "9asdf98sj3942j4fs9ji",
user: {
name: "Test Peer",
avatar: "//www.gravatar.com/avatar/cd56136f6d9abfdf4a0198dc9ce656c8?s=200&r=pg&d=mm"
},
bio: "Biography for Test Peer",
year: "2022",
courses: [
"CISC124",
"PSYC223",
"PSYC236",
"COMM200",
"CISC251"
]
}
let profiles = [];
profiles.push(dummyPeer);
let initialState = [];
profiles.forEach(profile => {
initialState.push("normal");
});
let [viewState, setViewState] = useState(initialState);
console.log(viewState);
const openLargeView = (id) => {
let changeIndex = profiles.map(profile => profile._id).indexOf(id);
setViewState(state => state[changeIndex] = "large");
console.log(viewState);
}
const closeLargeView = (id) => {
let changeIndex = profiles.map(profile => profile._id).indexOf(id);
setViewState(state => state[changeIndex] = "normal");
console.log(viewState);
}
return (
<Fragment>
{profiles.map((profile, index) => (<Fragment key={profile._id} >
{viewState[index] === "normal" ? (
<Peer openLargeView={openLargeView} profile={profile} />
) : (
<ViewPeer closeLargeView={closeLargeView} profile={profile} />
)}
</Fragment>))}
</Fragment>
)
}
当您按下按钮切换到其他组件时,它会工作。当你按下按钮返回时,它崩溃了。正在说“TypeError:无法分配给字符串“large”的只读属性“0”。在useState初始化之后,以及在每个函数中的状态更改调用之后,我放置了一些console.log(state)。发生的事情(只有一个元素的测试列表)是
const Peers = props => {
let dummyPeer = {
_id: "9asdf98sj3942j4fs9ji",
user: {
name: "Test Peer",
avatar: "//www.gravatar.com/avatar/cd56136f6d9abfdf4a0198dc9ce656c8?s=200&r=pg&d=mm"
},
bio: "Biography for Test Peer",
year: "2022",
courses: [
"CISC124",
"PSYC223",
"PSYC236",
"COMM200",
"CISC251"
]
}
let profiles = [];
profiles.push(dummyPeer);
let initialState = [];
profiles.forEach(profile => {
initialState.push("normal");
});
let [viewState, setViewState] = useState(initialState);
console.log(viewState);
const openLargeView = (id) => {
let changeIndex = profiles.map(profile => profile._id).indexOf(id);
setViewState(state => state[changeIndex] = "large");
console.log(viewState);
}
const closeLargeView = (id) => {
let changeIndex = profiles.map(profile => profile._id).indexOf(id);
setViewState(state => state[changeIndex] = "normal");
console.log(viewState);
}
return (
<Fragment>
{profiles.map((profile, index) => (<Fragment key={profile._id} >
{viewState[index] === "normal" ? (
<Peer openLargeView={openLargeView} profile={profile} />
) : (
<ViewPeer closeLargeView={closeLargeView} profile={profile} />
)}
</Fragment>))}
</Fragment>
)
}
const Peers=props=>{
让dummyPeer={
_id:“9asdf98sj3942j4fs9ji”,
用户:{
名称:“测试对等方”,
阿凡达://www.gravatar.com/avatar/cd56136f6d9abfdf4a0198dc9ce656c8?s=200&r=pg&d=mm
},
传记:“测试同行传记”,
年份:“2022年”,
课程:[
“CISC124”,
“心理223”,
“心理236”,
“通信200”,
“CISC251”
]
}
设profiles=[];
profiles.push(dummyPeer);
让initialState=[];
profiles.forEach(profile=>{
初始状态。推送(“正常”);
});
let[viewState,setViewState]=useState(initialState);
console.log(viewState);
const openLargeView=(id)=>{
让changeIndex=profiles.map(profile=>profile.\u id).indexOf(id);
setViewState(state=>state[changeIndex]=“大”);
console.log(viewState);
}
const closeLargeView=(id)=>{
让changeIndex=profiles.map(profile=>profile.\u id).indexOf(id);
setViewState(状态=>state[changeIndex]=“正常”);
console.log(viewState);
}
返回(
{profiles.map((profile,index)=>(
{viewState[index]=“正常”(
) : (
)}
))}
)
}
子组件1:
const Peer = ({ profile, openLargeView }) => {
const { _id, user, bio, year, courses } = profile;
const { avatar } = user;
return (<Fragment>
<div className="card-row">
<div className="profile-header">
<h1 className="peer-text row-title"> {user.name} </h1>
<p className="peer-text peer-small"> {year} </p>
<img className="avatar avatar-peer-small" src={avatar} alt='' />
</div>
<button onClick={() => openLargeView(_id)} className="btn-small"> More </button>
</div>
</Fragment>)
}
const Peer=({profile,openLargeView})=>{
const{u id,user,bio,year,courses}=profile;
const{avatar}=用户;
返回(
{user.name}
{year}
openLargeView(_id)}className=“btn small”>更多信息
)
}
儿童部分2:
const ViewPeer = ({ profile, closeLargeView }) => {
const { _id, user, bio, year, courses } = profile;
const { avatar } = user;
let courseElements = courses.map((course, index) =>
<li key={index} className="profile-text"> {course} </li>
);
return (
<Fragment>
<div className="card-md peer-card">
<div className="profile-header">
<h1 className="peer-text"> {user.name} </h1>
<img className="avatar avatar-peer" src={avatar} alt='' />
</div>
<div className="profile-info">
<h2 className="profile-text"> {bio} </h2>
<h2 className="profile-text2"> Year: {year} </h2>
<ul className="course-list"> {courseElements} </ul>
<div className="profile-button-group">
<button onClick={() => closeLargeView(_id)} className="btn-small"> Close </button>
<button className="btn-small"> Send Buddy Request </button>
</div>
</div>
</div>
</Fragment>
)
}
const ViewPeer=({profile,closeLargeView})=>{
const{u id,user,bio,year,courses}=profile;
const{avatar}=用户;
让courseElements=courses.map((课程,索引)=>
{course}
);
返回(
{user.name}
{bio}
年份:{Year}
{courseElements}
closeLargeView(_id)}className=“btn small”>关闭
发送好友请求
)
}
预期和实际结果
我希望当单击第一个组件的按钮时,它会返回到原始组件,但状态变成字符串数组,应用程序崩溃。这里的问题是
viewState
在openLargeView()
和closeLargeView()中更新的方式
调用这些函数时,对setViewState
的调用调用状态更改回调,该回调实际上将viewState
的类型从数组更改为字符串:
/*
Summary of problem with following line of code:
1. The statement: state[changeIndex] = "large" returns the string "large"
2. When executed, the statement returns the "large" string from the callback
3. The viewState therefore becomes a string with value "large"
*/
setViewState(state => state[changeIndex] = "large");
考虑将这些状态更新修改为以下内容:
setViewState(state => {
/*
1. Shallow clone state into a new array with ... spread
2. Assign value of "large" to the "changeIndex" in cloned array
3. Return cloned array as new state for viewState
*/
const arrayClone = [...state];
arrayClone[changeIndex] = "large";
return arrayClone;
});
这确保了setViewState()
回调传回组件的状态为数组类型,这是组件所期望的。一个更完整的示例显示了是否需要进行所有更改:
const Peers = props => {
const profiles = [{
_id: "9asdf98sj3942j4fs9ji",
user: {
name: "Test Peer",
avatar: "//www.gravatar.com/avatar/" +
"cd56136f6d9abfdf4a0198dc9ce656c8?s=200&r=pg&d=mm"
},
bio: "Biography for Test Peer",
year: "2022",
courses: [
"CISC124",
"PSYC223",
"PSYC236",
"COMM200",
"CISC251"
]
}]
let [viewState, setViewState] = useState(["normal"]);
const openLargeView = (id) => {
let changeIndex = profiles.map(profile => profile._id).indexOf(id);
setViewState(state => {
const arrayClone = [...state];
arrayClone[changeIndex] = "normal";
return arrayClone;
});
}
const closeLargeView = (id) => {
let changeIndex = profiles.map(profile => profile._id).indexOf(id);
setViewState(state => {
const arrayClone = [...state];
arrayClone[changeIndex] = "large";
return arrayClone;
});
}
return (
<Fragment>
{profiles.map((profile, index) => (<Fragment key={profile._id} >
{viewState[index] === "normal" ? (
<Peer openLargeView={openLargeView} profile={profile} />
) : (
<ViewPeer closeLargeView={closeLargeView} profile={profile} />
)}
</Fragment>))}
</Fragment>
)
}
const Peers=props=>{
常量配置文件=[{
_id:“9asdf98sj3942j4fs9ji”,
用户:{
名称:“测试对等方”,
阿凡达://www.gravatar.com/avatar/“+
“cd56136f6d9abfdf4a0198dc9ce656c8?s=200&r=pg&d=mm”
},
传记:“测试同行传记”,
年份:“2022年”,
课程:[
“CISC124”,
“心理223”,
“心理236”,
“通信200”,
“CISC251”
]
}]
让[viewState,setViewState]=useState([“正常”]);
const openLargeView=(id)=>{
让changeIndex=profiles.map(profile=>profile.\u id).indexOf(id);
setViewState(状态=>{
常数阵列气旋=[…状态];
ArraCyclone[changeIndex]=“正常”;
回流式旋风分离器;
});
}
const closeLargeView=(id)