Javascript React-回调中未使用props表达式集重新排序的子组件数组
我知道这个问题的措辞有点含糊不清,所以我将进一步阐述。这是我的一个个人项目,我学习了一些基础知识,并熟悉socket.io 我有一个可折叠列表组件和一个NestedList组件,它呈现一个可折叠列表组件数组 NestedList有一个在组件的componentWillMount中设置的事件处理程序。事件发生在通过socket.io从我的服务器到达菜单时。当菜单到达时,将向数组中添加一个新的可折叠列表,并更改状态以触发重新加载。事件由通过componentDidMount(获取菜单)发出的初始socket.io事件触发 可折叠列表通过其onclick进行折叠/解压,onclick使用从NestedList通过props传递的toggleVisiblity方法,NestedList的状态决定其子可折叠列表组件是否打开 问题:可折叠列表道具(来自NestedList的状态)不会随着所述NestedList状态的改变而改变。我已经检查了调试器中的属性,我已经被困了好几天了。换句话说,可折叠列表元素出现在浏览器窗口中,但单击它只会更改嵌套列表的状态,可折叠列表的支柱不会更改,因此不会出现/消失。我认为这与在socket.io回调中创建与“this”绑定的可折叠列表有关,因为可折叠列表的“collapsed”属性依赖于此。state[restaurantId]。collapsed。来源如下,如果不清楚,我可以补充更多的解释Javascript React-回调中未使用props表达式集重新排序的子组件数组,javascript,reactjs,socket.io,Javascript,Reactjs,Socket.io,我知道这个问题的措辞有点含糊不清,所以我将进一步阐述。这是我的一个个人项目,我学习了一些基础知识,并熟悉socket.io 我有一个可折叠列表组件和一个NestedList组件,它呈现一个可折叠列表组件数组 NestedList有一个在组件的componentWillMount中设置的事件处理程序。事件发生在通过socket.io从我的服务器到达菜单时。当菜单到达时,将向数组中添加一个新的可折叠列表,并更改状态以触发重新加载。事件由通过componentDidMount(获取菜单)发出的初始so
class CollapsibleList extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<List>
<ListItem
button
onClick={() => {
this.props.collapseEventHandler(this.props.restaurantId);
}}
>
<ListItemText primary="Collapse me!" />
</ListItem>
<ListItem>
<Collapse in={!this.props.collapsed} timeout="auto" unmountOnExit>
<ListItemText primary="Hello World!" />
</Collapse>
</ListItem>
</List>
);
}
}
class NestedList extends React.Component {
constructor(props) {
super(props);
//let menuData = props.menuData.map()
this.toggleVisiblity = this.toggleVisiblity.bind(this);
this.arrayOfMenus = [];
}
componentWillMount() {
socket.on(
"menu-arrived",
function(menuJson) {
if (menuJson.response.menu.menus.items) {
let restaurantId = menuJson.restaurant_id;
//let menuId = menuJson.response.menu.menus.items[0].menuId;
this.arrayOfMenus.push(
<CollapsibleList
collapsed={this.state[restaurantId].collapsed}
collapseEventHandler={this.toggleVisiblity}
restaurantId={restaurantId}
key={restaurantId}
/>
);
this.setState(function(prevState, props) {
return {
[restaurantId]: {
collapsed: prevState[restaurantId].collapsed,
updated: true
}
};
});
}
}.bind(this)
);
}
componentDidMount() {
getNearbyRestaurantRawData().then(
function(rawData) {
let restaurantIds = parseOutVenueIds(rawData);
let menusOpen = {};
for (let i = 0; i < restaurantIds.length; i++) {
menusOpen[restaurantIds[i]] = {
collapsed: true
};
}
this.setState(menusOpen, () => {
socket.emit("get-menus", {
ids: restaurantIds
});
});
}.bind(this)
);
}
toggleVisiblity(restaurantId) {
this.setState(function(prevState, props) {
let newState = Object.assign({}, prevState);
newState[restaurantId].collapsed = !prevState[restaurantId].collapsed;
return newState;
});
}
render() {
return (
<List>
<React.Fragment>
<CssBaseline>{this.arrayOfMenus}</CssBaseline>
</React.Fragment>
</List>
);
}
}
类可折叠列表扩展了React.Component{
建造师(道具){
超级(道具);
}
render(){
返回(
{
this.props.collapseEventHandler(this.props.restaurantId);
}}
>
);
}
}
类NestedList扩展了React.Component{
建造师(道具){
超级(道具);
//让menuData=props.menuData.map()
this.togglevisibility=this.togglevisibility.bind(this);
this.arrayOfMenus=[];
}
组件willmount(){
插座(
“菜单到了”,
函数(menuJson){
if(menuJson.response.menu.menus.items){
让restaurantId=menuJson.restaurant\u id;
//让menuId=menuJson.response.menu.menu.items[0].menuId;
这是arrayOfMenus推(
);
this.setState(函数(prevState、props){
返回{
[餐厅]:{
折叠:prevState[餐厅]。已折叠,
更新:正确
}
};
});
}
}.绑定(此)
);
}
componentDidMount(){
getNearbyRestaurantRawData()。然后(
函数(原始数据){
let restaurantIds=parseOutVenueIds(原始数据);
让menusOpen={};
for(设i=0;i{
发出(“获取菜单”{
ID:餐厅
});
});
}.绑定(此)
);
}
切换可视性(餐厅){
this.setState(函数(prevState、props){
让newState=Object.assign({},prevState);
newState[restaurantId]。已折叠=!prevState[restaurantId]。已折叠;
返回新闻状态;
});
}
render(){
返回(
{this.arrayOfMenus}
);
}
}
您正在将可折叠列表
React元素推送到实例上的数组中,这意味着当状态或道具更改时,将不会创建新的React元素并从渲染方法返回
您应该始终从呈现方法中的状态和道具派生UI
示例
class NestedList extends React.Component {
state = { restaurantIds: [] };
componentWillMount() {
socket.on("menu-arrived", menuJson => {
if (menuJson.response.menu.menus.items) {
let restaurantId = menuJson.restaurant_id;
this.setState(prevState => {
return {
restaurantIds: [...prevState.restaurantIds, restaurantId],
[restaurantId]: {
collapsed: prevState[restaurantId].collapsed,
updated: true
}
};
});
}
});
}
// ...
render() {
return (
<List>
<React.Fragment>
<CssBaseline>
{this.state.restaurantIds.map(restaurantId => (
<CollapsibleList
collapsed={this.state[restaurantId].collapsed}
collapseEventHandler={this.toggleVisiblity}
restaurantId={restaurantId}
key={restaurantId}
/>
))}
</CssBaseline>
</React.Fragment>
</List>
);
}
}
类嵌套列表扩展了React.Component{
状态={restaurantIds:[]};
组件willmount(){
on(“菜单到达”,menuJson=>{
if(menuJson.response.menu.menus.items){
让restaurantId=menuJson.restaurant\u id;
this.setState(prevState=>{
返回{
restaurantIds:[…prevState.restaurantIds,restaurantId],
[餐厅]:{
折叠:prevState[餐厅]。已折叠,
更新:正确
}
};
});
}
});
}
// ...
render(){
返回(
{this.state.restaurantIds.map(restaurantId=>(
))}
);
}
}
不要将JSX推到this.arrayOfMenus
,而是应该将数组中的所有restaurantId
保持为状态,并从render方法中的状态派生JSX。对,这很有意义,因为我可以避免任何“this.state”问题,我将尝试这样做。考虑到“this”绑定是准确的,我真的很好奇为什么道具没有随着重播器的出现而改变。你正在将
推到一个数组中,所以当道具或状态改变时,你永远不会为可折叠列表创建新的React元素。您应该总是从render方法中的状态和道具派生JSX。我明白了,所以我以前的理解是有缺陷的。如果jsx不是在render方法中派生的,react无法直接替换/修改它?。如果只创建元素并将它们存储在数组中,则永远不会创建新元素。我知道我以前的错误所在。render所能看到的只是显示现有组件数组的指令。状态的所有变化意味着对渲染的另一次调用。是的!我感谢你的及时帮助。我希望我能提高投票率,但看起来我需要更多的声誉来进行任何访问