简体   繁体   English

一种从外部调用 React 组件方法的方法(使用 state 和 props)

[英]A way to call React component's method from outside (with it's state and props)

I'm stuck with calling my clickRemoveHandler.我坚持调用我的 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.我的想法是我有两个组件:第一个 - 呈现 header 的布局、导航和页脚组件,第二个 - 计算器,它是我的核心组件,具有数据输入等......在计算器组件中,我有管理 state 的按钮,所以当我点击在布局组件 (div) 的任何位置,我需要调用计算器 function 来操作我的按钮。 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.我想要的是从布局中调用 static clickRemoveHandler。 As I guess static is an option that make function global.我猜 static 是一个使 function 成为全局的选项。 So it works, but I got an error TypeError: undefined is not an object (evaluating 'Calculator.state.btnClicked').所以它有效,但我收到错误 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.正如我所见,这意味着当调用 clickRemoveHandler 时,它与计算器组件没有关联,或者无法访问其 state 和道具。 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?调用 function 时传递计算器 state 还是有其他更优雅的方法?

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 .我建议您描述的情况(不同级别的不同组件需要访问某些 state 并对其进行操作)使用 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".您也可以查看 state 管理器,例如ReduxMobX ,但在这种特殊情况下,它会产生开销,因为您的应用程序不是那么“庞大”。 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.基本上你需要创建一些单独的文件夹(你可以称之为context ),在里面你应该创建上下文本身,导出它并将它包装在你最上层的组件中,这样所有的孩子都可以使用它。

You can find an example here: https://codesandbox.io/s/spring-glitter-0vzul .您可以在此处找到示例: https://codesandbox.io/s/spring-glitter-0vzul

Here is a link to documentation: https://reactjs.org/docs/context.html这是文档的链接: https://reactjs.org/docs/context.html

I can provide you some more details if you need如果您需要,我可以为您提供更多详细信息

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首先我从 Layout 组件调用 handleClick 作为 onclick 事件,然后从计算器再次调用它

  componentDidUpdate() {
    if (this.context.clicked) {
      this.clickRemoveHandler(this.context.clickedEvt)
    }
  }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM