繁体   English   中英

尽管props中的Object发生变化,但React组件未重新渲染

[英]React component not re-rendering, although Object in props changes

我知道,有很多很多相似的问题。** 重复警报! **

但是:我保证,我会仔细检查所有这些对象。 我现在很确定,这是另一种情况,可能与道具成为物体有关(从我在这里阅读的内容)。 但无论如何,我无法解决以下问题:

class CsvListDropdown extends Component {
    constructor(props) {
        super(props);
        this.state = { sessions: props.sessions }
        this csvsInSession = this.csvsInSession.bind(this);
    }

    csvsInSession(sessions) {
        return (sessions
            .map(keys => Object.entries(keys)[2][1])
            .map((csv, i) => (
                <option value={csv} key={i}>{csv}</option>
            ))
        )
    }

    render() {
        const { isLoading } = this.props
        if (isLoading) { blablabla.. }
        else {
            return (
                ...
                <select value={this.props.sessions[0].currentCsv}>
                    {this.csvsInSession(this.state.sessions)}
                </select>
                ...
            )
        }
    }
}

export default withTracker(() => {
    const handle = Meteor.subscribe('sessions');
    return {
      isLoading: !handle.ready(),
      sessions: Sessions.find({}).fetch() 
    };
})(CsvListDropdown);

现在,从客户端,我将另一个文档写入Sessions集合,其中包含.csv文件名,而此新的csv文件正在上传到远程服务器。 console.log(this.props.sessions)给了我一个数组,它是最新的。 但是组件本身不会重新渲染。

我还不明白的是: console.log(this.state.sessions)返回undefined (注: 状态

到目前为止我尝试过的是:

  • {this.csvsInSession(this.props.sessions)} (注意: props
  • withTracker / State / Props添加到父组件,并将sessions对象从stateprops作为参数传递给子组件,然后应重新呈现。

  • 强制性升级()

  • componentWillUpdate()

可能也很重要:该组件应该在另一个组件也重新渲染的同时重新渲染(显示从微服务返回并写入另一个集合的已上传CSV的内容)。 后者实际上确实会重新渲染。但是该下拉列表却没有。

仅当您调用this.setState()而不执行时, this.state才会更改。 您将使用props的值初始化state ,但仅在首次实例化组件时才在构造函数中进行初始化。 此后,即使props更改,您的组件也可能会重新渲染,但其显示的内容不会更改,因为state尚未更新。

实际上,似乎没有任何理由在该组件中以状态存储数据。 它也可能是功能性的演示组件:

function CsvListDropdown(props) {
    function csvsInSession(sessions) {
        return (sessions
            .map(keys => Object.entries(keys)[2][1])
            .map((csv, i) => (
                <option value={csv} key={i}>{csv}</option>
            ))
        )
    }

    const { isLoading } = props;
    if (isLoading) { blablabla.. }
    else {
        return (
            ...
            <select>
                {csvsInSession(props.sessions)}
            <select>
            ...
        )
    }
}

通常,除非出于某种原因特别需要存储内部状态,否则所有组件都应为无状态功能组件

现在我终于解决了它,而且事实证明,该组件实际上确实随时更新,但我没有注意到它,只是因为数组中的最新项目是悄悄地追加到下拉列表的底部 但是,这并不是我所期望的,因为我以降序排序 发布了该系列。

// server-side
Meteor.publish('sessions', function() {
    return Sessions.find({ userId: this.userId }, { sort: {createdAt: -1} });
});

服务器端似乎是错误的排序位置。 它根本没有作用。 因此,在订阅时在客户端排序:

// client-side
export default withTracker(() => {
    const handle = Meteor.subscribe('sessions');
    return {
      isLoading: !handle.ready(),
      sessions: Sessions.find({}, { sort: {createdAt: -1} }).fetch() 
    };
})(App)

我已经从问题中省略了一个重要的细节,那就是如何设置下拉字段的

<select value={this.props.sessions[0].currentCsv}>
    {this.csvsInSession(sessions)}
</select>

因此,我们汲取了以下教训:如果您认为自己的react组件没有重新渲染,请在进行假设之前始终检查是否正确。


作为调试的副作用,我重构了我的组件。 现在, Meteor.subscribe()位于父组件内,该组件包含必须处理sessions对象的所有子代。 然后sessions对象作为道具从父级传递到(大)子级。 我认为这种方式更具可读性,并且更容易维护。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM