开发者问题收集

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

2020-12-06
1778

我被困在调用 clickRemoveHandler 上。我的想法是,我有两个组件:第一个 - 布局,它呈现页眉、导航和页脚组件;第二个 - 计算器,它是我的核心组件,具有数据输入等功能...在计算器组件中,我有具有托管状态的按钮,因此当我单击布局组件 (div) 上的任意位置时,我需要调用操作按钮的计算器函数。 代码如下:

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})
    }
  }
....
}

这些组件中有很多逻辑,因此它们太强大了,无法发布完整的代码。 但问题是布局中没有计算器引用,计算器本身是通过另一个组件的路由呈现的,因此我无法将任何数据直接从布局传递到计算器。 我想要的是从布局调用静态 clickRemoveHandler。我猜静态是一个使函数全局化的选项。所以它可以工作,但我收到错误 TypeError:未定义不是对象(评估“Calculator.state.btnClicked”)。在我看来,这意味着当调用 clickRemoveHandler 时,它与计算器组件没有关联,或者无法访问其状态和道具。 问题是我如何让它们一起工作?在调用函数时传递计算器状态,还是有其他更优雅的方法来实现?

2个回答

对于您描述的情况(不同级别的不同组件需要访问某些状态并对其进行操作),我建议使用 React context 。您也可以查看 ReduxMobX 等状态管理器,但在这种情况下,由于您的应用程序不是那么“庞大”,因此会产生开销。基本上,您需要创建一些单独的文件夹(您可以将其称为 context ),在其中您应该创建上下文本身,将其导出并将您最上级组件包装在其中,以便所有子组件都可以使用它。

您可以在这里找到一个示例: https://codesandbox.io/s/spring-glitter-0vzul

这是文档的链接: https://reactjs.org/docs/context.html

如果您需要,我可以为您提供更多详细信息

Oleksandr Sakun
2020-12-06

这是一个挑战,但我做到了! 布局组件:

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">

首先,我从布局组件调用 handleClick 作为 onclick 事件,然后从计算器再次调用它

componentDidUpdate() {
    if (this.context.clicked) {
      this.clickRemoveHandler(this.context.clickedEvt)
    }
  }
Mikhail
2020-12-06