nrvarun
nrvarun

Reputation: 93

Is This An Anti-Pattern - Reactjs

I have just started using React and working on a small app, in the meantime I made a small show and hide modal. I wanted to know the way I have made it is a wrong way to do it. If this is an anti-pattern how should I go about it?

class App extends Component {
   constructor(props) {
      super(props);
      this.state = {show: false};
      this.showModal = this.showModal.bind(this);
   }

   render() {
       return (
           <div>
              <h2 className={styles.main__title}>Helloooo!</h2>
              <Modal ref='show'/> 
              <button onClick={this.showModal} className={styles.addtask}>&#x2795;</button>
           </div>
       );
   }

   showModal(){
       this.setState({
          show: true
       });
       this.refs.show.showModal();
   }

}

The modal component which i have made is using this logic, it hooks the dom elements and modifies using the document.queryselector. Is this a right way to do the dom manipulation in react.

The modal code which i have used is this :

class Modal extends Component {
constructor() {
    super();
    this.hideModal = this.hideModal.bind(this);
    this.showModal = this.showModal.bind(this);
    this.state = { modalHook: '.'+styles.container };
}

render() {
    return (
        <div>
            <div onClick={this.hideModal} className={styles.container}>
                <div className={styles.container__content}>
                    <div className={styles.card}>
                        <div className={styles.card__header}>
                            <h2>Add new task</h2>
                        </div>
                        <div className={styles.card__main}>
                            <Input type="text" placeholder="enter the task title" />
                            <Input type="textarea" placeholder="enter the task details" />
                        </div>
                        <div className={styles.card__actions}>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    );
}

showModal(){
    let container = document.querySelector(this.state.modalHook);
    container.classList.add(styles.show);    
}
hideModal(e){
    let container = document.querySelector(this.state.modalHook);
    if(e.target.classList.contains(styles.container)){
        container.classList.remove(styles.show);
    }
}
}

Upvotes: 1

Views: 1506

Answers (2)

spirift
spirift

Reputation: 3072

To do what you require you don't need to use refs at all. You can pass the state down the to child component as a prop. When the state updates the prop will automatically update. You can then use this prop to switch a class. You can see it in action on jsbin here

const Modal = (props) => {
  return (
    <div className={props.show ? 'show' : 'hide'}>modal</div>
  )
}

const styles = {
    main__title: 'main__title',
    addtask: 'addtask'
}

class App extends React.Component {
   constructor(props) {
      super(props);
      this.state = {show: false};
      this.toggleModal = this.toggleModal.bind(this);
   }

   render() {
       return (
           <div>
              <h2 className={styles.main__title}>Helloooo!</h2>
              <Modal show={this.state.show} /> 
              <button onClick={this.toggleModal} className={styles.addtask}>&#x2795;</button>
           </div>
       );
   }

   toggleModal(){
       this.setState({
          show: !this.state.show
       });
   }

}
ReactDOM.render(<App />, document.getElementById('root'));

Upvotes: 1

cn0047
cn0047

Reputation: 17091

Your example looks good and simple, but accordingly to this it is better don't overuse refs.
And also it might be helpful to lifting state up, like described here.

Here my example:

class Modal extends React.Component {
    constructor(props) {
        super(props);
        this.state = {show: props.show};
    }
    componentDidUpdate(prevProps, prevState) {
        let modal = document.getElementById('modal');
        if (prevProps.show) {
            modal.classList.remove('hidden');
        } else {
            modal.className += ' hidden';
        }
    }
    render() {
        return (
            <div id="modal" className={this.state.show ? '' : 'hidden'}>
                My modal content.
            </div>
        );
    }
}
class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {show: false};
        this.handleClick = this.handleClick.bind(this);
    }
    handleClick() {
        this.setState(prevState => ({
            show: !prevState.show
        }));
    }
    render() {
        return (
            <div>
                <button onClick={this.handleClick}>
                    Launch modal
                </button>
                <Modal show={this.state.show} />
            </div>
        );
    }
}
ReactDOM.render(<App />, document.getElementById('root'));

Here i don't pretend for ultimate truth, but try to provide another option how you can reach desired result.

Upvotes: 2

Related Questions