在 React 中单击组件时向兄弟姐妹添加类

Posted

技术标签:

【中文标题】在 React 中单击组件时向兄弟姐妹添加类【英文标题】:Add class to siblings when Component clicked in React 【发布时间】:2017-09-12 09:37:51 【问题描述】:

我正在使用 React.js 构建我的作品集。在一个部分中,我将四个组件布置在一个网格中。我想要实现的是,当单击一个组件时,将一个 css 类添加到该组件的兄弟姐妹中,以降低它们的不透明度,并且只保留单击的组件。在 jQuery 中,它类似于 $('.component').on('click', function() $(this).siblings.addClass('fadeAway'))。我怎样才能达到这个效果?这是我的代码,在此先感谢您的帮助!

class Parent extends Component
  constructor()
    super();
    this.state = fadeAway: false
    this.handleClick = this.handleClick.bind(this)
  
  handleClick()
    //Add class to siblings
  
  render()
    const array = ["Hello", "Hi", "How's it going", "Good Times"]
    return(
      array.map(function(obj, index)
        <Child text=obj key=index onClick=() => this.handleClick />
      )
    )
  

【问题讨论】:

【参考方案1】:

这个问题的一个工作示例可能看起来像这样,具有稍微复杂的初始化数组:

class Parent extends Component
  constructor()
    super();
    this.state = 
      elements: [
        
          id: "hello",
          text: "Hello",
          reduced: false,
        ,

        
          id: "hi",
          text: "Hi",
          reduced: false,
        

        
          id: "howsItGoing"
          text: "How's it going",
          reduced: false,
        

        
          id: "goodTimes",
          text: "Good Times",
          reduced: false,
        
      ],
    

    this.handleClick = this.handleClick.bind(this)
  

  handleClick(e)
    // copy elements from state
    const elements = JSON.parse(JSON.stringify(elements));
    const newElements = elements.map(element => 
      if (element.id === e.target.id) 
        element.reduced = false;
       else 
        element.reduced = true;
      
    );


    this.setState(
      elements: newElements,
    );
  

  render()
    return(
      this.state.elements.map(function(obj, index)
        <Child
          id=obj.id
          text=obj.text
          reduced=obj.reduced
          key=index
          onClick=() => this.handleClick />
      );
    );
  

然后您只需像这样向Child 组件添加一个三元组:

<Child
  id=this.props.id
  className=this.props.reduced ? "reduced" : "" />

这比其他示例添加了更多样板文件,但是将业务逻辑与组件内的文本联系起来非常脆弱,并且更强大的解决方案需要更强大的标识,例如呈现的 DOM 元素上的 ID 或类。如果您愿意,此解决方案还可以让您轻松扩展逻辑,以便多个元素一次保持最大不透明度。

【讨论】:

这个解决方案实际上帮助最大。起初,我所做的事情似乎有点健壮,但你真的很好地解释了它,现在对我来说完全有意义。我不得不稍微调整一下 handleClick 函数,并且不需要使用 JSON.parse,但总体概念有效,我实现了最终目标。谢谢!! @furkle @IanSpringer 很高兴为您提供帮助!【参考方案2】:

我将简单地存储在所选项目的状态索引中,然后将fadeAway prop 传递给定义为

的子组件
fadeAway=this.state.selectedIndex !== index

之后你只需要基于this.prop.fadeAway在Child中设置一个fade-away类并定义必要的CSS规则。

以下是您的情况:

class Parent extends React.Component
  constructor () 
    super();
    this.state = selectedIndex: null
  
  handleClick (selectedIndex) 
    this.setState( selectedIndex )
  
  render () 
    const array = ["Hello", "Hi", "How's it going", "Good Times"]
    return (
      <div>
        array.map((obj, index) => 
          const faded = this.state.selectedIndex && this.state.selectedIndex !== index
          return <Child 
            text=obj 
            fadeAway=faded
            key=index 
            onClick=() => this.handleClick(index) />
        )
      </div>  
    )
  


class Child extends React.Component 
  render () 
    return (
      <h2
        onClick=this.props.onClick
        className=this.props.fadeAway ? 'fade-away' : ''>
        this.props.text
      </h2>  
    ) 
  


ReactDOM.render(
  <Parent />,
  document.body
);
.fade-away 
  opacity: 0.3;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

【讨论】:

谢谢,这似乎很接近。但是,当页面呈现时,我希望所有组件都具有完全不透明度。当一个被点击时,其他的应该会失去它们的不透明度。此解决方案将一个组件设置为在页面加载时处于活动状态,此时它们都应该处于活动状态,直到单击一个组件。有什么建议吗? @IanSpringer 当然,只需将默认的selectedIndex 设为null 并在const faded = this.state.selectedIndex &amp;&amp; this.state.selectedIndex !== index 中检查它。查看演示。【参考方案3】:

您可以使用切换变量来实现:

handleClick()
  this.setState(fadeAway => (
    fadeAway: ! fadeAway
  );

...
<Child
  text=obj
  key=index
  onClick=() => this.handleClick
  className=this.state.fadeAway? 'class1' : 'class2'/>

【讨论】:

谢谢,但这个解决方案似乎切换了目标组​​件的类。我需要为单击的组件的兄弟姐妹添加一个新类。【参考方案4】:

我更喜欢使用currentWord这样的状态来保存在父组件中被点击的单词,presudo代码如下:

class Parent extends Component 
  constructor()
    super();
    this.state = 
      fadeAway: false,
      currentWord: ''
    ;
    this.handleClick = this.handleClick.bind(this)
  
  handleClick(currentWord)
    this.setState(
      currentWord: currentWord,
    );
  
  render()
    const array = ["Hello", "Hi", "How's it going", "Good Times"]
    const currentWord = this.state.currentWord;
    return(
      array.map(function(obj, index)
        <Child currentWord=currentWord text=obj key=index onClick=() => this.handleClick />
      )
    )
  

在子组件中

class Child extends Component 
  // some other code

  handleClick(e) 
    this.props.handleClick(e.target.value);
  

  render() 
    const isSelected = this.props.text === this.props.currentWord;
    // use isSelected to toggle className

    <div
      onClick=this.handleClick.bind(this)
    >this.props.text
    </div>
  

【讨论】:

您将 prop 传递为 currentWord,但在子组件中将其引用为 CurrentWord

以上是关于在 React 中单击组件时向兄弟姐妹添加类的主要内容,如果未能解决你的问题,请参考以下文章

使用 React 样式组件 / CSS 模块 / CSS-in-JS 的兄弟姐妹 CSS 规则

如何在组件(兄弟姐妹)之间传输数据Vue?

从兄弟姐妹那里传球

将道具传递给兄弟姐妹reactJS时未定义

vue 组件在兄弟姐妹中检测自己的索引

从另一个组件更新组件状态的最简单方法是啥?可以说组件是兄弟姐妹吗?