我在改变状态吗?如果可以,有哪些解决方案可用?

时间:2019-02-11 01:39:00

标签: reactjs ecmascript-6 state react-state-management

我有一个简单的组件,该组件从对象数组构建报告列表,我试图添加过滤器和排序功能(在一定程度上确实起作用),排序功能有效,但我担心我尽管尝试将原始状态复制到新数组中,但仍在更改状态。

我的过滤器在第一时间工作,但是由于状态已突变,或者因为我无法过滤初始状态,因此它不会过滤其他结果?这使我困惑了几个小时,非常感谢您的帮助。

非常感谢

constructor(props) {
    super(props);
    this.state = {
        reports: props.data
    };
    this.handleSortBy = this.handleSortBy.bind(this);
    this.handleFilterType = this.handleFilterType.bind(this);
}

handleSortBy(event) {
    const copy = [...this.state.reports];
    if (event.target.value === 'A-Z') {
        return this.setState({
            reports: copy.sort((a, b) => a.name.localeCompare(b.name))
        });
    }
    if (event.target.value === 'Z-A') {
        this.setState({
            reports: copy
                .sort((a, b) => a.name.localeCompare(b.name))
                .reverse()
        });
    }
}

handleFilterType(event) {
    this.setState({
        reports: this.state.reports.filter(item => {
            return item.type === event.target.value;
        })
    });
}

预先感谢:)

2 个答案:

答案 0 :(得分:0)

我认为问题在于每次您进行过滤时,您都是从state.reports中删除项目,而从未从props.data中收回它们。

相反,每次进行过滤/排序时,您都应从state.reports中重建props.data

或者,更好的IMO方法是将过滤/排序设置存储在state中,并根据当前设置对props.data中的render进行过滤/排序。

答案 1 :(得分:0)

一种简单的方法(取决于您的用例)是在两个更新函数中将this.state.reports替换为this.props.data。 (尽管,如果这样做,则无法同时应用排序和过滤器)

但是我同意ModestLeech的观点,最好将过滤器存储在状态中。为此,请将您的过滤器代码更改为:

handleFilterType(event) {
    this.setState({
        filter: event.target.value;
        })
    });
}

在渲染方法中,假设您使用的是地图,则可以将地图更改为this.state.reports.filter(item => (this.state.filter===undefined || item.type===this.state.filter)).map(...)

编辑:

使用React需要担心两种类型的突变。

一个不是在改变道具(即,改变组件无法控制的状态)。由于Javascript通过引用传递数组和对象,因此如果您要在sort上使用this.props.data,它将实际上修改组件的父级(或祖父母级或定义的位置)中存在的数组。好消息是您的原始代码已经避免了这种情况-可能是偶然的情况。 handleSortBy在对该数组进行突变之前对其进行了复制,handleFilterType使用Array.prototype.filter来创建一个新数组。

您需要担心的第二个突变是不使用setState来更改本地状态。在this.state.reports.sort(...)中调用render会更改本地状态,但是React不会知道,也不会重新渲染。这不是问题,因为您在需要之前就进行了排序,但是直接改变状态是危险的,因为它可能导致错误,您作为开发人员认为某些情况下应该或不应进行更改,但实际情况有所不同

您最初的filter问题与意外突变无关。问题在于,第一次使用过滤器调用this.setState时,您重写了this.state.reports,无法收回它。还有一个问题是,如果this.props.data在父项中进行了更改,则新报表将永远不会出现在此组件中,因为您仅在首次创建组件时才读取道具。

推荐的React方法是不要存储来自prop的状态,除非您只是使用prop设置一些初始状态,并且所有将来的更新都将来自组件内部。但是,假设该组件最终并没有拥有报告列表,那么从长远来看,在this.props.data中复制render并对其进行排序和过滤会更简单。然后,如果在组件树的更高处添加或删除了任何内容,则无需编写任何特殊逻辑即可更新该组件的本地状态。