Search code examples
reactjsreact-propsreact-state-management

Toggle show hide class on child component from parent onfocus method in React


I am a React beginner.

I have a Parent component that has multiple input fields (InputField child component). OnFocus I want to toggle a child of Inputfield(InputFieldToolTip component) to show/hide from a method in the parent component

Currently, when I set the state of the showHide and pass into the Input field component via props, it toggles all the tooltip components

How do I reference an individual tooltip component in React? In jQuery, I would just give it an ID and use a Dom selector.

Example code (please don't take this as actual code, it's just a representative of the structure and what's being passed currently):

Parent Component

import React from 'react';
import ReactDOM from 'react-dom';
import InputField from './InputField.jsx';

class Parent extends React.Component {
  constructor(props){
    super(props);
    this.state={
        showHide: ' hide',
        toolTip: 'This is a tooltip'
    }

    this.showHide = this.showHide.bind(this);
 }
 showHide(){
    if(this.state.showHide === 'hide') {
        this.setState({
            showHide: 'show'
        ))};
    } else {
        this.setState({
            showHide: 'hide'
        });
    }

 }

render(){
    return(
      <div>
        <InputField
            name='input-1'
            OnFocus={this.showHide}
            type="text"
            showHide={this.state.showHide}
            toolTip={this.state.toolTip}
        />
        <InputField
            name='input-2'
            OnFocus={this.showHide}
            type="text"
            showHide={this.state.showHide}
            toolTip={this.state.toolTip}
        />
        <InputField
            name='input-3'
            OnFocus={this.showHide}
            type="text"
            showHide={this.state.showHide}
            toolTip={this.state.toolTip}
        />
     </div>
    )       

  }
}

InputField Component

import React from 'react';
import ReactDOM from 'react-dom';
import InputField from './ToolTip.jsx';

export class InputField extends React.Component{

 render(){
    return(
      <div>
        <Input/>
        <ToolTip
            showHide={this.props.showHide}
            toolTip={this.props.toolTip}
        />
     </div>
    )           
  }
}

ToolTip Component

import React, {Component} from 'react';
export const ToolTip = (props) => {
  return <div className={this.props.showHide}>{this.props.toolTip}</div>
}

Solution

  • Your problem is that currently your state is shared by all your components. The showHide prop is the same for all inputs and tooltip components.

    I assume the behavior you're going for is to have the corresponding tooltip show up when you focus an input.

    You could do that by instead of having that state in your parent component, put it in each input/tooltip :

    Parent

    import React from 'react';
    import ReactDOM from 'react-dom';
    import InputField from './InputField.jsx';
    
    class Parent extends React.Component {
    
     render(){
        return(
          <div>
            <InputField
                name='input-1'
                type="text"
                tooltipText="Input1 Tooltip"
            />
            <InputField
                name='input-2'
                type="text"
                tooltipText="Input2 Tooltip"
            />
            <InputField
                name='input-3'
                type="text"
                tooltipText="Input3 Tooltip"
            />
         </div>
        )       
    
      }
    }
    

    InputField

    import React from 'react';
    import ReactDOM from 'react-dom';
    import InputField from './ToolTip.jsx';
    
    export class InputField extends React.Component{
    
     constructor(props){
        super(props)
        this.state = {
           tooltipShown: false
        }
        this.showTooltip = this.showTooltip.bind(this)
        this.hideTooltip = this.hideTooltip.bind(this)
     }
    
     showTooltip(){
       this.setState({
         tooltipShown: true
       })
     }
    
     hideTooltip(){
       this.setState({
         tooltipShown: false
       })
     }
    
     render(){
        return(
          <div>
            <input onFocus={this.showTooltip} onBlur={this.hideTooltip} />
            <ToolTip 
              shown={this.state.tooltipShown} 
              text={this.props.tooltipText} 
            />
         </div>
        )           
      }
    }
    

    Tooltip

    export const ToolTip = (props) => {
      return (
         <div className={props.shown ? 'show' : 'hide'}> 
           {props.tooltipText}
         </div>
      )
    }
    

    Now each InputField component controls its own Tooltip component. They can receive the tooltip's text as a prop and pass it down to the Tooltip. When you give focus to an InputField, it will tell the tooltip to be displayed, and when the focus is lost onBlur will trigger to hide it again.

    Note that I also changed the Input in InputField to input as it doesn't seem like you're using a custom Input component.