渲染在点击时反应组件

时间:2017-02-10 11:20:33

标签: javascript reactjs react-jsx

当我们点击"添加"时,我正在尝试渲染Need组件。链接。  下面是我的主要组件代码:

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>            
        )
    }
}

我正在实现我想要在第一次点击添加链接时实现的目标,即首先需要组件在没有任何条件的情况下呈现。当我点击&#34;添加&#34; Need组件再次渲染,但是当我点击&#34;添加&#34;第二次链接,我没有看到任何变化。为什么会这样,我想在每次点击&#34时添加需要组件;添加&#34;链接。

7 个答案:

答案 0 :(得分:3)

以下是解决您问题的解决方案。我试着尽可能地接近你的代码。

https://jsfiddle.net/birjubaba/t0yusos9/3/

@sean给出的解释是正确的。

  

默认情况下,调用setState将重新呈现组件,无论如何   传递给setState的有效参数。是的,它应该是   重新描绘。它似乎不会重新渲染,因为它是   第一次点击后总是显示相同的东西,因为   每次点击后,renderNeed始终为真

React维护一个虚拟DOM,所有DOM操作都在这个虚拟DOM中完成(在更新实际DOM之前)。添加Need组件是DOM操作。所以,第一次当我们点击&#34;添加&#34;它实际上更新了虚拟DOM以添加新的Need。现在反应差异算法工作,它更新实际的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)

下次&#34;添加&#34;单击,this.state.renderNeed再次为true,因此,React将尝试在虚拟DOM中添加Need组件(由于下面的代码)。

{this.state.renderNeed ? passNeed : null}
<a href="#" className="add" onClick = {this.addNeed}>add</a>

但是在添加Need之前,React diff算法将会运行,它会看到Virtual(和实际)DOM中已经存在一个Need组件,它与它尝试添加的组件完全相似。 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的所有优化。

我建议您通过以下两个精彩的网站,其中正确解释了反应差异算法。

  1. 搜索&#34;和解 - 反应&#34;在Google中,从搜索结果中打开facebook反应页面
  2. https://calendar.perfplanet.com/2013/diff/

答案 1 :(得分:1)

尝试: <a href="#" className="add" onClick = {this.addNeed.bind(this)}>add</a>

答案 2 :(得分:1)

如果您想继续呈现需求集合,您可能希望在您的州内存储可以跟踪您的需求的数组。

否则,基于此引用 -

  

首先,need组件在没有任何条件的情况下呈现。当我点击“添加”时,Need组件再次呈现,但是当我第二次单击“添加”链接时,我看不到任何更改。

您似乎希望根据 renderNeed 布尔

跟踪的更改进行渲染

默认情况下,无论您传递给setState的有效参数是什么,调用setState都会重新呈现组件。所以是的,应该重新渲染。它似乎没有重新渲染,因为,它在第一次点击后始终显示相同的内容,因为每次点击后renderNeed始终为真

这是一个很好的资源:ReactJS - Does render get called any time "setState" is called?

作为一个人为的例子,如果你真的想“重新渲染”你的组件,你可以做一些微不足道的事情,比如为renderNeed创建一个切换

  addNeed(e){
    e.preventDefault();
    this.setState((prevState, props) => ({
        renderNeed: !prevState.renderNeed
    });
  }

不推荐你这样做,因为你的addNeed函数没有按照它的名字暗示......

也是一个小小的小提示,以证明它正在重新渲染

https://jsfiddle.net/jwm6k66c/2131/

希望这有帮助。

答案 3 :(得分:1)

根据您的解释,我知道您每次点击Need链接时都要添加add组件。

由于您对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

答案 4 :(得分:0)

  {this.state.renderNeed ? passNeed : null}

替换为

 {this.state.renderNeed && <Need/> }

答案 5 :(得分:0)

1)实现这一目标的一种方法是:

<?php
    $Pages = array(
      'clothes' => 'Clothes',
      'something' => 'Something'
    );

    $path = $_SERVER["PHP_SELF"];
    $parts = explode('/',$path);
    if (count($parts) < 2)
    {
    echo("home");
    }
    else
    {
    echo ("<a href=\"/\">Home</a> &raquo; ");
    for ($i = 1; $i < count($parts); $i++)
        {
        if (!strstr($parts[$i],"."))
            {
            echo("<a href=\"");
            for ($j = 0; $j <= $i; $j++) {echo $parts[$j]."/";};
            echo("\">". str_replace('-', ' ', $Pages[$parts[$i]])."</a> &raquo; ");
            }
        else
            {
            $str = $parts[$i];
            $pos = strrpos($str,".");
            $parts[$i] = substr($str, 0, $pos);
            echo str_replace('-', ' ', $Pages[$parts[$i]]);
            };
        };
    };  
?>

在渲染中,您可以添加以下密钥:

addNeed(e){
  e.preventDefault();
  this.setState({
      needKey: Math.random()
  });
}

2)另一种方式是:

<Need key={this.state.needKey} /> 

3)另外,可以使用forceUpdate完成。但是,通常不建议这样做:

addNeed(e){
  e.preventDefault();
  this.setState(this.state);
}

答案 6 :(得分:0)

我会创建一个带有空数组的初始状态键,每次单击“添加”时,您将增加数组的大小,然后您将数组映射到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>
}