- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我试图在从子组件更改状态后更新状态但没有成功,每次我调用该函数时都会出现堆栈溢出,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,
};
child
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,
};
historyToggleStates(this.state.isFlipped, nextprops.keyId, true, this.state.update) 是我问题的根源,我真的需要更新它,因为我正在将他内部的数组与另一个数组进行比较
更新 1:我知道我对 historyToggleStates 的调用是在几个案例中完成的,但正如您所看到的,我需要从父级更新我的状态,因为我每次都在我的子组件的 componentWillReceiprops 中比较这个值。
这种情况真的需要状态管理器吗?我正在遵循 Dan Abramov 中的提示,并避免增加系统的复杂性,任何提示将不胜感激。
最佳答案
子组件的 componentWillReceiveProps
,首先在父组件使用新 Prop 更新时触发,触发父组件的更新(使用 historyToggleStates
) .
但是对于这个周期取决于以下几点:
if (nextprops.forceFlip && last.id === nextprops.keyId) {
即如果组件传入的 prop 的 keyId
与历史记录中的最后一个组件的 keyId
相同。换句话说,当子级更新时,如果 forceFlip
为真,则历史记录中的最后一个组件将始终运行此代码块。
forceFlip
的值取决于以下内容:
if (history.length > 1) {
if (JSON.stringify(last.opened) === JSON.stringify(beforeLast.opened)) {
即forceFlip
如果历史记录中的最后两个组件同时打开,则设置为 true。
然后,正如您所说,historyToggleStates
被触发,父级得到更新,子级的 componentWillReceiveProps
被触发,然后循环重复。
可能的解决方法
现在我认为它是有意设计的,如果最后两张牌同时打开,它们必须被强制翻转,即关闭。
为了实现这一点,我建议不要将卡片的状态保留在卡片组件中,而是将其拉至父组件状态并让子卡片组件不可知。在父级中,维护类似 cardsState
(也许是更好的名字)的东西,并用它来决定是否必须打开卡片。如果您检测到最近两个同时打开的卡片在历史记录中处于打开状态,只需将它们的状态设置为 false 即可关闭它们。
这将使您摆脱对 forceFlip
变量的依赖,并使您的子卡片组件更简单 - 只有在状态显示打开时才打开它们。
关于javascript - componentWillReceiveProps 和 componentDidUpdate 无限循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45270253/
您好,我正在调用 componentdidupdate 以便像这样使用新的 ToDos 重新呈现我的页面 this.state = { displayToDos
我收到以下警告,但我不知道它意味着哪个数据更改,你知道吗? Warning: componentWillReceiveProps has been renamed, and is not recomm
当我使用react-router更改路由时,componentDidUpdate是否会触发?我修改了示例代码,但似乎无法使其工作。 我让主页组件记录了一些文本,但它似乎没有触发。感谢任何帮助,谢谢!
我想知道 React 组件的生命周期方法 componentDidUpdate 是否在所有子组件的 render 方法完成后执行,或者在 render 调用该组件的方法。 由于协调器递归地调用 ren
在每个模块的仪表板中,其布局数据(使用react-grid-layout)与模块数据分开存储,并且每个数据都存储在数据库中。当前模块数据和布局数据存储在仪表板组件状态中。每当模块或布局的先前状态与当前
我正在尝试使用componentDidUpdate动态渲染组件集合。这是我的场景: var index = 0; class myComponent extends Component { con
我有一个设置屏幕,我可以在其中获取用户的信息数量,例如年龄、体重和性别,然后根据这些信息计算用户每天应该喝多少水。 我想自动计算这个金额而不需要计算按钮。 Invariant Violation: M
我想测试 componentDidUpdate我尝试传递 {...props} 而不定义它然后 componentDidUpdate 首先记录一个空对象,然后不需要更新这会记录它们两次并显示 prop
我有一个类组件如下: class App extends Component { constructor(props){ super(props); this.
我正在使用带有文本输入的简单表单。当写入内容时,组件的状态会更新,并且由于 this.setState 是异步的,我从 componentDidUpdate 上的 API 获取数据。 问题是我没有找到
这是场景。我有一个父组件和一个子组件。父组件执行 ajax 调用并将数据推送到子组件。 当子组件接收到新数据时,在(子组件)的 componentDidUpdate 中,我将重新设置其内部状态。 co
在我的应用程序中,我有一个 HomePage其中有导航链接的组件。该组件的路由是 。因此该组件有一个导航栏,其中包含指向其“子路线”的 NavLink 链接。例如,导航链接可引导您访问 /browse
我将 Redux 重构到我的代码中,但不知道如何获取之前的状态。我的 componentDidUpdate 生命周期方法需要此状态,以便我可以调用其他方法而不会陷入无限循环。 // when comp
当满足以下条件时,我需要确保输入元素获得焦点: DOM 可用 并且属性已更改 问题:我是否需要将代码同时放入 componentDidUpdate 和 componentDidMount 中,还是仅使
我将一个自调用函数从 App 组件传递到 WeatherForecast 组件的 getBgColor 函数。这会从子组件 WeatherForecast 获取一个值,并将其传递到 App 组件以更新
在这里阅读了大量其他相关问题后。我还找不到答案。我已经改进了我的代码,并且我相信我非常接近解决方案,但我仍然无法实现我的目标。 我是编码和 native react 的新手。我想构建水提醒应用程序,我
我有一个障碍,那就是如果我按下取消订单按钮(batalkan pesanan)就会出现无限循环,为什么我要使用ComponentDidUpdate因为要更新新的显示或者除了ComponentDidUp
我有一个带有 componentDidMount() 方法的组件,该方法调用名为 getData() 的方法,该方法获取初始数据并设置组件的初始状态。 class LogsSettings exten
简单的例子,但不知道为什么我不能让它工作: class Grid extends React.Component { componentDidUpdate = () =>{
我的纯组件中有这段代码: componentDidUpdate(prevProps) { const { scheduleSheet } = this.props; const {
我是一名优秀的程序员,十分优秀!