我知道,有很多相似的问题。** 重复警报! **
但是:我保证,我会仔细检查所有这些内容。我现在很确定,这是另一种情况,可能与道具成为物体有关(从我在这里阅读的内容)。但无论如何,我无法解决以下问题:
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)}
(请注意:道具)向父组件添加withTracker
/ State
/ Props
,并从sessions
或{{1}中传递state
对象}作为子组件的参数,应重新渲染。
forceUpdate()
可能也很重要:该组件应该在另一个组件也重新渲染的同时重新渲染(显示从微服务返回并写入另一个集合的已上传CSV的内容)。后者实际上确实会重新渲染。.但是该下拉列表却没有.. argh!
答案 0 :(得分:4)
this.state
仅在您调用this.setState()
时才会更改,而您并没有这样做。您正在使用state
中的值初始化props
,但是仅在首次实例化组件时才在构造函数中进行初始化。之后,即使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>
...
)
}
}
通常,除非出于某种原因特别需要存储内部状态,否则所有组件都应为stateless functional components。
答案 1 :(得分:0)
现在我终于解决了它,事实证明组件 did 实际上可以随时更新,但是我没有注意,只是因为其中的最新项数组被悄悄地附加到下拉列表的底部上。但是,这并不是我所期望的,因为我已经发布了该收藏集并以 sorting 降序排列。
// 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
对象作为道具从父级传递到(大)子级。我认为这样更易于阅读和维护。