单击按钮会渲染多个不需要的组件

时间:2018-10-21 14:44:27

标签: javascript reactjs

我的问题是:我有一个必须在应用程序中渲染3次的组件,并且该组件具有一个按钮,该按钮 应该 用新的零件。我在每个实例中都有占位符组件,而不仅仅是触发事件的组件。我的代码:

class App extends Component {
  constructor(){
    super()
    this.state = {showCard : false,cards : []}
    this.buttonClick = this.buttonClick.bind(this)
  }

  buttonClick(ev){
    console.log(ev.target)
    const nextId = this.state.cards.length + 1
    this.setState({cards: this.state.cards.concat([nextId])})
    this.setState({showCard: true,})
  }

  render() {
    console.log(this)
    return (
      <div className="App">
        <h2>React Demo</h2>
          <ul className="container">
            <Contact key="0" text={"Contact 1"} buttonClick={this.buttonClick} showCard={this.state.showCard} cards={this.state.cards}/>
            <Contact key="1" text={"Contact 2"} buttonClick={this.buttonClick} showCard={this.state.showCard} cards={this.state.cards}/>
            <Contact key="2" text={"Contact 3"} buttonClick={this.buttonClick} showCard={this.state.showCard} cards={this.state.cards}/>
        </ul>
      </div>
    );
  }
}

function Contact(props){
    return <li>
            <h3>{props.text}</h3>
            <ul className="stack">
              <li><button id={props.text} type="button" className="block" onClick={e =>props.buttonClick(e)}>+</button></li>
              {props.cards.map(cardId => <Card key={props.text+cardId}/>)}
            </ul>
           </li>
}

function Card(){
  return <li><div className="card">Place Holder</div></li>
}

export default App;

我尝试使用showCard和映射进行条件渲染,如此处所示,在这两种情况下,组件的所有三个实例均被更新,而不是正确的实例。我知道这是我正在做的愚蠢的事情,我只是看不到它。预先感谢。

J

2 个答案:

答案 0 :(得分:0)

更新的代码:

const list = [
  {
    id : 0,
    title : "Contact 1",
    showCard : false,
    addCard : ()=> <Card key={"x"+count++}/>,
    cards : []
  },
  {
    id : 1,
    title : "Contact 2",
    showCard : false,
    addCard : ()=> <Card key={"y"+count++}/>,
    cards : []
  },
  {
    id : 2,
    title : "Contact 3",
    showCard : false,
    addCard : ()=> <Card key={"z"+count++}/>,
    cards : []
   }
]


let count = 0

class App extends Component {
  constructor(){
    super()
    this.state = {list : list}
    this.buttonClick = this.buttonClick.bind(this)
  }

  buttonClick(ev,id){
    let a0 = null
    for(let obj of this.state.list){
      if(obj.id === id){ 
        a0 = obj.addCard()
        obj.cards.push(a0)
      }
    }
    this.setState({list:this.state.list})
  }

  render() {
    return (
      <div className="App">
        <h2>React Demo</h2>
          <ul className="container">
            {this.state.list.map((item) =>
                <Contact key={item.title+item.id} text={item.title} buttonClick={this.buttonClick} showCard={item.showCard} id={item.id} cards={item.cards}/>
          )}

        </ul>
      </div>
    );
  }
}

function Contact(props){
    return <li>
            <h3>{props.text}</h3>
            <ul className="stack">
              <li><button id={props.text} type="button" className="block" onClick={e =>props.buttonClick(e,props.id)}>+</button></li>
              {props.cards.map((card)=> {
                return card || null
                })}
            </ul>
           </li>
}

function Card(){
  return <li><div className="card">Place Holder</div></li>
}

export default App;

Jonas H 建议 ,我正在与Contact组件的所有三个实例共享状态。我只做了React几周,所以花了很多时间解决这个问题。我的解决方案可能不是最佳解决方案,但它确实有效,尽管确实破坏了我的用户界面……但这是另一个任务。谢谢大家。

J

感谢@Jonas H

答案 1 :(得分:-2)

shouldComponentUpdate()方法将解决您的问题

使用shouldComponentUpdate()来让React知道组件的输出是否不受当前状态或道具更改的影响。默认行为是在每次状态更改时重新呈现,并且在大多数情况下,您应该依赖默认行为。 more

shouldComponentUpdate(nextProps, nextState) {
   // should return either true or fase 

   // component should render on state changes or initial render
   if((JSON.stringify(nextState) !== JSON.stringify(this.state)) || (JSON.stringify(this.state) === (JSON.stringify({showCard : false,cards : []})) ) {
     return true;
   }

     return false;
}

将上述方法放入您的代码