我有两个标签,分别包含一些bulletins
和newses
。并在每个标签上添加badge
,以判断是否已查看所有项目。
如果查看了所有bulletins
或newses
,则该标签上的徽章将隐藏,否则徽章将会显示。
所有需要的计算都在函数checkBulletinHasNew
和checkNewsesHasNew
中定义。但是当我在浏览器中打开它时,它崩溃了。
我非常确定崩溃的原因是这两个函数中的this.setState
,因为当我评论this.setState
并将其替换为console.log
句子时,浏览器就像通常
我该如何解决?
import React from 'react';
import {Tab, Tabs} from '../../../../../components/Tabs';
import {TitleBar} from '../../../../../components/TitleBar';
import List from './List.jsx'
import ListItem from './ListItem.jsx'
class MsgCenter extends React.Component {
constructor() {
super()
this.checkBulletinHasNew = this.checkBulletinHasNew.bind(this)
this.checkNewsesHasNew = this.checkNewsesHasNew.bind(this)
this.state = {
bulletinHasNew: false,
newsesHasNew: false,
active: true
}
}
handleTabChanged() {
}
checkBulletinHasNew(bulletins) {
if (bulletins && bulletins.length > 0) {
for(var i = 0;i < bulletins.length;i++){
if (!bulletins[i].viewed){
this.setState({bulletinHasNew: true})
//console.log('bulletings has un-viewed')
return
}
}
this.setState({bulletinHasNew: false})
//console.log('bulletings are viewed')
return
}
}
checkNewsesHasNew(newses) {
if (newses && newses.length > 0) {
for(var i = 0;i < newses.length;i++) {
if(!newses[i].viewed){
this.setState({newsesHasNew: true})
//console.log('newses has un-viewed')
return
}
}
this.setState({newsesHasNew: false})
//console.log('newses are viewed')
return
}
}
componentWillUpdate(nextProps, nextState) {
this.checkBulletinHasNew(nextProps.bulletins.items)
this.checkNewsesHasNew(nextProps.newses.items)
}
componentDidMount(){
this.checkBulletinHasNew(this.props.bulletins.items)
this.checkNewsesHasNew(this.props.newses.items)
}
render() {
return (
<div>
<TitleBar title="Message Center"></TitleBar>
<Tabs showInkBar>
<Tab label="Bulletins" value={0} badge={this.state.bulletinHasNew ?
<span className="circleBadge">badge</span> :
null
}>
<List>
{
this.props.bulletins.items.map(function (item) {
return (
<ListItem item={item} key={'bulletin.' + item.id}></ListItem>
)
})
}
</List>
</Tab>
<Tab label="Newses" value={1} badge={this.state.newsesHasNew ?
<span className="circleBadge">badge</span> :
null
}>
<List>
{
this.props.newses.items.map(function (item) {
return (
<ListItem item={item} key={'news' + item.id}></ListItem>
)
})
}
</List>
</Tab>
</Tabs>
</div>
)
}
}
MsgCenter.defaultProps = {
activeSubject: 'bulletins',
bulletins: {
isFetching: false,
isRefreshing: false,
page: 1,
totalPage: 1,
items: [
{
id: 1,
title: 'This is bulletin 1',
publicDate: 1461513600000,
viewed: true
},
{
id: 2,
title: 'This is bulletin 2',
publicDate: 1461427200000,
viewed: true
},
{
id: 3,
title: 'This is bulletin 3',
publicDate: 1461340800000,
viewed: true
},
{
id: 4,
title: 'This is bulletin 4',
publicDate: 1461254400000,
viewed: true
}
]
},
newses: {
isFetching: false,
isRefreshing: false,
page: 1,
totalPage: 1,
items: [
{
id: 5,
title: 'This is news 1',
publicDate: 1458748800000,
viewed: false
},
{
id: 6,
title: 'This is news 2',
publicDate: 1458662400000,
viewed: false
},
{
id: 7,
title: 'This is news 3',
publicDate: 1458576000000,
viewed: true
},
{
id: 8,
title: 'This is news 4',
publicDate: 1458489600000,
viewed: true
},
]
}
}
module.exports = MsgCenter
答案 0 :(得分:2)
文档特别声明您不应在这些生命周期方法中使用set state:
您不能在此方法中使用this.setState()。如果您需要更新 状态响应prop更改,使用componentWillReceiveProps 代替。
我不确定它到底在做什么,但我猜测setState触发另一个“componentWillX”,然后调用setState触发另一个“componentWillX”,然后调用setState触发另一个“componentWillX”,反过来调用setState触发另一个“componentWillX”,然后调用setState ......
答案 1 :(得分:0)
这可能(可能)不是你崩溃原因的答案,但我建议改变这个:
checkBulletinHasNew(bulletins) {
if (bulletins && bulletins.length > 0) {
for(var i = 0;i < bulletins.length;i++){
if (!bulletins[i].viewed){
this.setState({bulletinHasNew: true})
//console.log('bulletings has un-viewed')
return
}
}
this.setState({bulletinHasNew: false})
//console.log('bulletings are viewed')
return
}
}
对此:
checkBulletinHasNew(bulletins) {
if (bulletins && bulletins.length > 0) {
var hasUnviewed = false;
for(var i = 0;i < bulletins.length;i++){
if (!bulletins[i].viewed){
hasUnviewed = true;
//console.log('bulletins have un-viewed')
}
}
this.setState({bulletinHasNew: hasUnviewed})
//console.log('bulletins are viewed')
}
}
甚至更短,array.reduce()
:
checkBulletinHasNew(bulletins) {
if (bulletins && bulletins.length > 0) {
var hasUnviewed = bulletins.reduce(function(prevVal, curVal, i, array) {
return prevVal || !curVal.a;
},false);
this.setState({bulletinHasNew: hasUnviewed})
//console.log('bulletins are viewed')
}
}
获得更清洁的功能,保证只进行1次状态更新 与其他类似方法相同。
答案 2 :(得分:0)
我认为你的构造函数应该是这样的。否则你将两次设置状态。
constructor() {
super()
this.state = {
bulletinHasNew: false,
newsesHasNew: false,
active: true
}
这将导致渲染方法将使用我们通过构造函数设置的默认值进行渲染。之后,您可以在组件安装在DOM上后更改值。
您可以删除 componentWillUpdate ,然后依靠 componentDidMount 来设置状态。如果要在重新渲染组件后更改setStatus,请使用 componentDidUpdate
注意:我建议将两个(bulletinHasNew,newsesHasNew)状态设置在一起,以避免两次渲染调用。
希望这是有道理的。
答案 3 :(得分:-1)
感谢@Chris,这个答案很有帮助,因为我没有仔细阅读文档。那个真正的@Rajeesh Madambat,除了setState
之外,你不能在那些生命周期函数中调用componentWillReceiveProps
方法,但是,这个函数没有任何用处对我来说。
我是reactjs的新手,所以当我想控制一个组件的外观时(这里是badge
),我所提出的所有反射都是创建一个{{1管理它。 那是错的,因为这种状态一直依赖道具。
想象一下:我在一开始就初始化两个状态,但这没有意义,因为这两个状态的值取决于props.所以我必须在组件收到道具后立即设置这两个状态。这意味着没有办法避免这种呼叫 - 设置状态 - 生命周期陷阱。
如果你有一些值一直依赖于道具,不要把它作为状态(也许是道具?),把它作为计算值。并且你在渲染方法中计算这些计算值。这个问题发生在我身上只是因为我在React中以错误的方式思考。
所以,有了@ wintvelt关于代码优化的很好的建议,我可以重写我的代码,它可以按预期工作:
state
随意对此发表评论。