Yur*_*mos 11 javascript ecmascript-6 reactjs
我试图在从子组件改变状态后更新状态并且没有成功,每次我调用函数时我得到堆栈溢出,prop都调用无限次函数,但问题是,我真的需要更新这种状态,目前还不知道如何解决这个问题.
亲
import React, { PropTypes, Component } from 'react';
import Card from './card/card.js';
import style from './style.scss';
class Container extends Component {
constructor(props) {
super(props);
this.state = {
isFlipped: false,
oneOpened: true,
history: [],
childFlipToFalse: false,
};
this.historyToggleStates = this.historyToggleStates.bind(this);
this.forceFlipParent = this.forceFlipParent.bind(this);
this.checkForceFlip = false;
}
historyToggleStates(bool, id, callForceFlip) {
this.setState({
history: this.state.history.concat([{ opened: bool, id }]),
}, () => {
console.log('inside historyToggleStates');
if (callForceFlip) {
this.forceFlipParent()
}
});
}
forceFlipParent() {
const { history } = this.state;
const first = history[0];
const last = history[history.length - 1];
const beforeLast = history[history.length - 2];
console.log('force FLIP PARENT');
if (history.length > 1) {
if (JSON.stringify(last.opened) === JSON.stringify(beforeLast.opened)) {
this.setState({ childFlipToFalse: true });
}
}
}
render() {
const rest = {
basePath: this.props.basePath,
backCard: this.props.backCard,
isShowing: this.props.isShowing,
historyToggleStates: this.historyToggleStates,
isOpened: this.state.isOpened,
isFlipped: this.state.isFlipped,
checkOneOpened: this.checkOneOpened,
history: this.state.history,
forceFlip: this.state.childFlipToFalse,
flipToFalse: this.forceFlipParent,
};
const cardsMap = this.props.cards.map((item, key) => {
return (
<Card
item={item}
keyId={key}
{...rest}
/>
);
});
return (
<div className="col-lg-12 text-center">
{cardsMap}
</div>
);
}
}
export default Container;
Container.propTypes = {
cards: PropTypes.array.isRequired,
item: PropTypes.func,
basePath: PropTypes.string,
backCard: PropTypes.string,
isShowing: PropTypes.bool,
};
Run Code Online (Sandbox Code Playgroud)
儿童
import React, { Component, PropTypes } from 'react';
import ReactCardFlip from 'react-card-flip';
import style from './style.scss';
class Card extends Component {
constructor(props) {
super(props);
this.state = {
isFlipped: false,
update: false,
id: 9999999,
};
this.handleClick = this.handleClick.bind(this);
this.checkOneOpened = this.checkOneOpened.bind(this);
}
componentWillReceiveProps(nextprops) {
const { history, isFlipped, historyToggleStates } = this.props;
const last = nextprops.history[nextprops.history.length - 1];
const beforeLast = nextprops.history[nextprops.history.length - 2];
console.log(history);
console.log(nextprops.history);
if (nextprops.forceFlip && last.id === nextprops.keyId) {
this.setState({ isFlipped: !this.state.isFlipped, update: true, id: last.id }, () => {
console.log('callback willreceiveprops', this.state.isFlipped);
historyToggleStates(this.state.isFlipped, nextprops.keyId, true, this.state.update); **<--- Here's my problem**
});
}
if (nextprops.forceFlip && beforeLast.id === nextprops.keyId) {
this.setState({ isFlipped: !this.state.isFlipped, update: true, id: beforeLast.id }, () => {
});
}
}
handleClick(e, nextState, id) {
const { keyId, historyToggleStates, forceFlip } = this.props;
if (e) {
e.preventDefault();
}
if (!nextState) {
this.setState({ isFlipped: !this.state.isFlipped }, () => {
historyToggleStates(this.state.isFlipped, keyId, true, this.state.update);
});
} else {
// historyToggleStates(nextState, id, false);
return 0;
}
}
checkOneOpened(e) {
if (!this.props.isShowing) {
this.handleClick(e);
}
}
render() {
const { item, basePath, backCard, isShowing, isFlipped, forceFlip } = this.props;
return (
<div className={`col-lg-2 col-md-3 col-sm-6 ${style.card}`}>
<ReactCardFlip
isFlipped={this.state.isFlipped}
flipSpeedBackToFront={0.9}
flipSpeedFrontToBack={0.9}
>
<div key="front">
<button
onClick={() => {this.checkOneOpened()}}
>
<img src={isShowing ? `${basePath}${item.image}` : backCard} alt={item.name} className={`${style.img}`} />
</button>
</div>
<div key="back">
<button
onClick={() => {this.checkOneOpened()}}
>
<img src={isShowing ? backCard : `${basePath}${item.image}`} alt={item.name} className={`${style.img}`} />
</button>
</div>
</ReactCardFlip>
</div>
);
}
}
export default Card;
Card.propTypes = {
basePath: PropTypes.string,
backCard: PropTypes.string,
isShowing: PropTypes.bool,
historyToggleStates: PropTypes.func,
isOpened: PropTypes.bool,
isFlipped: PropTypes.bool,
checkOneOpened: PropTypes.func,
};
Run Code Online (Sandbox Code Playgroud)
historyToggleStates(this.state.isFlipped,nextprops.keyId,true,this.state.update)是我的问题的根源,我真的需要更新它,因为我正在比较他里面的数组和另一个数组
更新1:我知道我对historyToggleStates的调用是在几个案例中完成的,但是你可以看到我需要从父级更新我的状态,因为我每次都在我的componentWillReceiprops中从我的子组件中比较这个值.
对于这种情况,是否真的有必要成为州经理?我正在遵循Dan Abramov的提示,并且避免提高系统的复杂性,任何提示都会受到赞赏.
小智 3
子组件的componentWillReceiveProps,首先在父组件使用新的 props 进行更新时被触发,触发父组件中的更新(使用historyToggleStates)。
然而,这个周期取决于以下因素:
if (nextprops.forceFlip && last.id === nextprops.keyId) {
Run Code Online (Sandbox Code Playgroud)
即如果组件的传入 propkeyId与历史记录中的最后一个组件相同keyId。换句话说,当子级更新时,历史记录中的最后一个组件将始终运行此代码块(只要为forceFliptrue)。
forceFlip的值取决于以下因素:
if (history.length > 1) {
if (JSON.stringify(last.opened) === JSON.stringify(beforeLast.opened)) {
Run Code Online (Sandbox Code Playgroud)
forceFlip如果历史记录中的任何最后两个组件同时打开,则ie设置为 true。
然后,正如您所说的historyToggleStates被触发,父级被更新,子级componentWillReceiveProps被触发并重复循环。
可能的解决方法
现在我认为这是有意设计的,如果最后两张牌同时打开,它们必须被强制翻转,即关闭。
为了实现这一目标,我想说不要将卡的状态保留在卡组件中本地化,而是将其拉至父组件状态并保持子卡组件不可知。在父级中,维护类似cardsState(也许更好的名称)的名称,并使用它来决定是否必须打开卡。如果您检测到最后两张同时打开的卡片在历史记录中处于打开状态,只需将它们的状态设置为 false 即可关闭它们。
这将使您摆脱对变量的依赖forceFlip,并使您的子卡组件更简单 - 仅当状态显示打开时才打开它们。
| 归档时间: |
|
| 查看次数: |
1141 次 |
| 最近记录: |