在列表之间移动具有状态的元素

时间:2019-03-19 20:25:13

标签: reactjs state

我在这里所说的服务器基本上是一个列表项,其中包含一些数据,例如标题,标志等,

enter image description here

我基本上有两个“服务器”列表:

第一个包含收藏的服务器。另一个包含其他服务器。

每当有人“喜欢”服务器时,应将其项从第二个列表移至第一个列表,并且他的“心脏”应变为红色。

每当有人“不喜欢”服务器时,都会发生相同的过程,但是倒退:服务器应移至第二个列表,并且他的心又变灰。

我能够毫无问题地在列表之间移动元素,但是其渲染发生了奇怪的事情,我无法理解要解决的问题:

我在.gifv中记录了发生了什么:https://i.imgur.com/i5QHNml.gifv

我为此主题删除了无用的代码,但是它仍然很大,很抱歉。

ServerList.js

import * as React from 'react';
import { List, Collapse, ListItem, ListItemIcon, ListItemText, ListSubheader } from '@material-ui/core';
import { Favorite, Computer, ExpandLess, ExpandMore } from "@material-ui/icons";
import ServerListItem from "./ServerListItem";
import SearchBar from './SearchBar';

export default class ServerList extends React.Component {

onSearch(text) {
    ... things about searchbar, not worth to include ...
}

constructor(props) {
    super(props);
    this.state = {
        offset: 0,
        favoritesOpen: false,
        allOpen: true,
    };
    this.onSearch = this.onSearch.bind(this);

    this.serverList = this.props.servers
        .sort((a, b) => { ... sorting servers ... })
        .map((server) => {
            return (
                <ServerListItem
                    country={server.country}
                    hostname={server.hostname}
                    players={server.players}
                    maxplayers={server.maxplayers}
                    level={server.level}
                    host={server.endpoint}
                    onFavorited={ flag => {
                        let index = this.favorites.indexOf(server.hostname);
                        if(!flag && index >= 0){
                            this.favorites.splice(index, 1);
                            this.forceUpdate();
                        }
                        if(flag && index === -1){
                            this.favorites.push(server.hostname);
                            this.forceUpdate();
                        }
                    }}
                />
            )
        });

    this.favorites = [];
}

render() {
    let allServersFiltered = this.serverList
        .filter((it) => { ... things about searchbar, not worth to include ... });

    let otherServers = allServersFiltered
        .filter((it, index) => (
            !this.favorites.includes(it.props.hostname) &&
            index >= this.state.offset && index < this.state.offset + 10
        ));

    return(
            <List
                subheader={ ... things about searchbar, not worth to include ... }
            >
                <ListItem button onClick={() => { this.setState({favoritesOpen: !this.state.favoritesOpen}) }}>
                    <ListItemIcon>
                        <Favorite />
                    </ListItemIcon>
                    <ListItemText inset primary="Favorites" />
                    { this.state.favoritesOpen ? <ExpandLess /> : <ExpandMore /> }
                </ListItem>
                {
                    <Collapse in={this.state.favoritesOpen} timeout={"auto"} unmountOnEdit>
                        <List component={"div"}>
                            {
                                this.favorites.length === 0
                                    ? <ListItemText inset primary={"You have no favorite servers :c"}/>
                                    : this.serverList.filter((it) => this.favorites.includes(it.props.hostname))
                            }
                        </List>
                    </Collapse>
                }
                <List>
                    <ListItem button onClick={() => {this.setState({ allOpen: !this.state.allOpen })}}>
                        <ListItemIcon>
                            <Computer />
                        </ListItemIcon>
                        <ListItemText inset primary="All Servers" />
                        { this.state.allOpen ? <ExpandLess /> : <ExpandMore /> }
                    </ListItem>
                    <Collapse in={this.state.allOpen} unmountOnEdit>
                        {
                            otherServers.length === 0
                            ? <ListItemText inset primary={"No more servers found :c"}/>
                            : otherServers
                        }
                    </Collapse>
                </List>
            </List>
    );
}
}

ServerListItem.js

import './ServerListItem.css'
import * as React from 'react';
import { Badge } from 'react-bootstrap'
import { ListItemSecondaryAction, ListItem, ListItemAvatar, Avatar, ListItemText, 
IconButton } from "@material-ui/core";
import { Favorite } from '@material-ui/icons'

export default class ServerListItem extends React.Component{

constructor(props){
    super(props);
    this.state = { favorited: false };
    this.toggleFavorite = this.toggleFavorite.bind(this);
}


toggleFavorite() {
    if(this.props.onFavorited) this.props.onFavorited(!this.state.favorited); //calls onFavorite callback with the current state
    this.setState({ favorited: !this.state.favorited });
}

render() {
    let flag = `https://www.countryflags.io/${this.props.country}/shiny/64.png`;

    return(
        <ListItem>
            <ListItemAvatar>
                <Avatar src={flag} alt={this.props.flag}/>
            </ListItemAvatar>
            <ListItemText
                primary={this.props.hostname}
                secondary={ ... just the badges, not worth to include ... }
            />
            <ListItemSecondaryAction>
                <IconButton aria-label="Favorite" onClick={this.toggleFavorite}>
                    <Favorite className={ this.state.favorited && 'favorited' }/>
                </IconButton>
            </ListItemSecondaryAction>
        </ListItem>
    );
}
}

我阅读了一些有关在元素渲染时清除状态的内容,但是我不能很好地理解这个概念,并且在使它起作用方面应该做些困难。我也无法理解为什么我的代码会移动正确的元素,却会触发错误的元素(因为状态更改是在同一方法中调用的)。

0 个答案:

没有答案