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

时间:2017-02-19 03:22:34

标签: javascript reactjs dynamic

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

class Foo extends React.Component {
   bar() { ... }
}

我正在呈现Foo以及button,其目的是触发Foo.bar()

render() {

 return (
     <Foo ...>
     </Foo>
     <Button onClick={I want to trigger Foo.bar()} />
 );
}

我尝试过的事情:

  1. <Button >内移动Foo,然后在onClick构造函数中添加<Button/> Foo's - onClick的绑定无效 - 我看到它已附加,但<Button />仍未触发onClick。 (或者,如果它可以工作,如何正确地做到这一点)?
  2. 不能做我想做的解决方案:

    1. 我看到一个potential solution建议收听整个MyComponent中的点击,然后进行一些DOM查询以查找是否点击了实际按钮。但是,这对我来说不起作用,因为MyComponent 拥有这些按钮(这些按钮不是MyComponent.props.children),我更喜欢头脑风暴一个解决方案,不会迫使我必须移动按钮。

    2. Another potential solution无效:我无法让render()<MyComponent />的值返回到var myComp,然后放入<Button onClick={() => {myComp.blah()}} />因为<Button />本身作为一个孩子在<MyComponent />内实例化! (并且,它们都在相同的render()调用中)

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

    4. Using app state (such as a store)不是我想要的 - 或者MyComponent是一个可重复使用的小部件,不能绑定到特定的应用程序状态或听取任何特定的商店或商店行动。

    5. 有什么建议吗?

      由于

2 个答案:

答案 0 :(得分:12)

您可以在父级上定义一个函数,该函数具有对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'));
<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" />

答案 1 :(得分:2)

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

上面的代码沙盒并不总是有效,但是我注意到它在一段时间后开始起作用。

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>;
};