我了解到该问题的措词有些含糊,因此我将进行扩展。这是我的一个个人项目,我学习了一些React基础知识并熟悉了socket.io
我有一个CollapsibleList组件和一个NestedList组件,该组件呈现CollapsibleList组件的数组。
NestedList具有一个事件处理程序,该事件处理程序在组件的componentWillMount中设置。事件是当菜单从我的服务器通过socket.io到达时。菜单到达时,新的CollapsibleList被添加到数组,并且状态被更改以触发重新渲染。这些事件由通过componentDidMount(get-menus)发出的初始socket.io事件触发。
CollapsibleList通过onclick折叠/展开,该onclick使用通过NestedList的props传递的toggleVisiblity方法,其状态确定其子CollapsibleList组件是否打开。
问题:CollapsibleList道具(来自NestedList的状态)在更改NestedList的状态时不会更改。我已经检查了调试器中的属性,并且已经停留了几天。换句话说,CollapsibleList元素出现在浏览器窗口中,但是单击它只会更改NestedList的状态,并且CollapsibleList的props不会更改,因此不会出现/消失。我认为这与在socket.io回调中创建绑定了“ this”的CollapsibleLists有关,因为CollapsibleList的“ collapsed”属性取决于this.state [restaurantId] .collapsed。来源如下,如果不清楚,我可以添加更多解释。
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>
);
}
}
答案 0 :(得分:1)
您将CollapsibleList
个React元素推送到实例上的数组,这意味着当状态或道具更改时,不会创建新的React元素,也不会从render方法返回它。
您应该始终从状态和props中的render方法中获取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>
);
}
}