单击时渲染反应组件
Posted
技术标签:
【中文标题】单击时渲染反应组件【英文标题】:rendering react components on click 【发布时间】:2017-06-28 17:28:57 【问题描述】:当我们单击“添加”链接时,我正在尝试呈现需要组件。 以下是我的主要组件代码:
import React from 'react';
import ReactDOM from 'react-dom';
import Hand from './hand.js';
import Need from './need.js';
class App extends React.Component
constructor()
super();
this.processHand = this.processHand.bind(this);
this.addNeed = this.addNeed.bind(this);
this.state =
inhandMoney : " ",
renderNeed: false,
processHand(e)
e.preventDefault();
const handMoneyReceived = this.handMoney.value;
this.setState(
inhandMoney: handMoneyReceived
);
addNeed(e)
e.preventDefault();
this.setState(
renderNeed:true
);
render()
const passNeed = (
<Need/>
);
return(
<div>
<div className ="hand">
<form onSubmit = this.processHand>
<input type="text" ref= ref => this.handMoney = ref/>
<input type="submit"/>
</form>
<Hand handMoney = this.state.inhandMoney/>
<Need/>
</div>
this.state.renderNeed ? passNeed : null
<a href="#" className="add" onClick = this.addNeed>add</a>
</div>
)
ReactDOM.render(<App />, document.getElementById('container'));
下面是我的需要组件以防万一:
import React from 'react';
export class Need extends React.Component
constructor()
super();
this.processNeed = this.processNeed.bind(this);
this.state =
why: " ",
howMuch: 0
processNeed(e)
e.preventDefault();
const why=this.why.value;
const howMuch=this.howMuch.value;
this.setState(
why:why,
howMuch:howMuch
);
render()
return(
<div className ="need">
<form onSubmit = this.processNeed>
<input type="text" ref= ref => this.why = ref/>
<input type="text" ref= ref => this.howMuch = ref/>
<input type="submit"/>
</form>
<div>
<h1>this.state.why</h1>
<h1>this.state.howMuch</h1>
</div>
</div>
)
我正在实现我在第一次单击添加链接时想要实现的目标,即最初需要组件在没有任何条件的情况下呈现。当我单击“添加”时,需要组件再次呈现但是当我第二次单击“添加”链接,我没有看到任何更改。为什么会这样,每次点击“添加”链接时,我都想渲染 Need 组件。
【问题讨论】:
类方法需要“绑定”。 @john_omalley 的答案如下。请参阅***.com/a/30721098/368697 了解您打算用作回调的绑定类方法。 您得到解决方案还是仍然面临问题?? 【参考方案1】:以下是您的问题的解决方案。我尽量贴近你的代码。
https://jsfiddle.net/birjubaba/t0yusos9/3/
@sean 给出的解释很到位。
默认情况下,调用 setState 会重新渲染组件,无论如何 您传递给 setState 的有效参数。所以是的,应该是 重新渲染。它似乎没有重新渲染,因为它是 第一次点击后总是显示相同的东西,因为 每次点击后,renderNeed 始终为真
React 维护一个虚拟 DOM,所有 DOM 操作都在这个虚拟 DOM 中完成(在更新实际 DOM 之前)。添加Need
组件是一种DOM 操作。因此,第一次当我们点击“添加”时,它实际上会更新虚拟 DOM 以添加一个新的Need
。现在 react diff 算法起作用了,它更新了实际的 DOM。因此,Need
组件显示在 UI 中。 DOM 如下所示:
div
|- div (class=hand)
|-form
|-input (type=text)
|-input (type=submit)
|- Hand
|- Need
|-Need (added by clicking on add anchor tag)
|-a (class=add)
下次单击“添加”时,this.state.renderNeed 再次为 true,因此,React 将尝试在虚拟 DOM 中添加 Need 组件(由于以下代码)。
this.state.renderNeed ? passNeed : null
<a href="#" className="add" onClick = this.addNeed>add</a>
但在添加 Need
之前,React diff 算法将运行,它会看到虚拟(和实际)DOM 中已经存在一个需要组件,这与它尝试添加的组件完全相同。 React 会认为两个 DOM 是相同的,并且 UI 中没有任何更新。
您对添加的要求如下:
div
|- div (class=hand)
|-form
|-input (type=text)
|-input (type=submit)
|- Hand
|- Need
|-Need (added by clicking on add anchor tag)
|-Need (added by clicking on add anchor tag)
|-Need (added by clicking on add anchor tag)
|-Need (added by clicking on add anchor tag)
|-a (class=add)
这可以通过维护Need
组件的数组并在单击添加时呈现它们来实现。 React diff 算法将负责更新虚拟 DOM 和实际 DOM 的所有优化。
我鼓励您浏览以下两个很棒的站点,其中正确解释了 react diff 算法。
-
在 Google 中搜索“Reconciliation - React”,然后从搜索结果中打开 facebook react 页面
https://calendar.perfplanet.com/2013/diff/
【讨论】:
&&
运算符的基本规则,如果第一个为真,则评估第二个条件。所以这里如果this.state.renderNeed
为真,那么第二个条件是方法调用 (this.renderNeedArray()` 被评估。它只是确保当this.state.renderNeed
为真时,只有renderNeedArray()
被调用。
谢谢,我还想在完成添加需求后在所有需要组件中添加“多少”的所有值。有办法吗?
对不起,在您回答之前我删除了上一个问题。无论如何,谢谢。【参考方案2】:
根据您的解释,我知道每次单击 add
链接时,您都想添加 Need
组件。
由于您对render()
方法的错误理解,您提供的代码无法按照您希望的方式工作。每次单击add
链接时,您的<Need />
组件都会重新渲染,但每次只有一个<Need />
组件重新渲染。如果您想在每次单击 add
链接时呈现新组件。您将需要使用一个包含所有<Need />
组件的数组。
为了达到同样的效果,我创建了一个名为 needArray
的状态变量。每次点击add
链接时,都会在这个状态变量中添加一个新的<Need />
组件,并渲染相同的组件。
constructor(props)
super(props)
this.state = renderNeed: false, needArray: []
this.addNeed = this.addNeed.bind(this)
addNeed(e)
e.preventDefault();
// any another better approach can be used to generate unique key. I've used Math.random() for demo only.
this.setState(
renderNeed: true,
needArray: [<Need key=Math.random()/>, ...this.state.needArray]
)
render()
return (
<div>
<a href="#" onClick = this.addNeed>add</a>
this.state.renderNeed ? this.state.needArray : null
</div>
)
这是工作小提琴的链接。为简洁起见,我只添加了需要的代码。 JSFiddle
【讨论】:
【参考方案3】:尝试:
<a href="#" className="add" onClick = this.addNeed.bind(this)>add</a>
【讨论】:
正确 - 错过了。您需要对状态中的项目数组进行建模 - 而不是以布尔标志的 false 开头以 [] 开始,然后在每次单击时连接一个新项目。然后,您需要为数组中的每个项目呈现一个项目。请参阅有关渲染项目数组的反应文档(尤其是“键”属性。【参考方案4】:如果您想继续呈现需求集合,您可能希望在您的状态中存储一个可以跟踪您的需求的数组。
否则,基于此报价-
起初需要组件在没有任何条件的情况下呈现。当我单击“添加”时,需要组件再次呈现,但是当我第二次单击“添加”链接时,我看不到任何更改。
您似乎想根据 renderNeed 布尔值跟踪的更改进行渲染
默认情况下,调用 setState 将重新渲染组件,无论您传递给 setState 的有效参数是什么。所以是的,它应该重新渲染。它似乎没有重新渲染,因为,第一次点击后它总是显示相同的东西,因为每次点击后 renderNeed 总是为真
这是一个很好的资源:@987654321@
作为一个人为的例子,如果你真的想“重新渲染”你的组件,你可以做一些微不足道的事情,比如为 renderNeed 创建一个切换
addNeed(e)
e.preventDefault();
this.setState((prevState, props) => (
renderNeed: !prevState.renderNeed
);
不建议您这样做,因为您的 addNeed 函数没有按照它的名称执行...
还有一个小技巧来证明它正在重新渲染
https://jsfiddle.net/jwm6k66c/2131/
希望这会有所帮助。
【讨论】:
【参考方案5】: this.state.renderNeed ? passNeed : null
替换为
this.state.renderNeed && <Need/>
【讨论】:
【参考方案6】:1) 实现此目的的一种方法是:
addNeed(e)
e.preventDefault();
this.setState(
needKey: Math.random()
);
在你的渲染中你可以添加这个键:
<Need key=this.state.needKey />
2) 另一种方法是:
addNeed(e)
e.preventDefault();
this.setState(this.state);
3) 另外,可以通过 forceUpdate 来完成。但是,一般不建议这样做:
addNeed(e)
e.preventDefault();
this.forceUpdate()
【讨论】:
【参考方案7】:我将创建一个带有空数组的初始状态键,每次单击“添加”时都会增加数组的大小,然后将数组映射到 render()。像这样的:
constructor()
super();
this.processHand = this.processHand.bind(this);
this.addNeed = this.addNeed.bind(this);
this.state =
inhandMoney : " ",
fields: [],
addNeed(e)
e.preventDefault();
this.setState(
fileds: this.state.fields.push(1),
);
render()
<div>
<div className="hand">
<form onSubmit=this.processHand>
<input type="text" ref=ref => this.handMoney = ref/>
<input type="submit"/>
</form>
<Need/>
</div>
this.state.fields.map(i => <Need key=i />)
<a href="#" className="add" onClick=this.addNeed>add</a>
</div>
【讨论】:
以上是关于单击时渲染反应组件的主要内容,如果未能解决你的问题,请参考以下文章
我应该刷新浏览器以使用 Routes | 渲染我的组件反应JS