React - 从另一个组件触发组件方法,两者都属于同一个render()

dev*_*dev 5 javascript dynamic reactjs

我有一个自定义组件Foo,其bar功能我想从外部触发:

class Foo extends React.Component {
   bar() { ... }
}
Run Code Online (Sandbox Code Playgroud)

我绘制Foo了一起button,其目的是触发Foo.bar():

render() {

 return (
     <Foo ...>
     </Foo>
     <Button onClick={I want to trigger Foo.bar()} />
 );
}
Run Code Online (Sandbox Code Playgroud)

我尝试过的事情:

  1. 移动<Button >里面Foo,然后加入onClick<Button/>Foo's构造-鼠标点击的结合没有工作-我看它重视,但<Button />仍然不会触发onClick.(或者,如果它可以工作,如何正确地做到这一点)?

没有做我想要的解决方案:

  1. 我看到一个可能的解决方案,它建议在整个过程中听一下点击MyComponent,然后做一些DOM查询以查找是否点击了实际的按钮.这不会对我的工作,但是,由于MyComponent拥有这些按钮(这些按钮都没有MyComponent.props.children),我宁愿一个集思广益的解决方案,不强迫我一定要移动内部的按钮.

  2. 另一个潜在的解决方案不起作用:我不能render()将值返回<MyComponent />到a var myComp,然后在里面<Button onClick={() => {myComp.blah()}} />,因为<Button />它本身<MyComponent />就像孩子一样被实例化!(并且,它们都在相同的render()调用中)

  3. 部分b)#2(上面),使用React-Component静态类方法,也不会工作:我需要基于每个实例.

  4. 使用app状态(例如商店)也不是我想要的 - MyComponent也就是说是一个可重用的小部件,不能绑定到特定的应用程序状态或者监听任何特定的商店或存储操作.

有什么建议?

谢谢

nov*_*yak 13

您可以在父级上定义一个函数,该函数具有对Foo子级的引用.该函数将调用this.refs.foo.yourFunction(); 然后将该函数传递给按钮,以便在单击按钮时调用父函数.在这里添加了一个示例,单击按钮将切换Foo组件的状态(但它可以执行任何操作).

以下示例

class Parent extends React.Component {
  triggerFoo() {
    this.foo.toggle();
  }
  render() {
    return (
      <div>
        <Foo ref={foo => this.foo = foo} />
        <Button onClick={this.triggerFoo.bind(this)}/>
      </div>
    );  
  }
}

class Foo extends React.Component {
  state = {foo: false}
  toggle() {
    this.setState({
      foo: !this.state.foo
    });
  }
  render() {
    return (
      <div>
        Foo Triggered: {this.state.foo.toString()}
      </div>
    );
  }
}


class Button extends React.Component {
  render() {
    return (
      <button onClick={this.props.onClick}>
        Click This
      </button>
    );
  };
}
ReactDOM.render(<Parent />, document.getElementById('root'));
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root" />
Run Code Online (Sandbox Code Playgroud)

  • 快速说明:最新的反应版本似乎不支持'string'引用?根据最新的反应文档(2017年2月),ref现在接受一个回调,其中元素是第一个参数.所以你的上面将是ref = {(foo)=> {this.foo = foo}}(我实际上是使用传统的ref api获得了一个硬的不变违规,但使用回调模式修复了这个问题) (2认同)

kee*_*mor 5

2020 更新

这是使用功能组件和 TS 的方法

  1. setCustomRef发送到CustomComponent并向下发送到CustomButton以设置customRef
  2. customRef发送到ClickDiv
  3. 调用 customRef.click(); 在ClickDiv里面

CSB https://codesandbox.io/s/triggering-component-method-from-another-component-skt8o?file=/src/App.tsx

以上 Codesandbox 并不总是有效,但我注意到它在一段时间后开始工作。

import React from "react";
import "./styles.css";
import Button, { ButtonProps } from "@material-ui/core/Button";

export default function App() {
  const [customRef, setCustomRef] = React.useState<HTMLButtonElement | null>(
    null
  );
  return (
    <div className="App">
      <h3>
        React - Triggering a component method from another component, both
        belonging in the same render()
      </h3>
      <p>
        <ClickDiv customRef={customRef} />
      </p>
      <CustomComponent setCustomRef={setCustomRef} />
    </div>
  );
}

type Props = {
  setCustomRef: React.Dispatch<React.SetStateAction<HTMLButtonElement | null>>;
};

const CustomComponent = ({ setCustomRef }: Props) => {
  const anchorRef = React.useRef<HTMLButtonElement>(null);
  const { current } = anchorRef;
  React.useEffect(() => {
    if (current) {
      setCustomRef(current);
    }
  }, [current, setCustomRef]);

  return <CustomButton ref={anchorRef}>Custom Button</CustomButton>;
};

const CustomButton = React.forwardRef<HTMLButtonElement, ButtonProps>(
  (props, ref) => {
    const onClick = () => {
      alert("CustomButton clicked");
    };
    return (
      <Button ref={ref} {...props} variant="contained" onClick={onClick} />
    );
  }
);

type ClickDivProps = {
  customRef: HTMLButtonElement | null;
};
const ClickDiv = ({ customRef }: ClickDivProps) => {
  const onClick = () => {
    if (customRef) customRef.click();
  };
  return <button onClick={onClick}>Triger Custom Button Click</button>;
};
Run Code Online (Sandbox Code Playgroud)