1

I'm stuck with calling my clickRemoveHandler. The idea is that I have two components: first - Layout that renders header, nav and footer components, second - calculator that is my core component with data input etc... In calculator component I have buttons with managed state, so when I click anywhere on Layout component (div), i need to call Calculator function that manipulates my buttons. The code is below:

class Layout extends Component {
.....
    clickHandler = (event) => {
        Calculator.clickRemoveHandler(event);
        console.log('Clikced')
    };
.....
}
class Calculator extends Component {
  state = {
    currentServiceClass: null,
    hoverIndex: null,
    btnClicked: false,
    selectedService: null
  }
  currentCursorPosition = {
    el: null,
    index: null,
    rendered: false
  }
  static clickRemoveHandler = (event) => {
    if ((!event.target.hasAttribute("type")) && (this.state.btnClicked)) {
      this.currentCursorPosition = {
        el: null,
        index: null,
        rendered: false
      };
      this.setState({currentServiceClass: null, hoverIndex: null, btnClicked: false})
    }
  }
....
}

There are a lot of logic in these components so they are too robust to post full code. But the problem is that there is none of Calculator reference in Layout, calculator itself is rendered with Routing from another component, so I cannot pass any data from Layout to calculator directly. What I want is to call static clickRemoveHandler from Layout. As I guess static is an option that make function global. So it works, but I got an error TypeError: undefined is not an object (evaluating 'Calculator.state.btnClicked'). As I see it means that when the clickRemoveHandler is called it is not associated with Calculator component, or doesn't have access to its state and props. The question is how can I make it all work together ? Pass calculator state when calling function or is there another more elegant way to do it ?

Mikhail
  • 57
  • 1
  • 7
  • Here you can find some answers https://stackoverflow.com/questions/37949981/call-child-method-from-parent – lissettdm Dec 06 '20 at 19:18

2 Answers2

0

I would suggest for the case you described (different components on different levels need access to some state and manipulate it) to use React context. You can take a look also on state managers like Redux or MobX, but in this particular case it will be overhead since your application is not so "huge". Basically you need to create some separate folder (you can call it context), inside it you should create context itself, export it and wrap in it you most up level component so that all the children will be able to use it.

You can find an example here: https://codesandbox.io/s/spring-glitter-0vzul.

Here is a link to documentation: https://reactjs.org/docs/context.html

I can provide you some more details if you need

Oleksandr Sakun
  • 452
  • 4
  • 9
0

That was a challenge, but I've done it! Layout component:

state = {
    firstMount: false,
    clicked: false,
    clickedEvt: null
};
clickHandler = (event) => {
    console.log('Clikced')
    if (this.state.clickedEvt) 
        this.setState({clicked: false, clickedEvt: null});
    else         
        this.setState({clicked: true, clickedEvt: event.target}, ()=>{setTimeout(() => 
            this.setState({clicked: false, clickedEvt: null})
        , 50)})

};
        <LayoutContext.Provider value={{
            clicked: this.state.clicked,
            clickedEvt: this.state.clickedEvt,
            handleClick: this.clickHandler
        }}>

render() {
    return(
        <div onClick={(event) => this.clickHandler(event)} className="web">

First I call handleClick as onclick event from Layout component, then it is called again from calculator

  componentDidUpdate() {
    if (this.context.clicked) {
      this.clickRemoveHandler(this.context.clickedEvt)
    }
  }
Mikhail
  • 57
  • 1
  • 7