在子组件上切换活动类

时间:2016-03-20 15:16:02

标签: javascript reactjs

我有点头疼,试图弄清楚React的实施方式。

我有一个搜索组件,其中包含SearchItems,当一个项目被点击以及其他东西我需要设置它的状态激活它得到正确的CSS,我设法让这个工作得很好但是怎么会我要从其他人那里取消活跃状态吗?

我原以为我可以从顶级组件传递一个函数来获取搜索的ID,当点击它时,它会通过SearchItems压缩并根据哪个ID将其状态更改为true / false是吗?

以下代码!

顶级组件:

    import React from "react";
import {Link} from "react-router";

import Search from "./Search";

    export default class Searches extends React.Component {
      constructor(){
        super();
        this.state = {
          searches : [
          {
            id : "2178348216",
            searchName: "searchName1",
            matches: "5"

          },
          {
            id : "10293840132",
            searchName: "searchName2",
            matches: "20"

          }

          ]
        };

      }

      render() {
        const { searches } = this.state;

        const SearchItems = searches.map((search) => {
          return <Search key={search.id} {...search}/>

        })

        return (
         <div> {SearchItems} </div>
          );

      }
    }

搜索商品组件

export default class Search extends React.Component {
  constructor() {
    super();

    // Set the default panel style

    this.state = {
      panelStyle: { height: '90px', marginBottom: '6px', boxShadow: '' },
      selected: false
    }



  }

  isActive(){
    return 'row panel panel-success ' + (this.state.selected ? 'active' : 'default');
  }

viewNotifications(e){
  this.setState({selected: true});

}
    render() {
      const { id, searchName, matches } = this.props;



      const buttonStyle = {
        height: '100%',
        width: '93px',
        backgroundColor: '#FFC600'
      }

    return (
     <div style={this.state.panelStyle} className={this.isActive()}>
       <div class="col-xs-10">
       <div class="col-xs-7">
         Search Name: {searchName}
       </div>
        <div class="col-xs-7">
         Must Have: PHP, MySQL
       </div>
       <div class="col-xs-7">
         Could Have: AngularJS
       </div>

       </div>

          <button type="button" onClick={this.viewNotifications.bind(this)} style={buttonStyle} class="btn btn-default btn-lg"> {matches} </button>



     </div>



    );
  }
}

2 个答案:

答案 0 :(得分:2)

我认为你根本不需要子组件中的状态。事实上,避免在大多数组件中使用状态是一个好主意,因此它们易于推理和重用。

在这种情况下,我只会将所有状态保留在父组件上。

TOP组件:

position: absolute;

儿童组成部分:

import React from "react";

import Search from "./search";

export default class Searches extends React.Component {
  constructor(){
    super();
    this.state = {
      searches : [
        {
          id : "2178348216",
          searchName: "searchName1",
          matches: "5"
        },
        {
          id : "10293840132",
          searchName: "searchName2",
          matches: "20"
        }
      ],
      activeElement : null
    };
  }

  _onSearchSelect(searchId) {
    this.setState({'activeElement': searchId})
  }

  render() {
    const { searches, activeSearchId } = this.state;

    const SearchItems = searches.map((search) => {
      return <Search key={search.id} {...search}
        isActive={search.id === activeElement}
        onSelect={this._onSearchSelect.bind(this)} />
    })

    return (
     <div> {SearchItems} </div>
    );
  }
}

您还可以在Plunker中看到它正在运行:https://plnkr.co/edit/sdWzFedsdFx4MpbOuPJD?p=preview

答案 1 :(得分:0)

好吧事实证明这比我想象的要简单,只是了解反应如何起作用(而不是混淆)。

如果你有一个顶级组件,你通过props将状态传递给子节点,当你更新顶级组件中的状态时,它会将它传递给子节点,你可以使用componentWillReceiveProps来采取行动。

我在我的顶级组件中添加了一个名为updateActiveSearch的函数,它只是设置TOP级组件的状态,然后将activeElement状态作为prop传递给子元素以及函数。当一个子元素调用此函数将其自身设置为活动状态时,所有这些函数都将触发componentWillReceiveProps,他们只需要根据他们收到的ID检查自己的ID,如果匹配它们是活动的,如果它们不是它们不是!

所以我的顶级组件现在看起来像这样:

export default class Searches extends React.Component {
  constructor(){
    super();
    this.state = {
      searches : [
      {
        id : "2178348216",
        searchName: "searchName1",
        matches: "5"

      },
      {
        id : "10293840132",
        searchName: "searchName2",
        matches: "20"

      }

      ],
      activeElement : 0
    };


  }
// This function gets passed via a prop below
  updateActiveSearch(id){
    //console.log(id);
    this.setState({activeElement : id});
  }

  render() {


    const SearchItems = this.state.searches.map((search) => {
      return <Search activeElement={this.state.activeElement} goFunction={this.updateActiveSearch.bind(this)} key={search.id} {...search}/>

    })

    return (
     <div> {SearchItems} </div>
      );

  }
}

儿童组件

export default class Search extends React.Component {
  constructor() {
    super();

    // Set the default panel style

    this.state = {
      panelStyle: { height: '90px', marginBottom: '6px', boxShadow: '' },
      selected: false
    }

  }


// This happens right before the props get updated!   
    componentWillReceiveProps(incomingProps){
      if(incomingProps.activeElement == this.props.id){
        this.setState({selected: true});
      } else {
        this.setState({selected: false});
      }
}

  isActive(){
    return 'row panel panel-success ' + (this.state.selected ? 'active' : 'default');
  }

viewNotifications(e){
  //this.state.panelStyle.boxShadow = '-2px 3px 20px 5px rgba(255,198,0,1)';
  this.setState({selected: true});
  this.props.goFunction(this.props.id);

}
    render() {
      const { id, searchName, matches } = this.props;

      const buttonStyle = {
        height: '100%',
        width: '93px',
        backgroundColor: '#FFC600'
      }

    return (
     <div style={this.state.panelStyle} className={this.isActive()}>
       <div class="col-xs-10">
       <div class="col-xs-7">
         Search Name: {searchName}
       </div>
        <div class="col-xs-7">
         Must Have: PHP, MySQL
       </div>
       <div class="col-xs-7">
         Could Have: AngularJS
       </div>

       </div>

          <button type="button" onClick={this.viewNotifications.bind(this)} style={buttonStyle} class="btn btn-default btn-lg"> {matches} </button>



     </div>



    );
  }
}