Javascript 从父级调用子方法

Javascript 从父级调用子方法,javascript,reactjs,Javascript,Reactjs,我有两个部分: 父组件 子组件 我试图从父级调用Child的方法,我尝试了这种方法,但没有得到结果: class Parent extends Component { render() { return ( <Child> <button onClick={Child.getAlert()}>Click</button> </Child> ); } } class Chi

我有两个部分:

  • 父组件
  • 子组件
  • 我试图从父级调用Child的方法,我尝试了这种方法,但没有得到结果:

    class Parent extends Component {
      render() {
        return (
          <Child>
            <button onClick={Child.getAlert()}>Click</button>
          </Child>
          );
        }
      }
    
    class Child extends Component {
      getAlert() {
        alert('clicked');
      }
     
      render() {
        return (
          <h1 ref="hello">Hello</h1>
        );
      }
    }
    
    类父级扩展组件{
    render(){
    返回(
    点击
    );
    }
    }
    类子扩展组件{
    getAlert(){
    警报(“点击”);
    }
    render(){
    返回(
    你好
    );
    }
    }
    
    有没有办法从父对象调用子对象的方法


    注意:子组件和父组件位于两个不同的文件中。

    首先,让我表示,在React land中,这通常不是处理事情的方式。通常,您要做的是将功能传递给道具中的子级,并在事件中传递来自子级的通知(或者更好:)

    但如果必须在子组件上公开命令式方法,则可以使用。请记住,这是一个逃生舱口,通常表明有更好的设计可用

    以前,只有基于类的组件才支持引用。 随着技术的发展,情况不再如此

    现代版使用挂钩(
    v16.8+
    const{forwardRef,useRef,useImperialiveHandle}=React;
    //我们需要将组件包装在'forwardRef'中以获得
    //访问使用'ref'属性指定的ref对象。
    //此ref作为第二个参数传递给函数组件。
    const Child=forwardRef((道具,ref)=>{
    //组件实例将被扩展
    //无论你从回调中返回什么
    //作为第二个论点
    使用命令式句柄(参考,()=>({
    getAlert(){
    警报(“从子项获取警报”);
    }
    }));
    返回Hi;
    });
    常量父项=()=>{
    //为了访问子组件实例,
    //您需要将其分配给一个'ref',因此我们调用'useRef()'来获得一个
    const childRef=useRef();
    返回(
    childRef.current.getAlert()}>单击
    );
    };
    ReactDOM.render(
    ,
    document.getElementById('root'))
    );
    
    
    
    有关更多答案,请参阅此处

    通过查看“reason”组件的引用,您破坏了封装,使得在不仔细检查所有使用位置的情况下无法重构该组件。因此,我们强烈建议将引用视为组件的私有引用,就像状态一样


    一般来说,数据应该通过道具向下传递。有一些例外情况(例如调用.focus()或触发一个不会真正“改变”状态的一次性动画),但每当您公开一个名为“set”的方法时,道具通常是更好的选择。尽量使内部输入组件担心其大小和外观,这样它的祖先就不会担心了。

    您可以在这里使用另一种模式:

    class Parent extends Component {
     render() {
      return (
        <div>
          <Child setClick={click => this.clickChild = click}/>
          <button onClick={() => this.clickChild()}>Click</button>
        </div>
      );
     }
    }
    
    class Child extends Component {
     constructor(props) {
        super(props);
        this.getAlert = this.getAlert.bind(this);
     }
     componentDidMount() {
        this.props.setClick(this.getAlert);
     }
     getAlert() {
        alert('clicked');
     }
     render() {
      return (
        <h1 ref="hello">Hello</h1>
      );
     }
    }
    
    类父级扩展组件{
    render(){
    返回(
    this.clickChild=单击}/>
    单击此项。clickChild()}>单击
    );
    }
    }
    类子扩展组件{
    建造师(道具){
    超级(道具);
    this.getAlert=this.getAlert.bind(this);
    }
    componentDidMount(){
    this.props.setClick(this.getAlert);
    }
    getAlert(){
    警报(“点击”);
    }
    render(){
    返回(
    你好
    );
    }
    }
    
    它所做的是在装入子对象时设置父对象的
    clickChild
    方法。这样,当您单击父级中的按钮时,它将调用
    clickChild
    ,调用child的
    getAlert

    如果您的孩子是用
    connect()
    包装的,那么这也适用,这样您就不需要
    getWrappedInstance()
    hack


    注意:您不能在父级中使用
    onClick={this.clickChild}
    ,因为当呈现父级时,未装入子级,因此
    this.clickChild
    尚未分配。使用
    onClick={()=>this.clickChild()}
    是可以的,因为当您单击按钮
    this.clickChild
    时,应该已经指定了它。

    您可以进行继承反转(在此处查找:)。这样你就可以访问要包装的组件的实例(这样你就可以访问它的函数)

    如果你这么做只是因为你想让孩子提供一个可重用的特性给它的父母,那么你可以考虑这样做。

    这项技术实际上将结构颠倒过来。
    子项
    现在包装父项,因此我将其重命名为下面的
    AlertTrait
    。我保留了名称
    Parent
    ,以保持连续性,尽管它现在不是真正的家长

    //像这样使用它:
    类AlertTrait扩展组件{
    //如果此函数使用“this”,则需要绑定此函数
    多勒特(){
    警报(“点击”);
    }
    render(){
    返回this.props.renderComponent({doAlert:this.doAlert});
    }
    }
    类父级扩展组件{
    render(){
    返回(
    点击
    );
    }
    }
    
    在这种情况下,AlertTrait提供了一个或多个特性,它将这些特性作为道具传递给在其
    renderComponent
    prop中给出的任何组件

    父级作为道具接收
    doAlert
    ,并在需要时调用它

    (为了清楚起见,我在上面的示例中调用了prop
    renderComponent
    。但是在上面链接的React文档中,他们只称它为
    render

    Trait组件可以在其render函数中渲染父对象周围的内容,但不会渲染父对象内部的任何内容。实际上,如果它将另一个道具(例如,
    renderChild
    )传递给父级,父级可以在其渲染方法中使用,则它可以渲染父级内部的内容


    这与OP要求的有些不同,但有些人可能会在这里结束(像我们一样),因为他们想创建一个可重用的特性,并且认为子组件是一个很好的方法。

    我认为调用方法的最基本方法是通过在子组件上设置请求。然后尽快
    const { request } = this.state;
    return (<Child request={request} onRequestHandled={()->resetRequest()}/>);
    
    sendRequest() {
      const request = { param: "value" };
      this.setState({ request });
    }
    
    resetRequest() {
      const request = null;
      this.setState({ request });
    }
    
    constructor(props) {
      super(props);
      const { request } = props;
      this.state = { request };
    }
    
    static getDerivedStateFromProps(props, state) {
      const { request } = props;
      if (request !== state.request ) return { request };
      return null;
    }
    
    componentDidMount() {
      const { request } = this.state;
      // todo handle request.
    
      const { onRequestHandled } = this.props;
      if (onRequestHandled != null) onRequestHandled();
    }
    
    class Parent extends React.Component {
        triggerChildAlert(){
            this.refs.child.callChildMethod();
            // to get child parent returned  value-
            // this.value = this.refs.child.callChildMethod();
            // alert('Returned value- '+this.value);
        }
    
        render() {
            return (
                <div>
                    {/* Note that you need to give a value to the ref parameter, in this case child*/}
                    <Child ref="child" />
                    <button onClick={this.triggerChildAlert}>Click</button>
                </div>
            );
        }
    }  
    
    class Child extends React.Component {
        callChildMethod() {
            alert('Hello World');
            // to return some value
            // return this.state.someValue;
        }
    
        render() {
            return (
                <h1>Hello</h1>
            );
        }
    }
    
    class Child extends Component {
       Method=()=>{
       --Your method body--
       }
       render() {
         return (
        //check whether the variable has been updated or not
          if(this.props.updateMethod){
            this.Method();
          }
         )
       }
    }
    
    class Parent extends Component {
    
    constructor(){
      this.state={
       callMethod:false
      }
    
    }
    render() {
       return (
    
         //update state according to your requirement
         this.setState({
            callMethod:true
         }}
         <Child updateMethod={this.state.callMethod}></Child>
        );
       }
    }
    
    <ParentComponent>
     <ChildComponent arbitrary={value} />
    </ParentComponent>
    useEffect(() => callTheFunctionToBeCalled(value) , [value]);
    
    import React, {
      Component,
      createRef,
      forwardRef,
      useState,
      useEffect
    } from "react"; 
    
    {...}
    
    // Child component
    // I am defining here a forwardRef's element to get the Child's methods from the parent
    // through the ref's element.
    let Child = forwardRef((props, ref) => {
      // I am fetching the parent's method here
      // that allows me to connect the parent and the child's components
      let { validateChildren } = props;
      // I am initializing the state of the children
      // good if we can even leverage on the functional children's state
      let initialState = {
        one: "hello world",
        two: () => {
          console.log("I am accessing child method from parent :].");
          return "child method achieve";
        }
      };
      // useState initialization
      const [componentState, setComponentState] = useState(initialState);
      // useEffect will allow me to communicate with the parent
      // through a lifecycle data flow
      useEffect(() => {
        ref.current = { componentState };
        validateChildren(ref.current.componentState.two);
      });
    
    {...}
    
    });
    
    {...}
    
    // Parent component
    class App extends Component {
      // initialize the ref inside the constructor element
      constructor(props) {
        super(props);
        this.childRef = createRef();
      }
    
      // I am implementing a parent's method
      // in child useEffect's method
      validateChildren = childrenMethod => {
        // access children method from parent
        childrenMethod();
        // or signaling children is ready
        console.log("children active");
      };
    
    {...}
    render(){
           return (
              {
                // I am referencing the children
                // also I am implementing the parent logic connector's function
                // in the child, here => this.validateChildren's function
              }
              <Child ref={this.childRef} validateChildren={this.validateChildren} />
            </div>
           )
    }
    
    // Main helper hook:
    export function useCounterKey() {
      const [key, setKey] = useState(0);
      return [key, () => setKey(prev => prev + 1)] as const;
    }
    
    // Sample 1 - normal React, just reset a control by changing Key on demand
    function Sample1() {
      const [inputLineCounterKey, resetInputLine] = useCounterKey();
    
      return <>
        <InputLine key={inputLineCounterKey} />
        <button onClick={() => resetInputLine()} />
      <>;
    }
    
    // Second sample - anytime the counterKey is incremented, child calls focus() on the input
    function Sample2() {
      const [amountFocusCounterKey, focusAmountInput] = useCounterKey();
    
      // ... call focusAmountInput in some hook or event handler as needed
    
      return <WorkoutAmountInput focusCounterKey={amountFocusCounterKey} />
    }
    
    function WorkoutAmountInput(props) {
      useEffect(() => {
        if (counterKey > 0) {
          // Don't focus initially
          focusAmount();
        }
      }, [counterKey]);
    
      // ...
    }
    
    const [refresh, doRefresh] = useState(0);
    <Button onClick={() => doRefresh(prev => prev + 1)} />
    <Children refresh={refresh} />
    
    useEffect(() => {
        performRefresh(); //children function of interest
      }, [props.refresh]);
    
    export default withRouter(TableConfig);
    
    export default TableConfig;
    
    // Parent component.
    function MyParentComponent(props) {
    
       function someParentFunction() {
          // The child component can call this function.
       }
    
       function onButtonClick() {
           // Call the function inside the child component.
           biRef.someChildFunction();
       }
    
       // Add all the functions here that the child can call.
       var biRef = {
          someParentFunction: someParentFunction
       }
    
       return <div>
           <MyChildComponent biRef={biRef} />
           <Button onClick={onButtonClick} />
       </div>;
    }
    
    
    // Child component
    function MyChildComponent(props) {
    
       function someChildFunction() {
          // The parent component can call this function.
       }
    
    
       function onButtonClick() {
          // Call the parent function.
          props.biRef.someParentFunction();
       }
    
       // Add all the child functions to props.biRef that you want the parent
       // to be able to call.
       props.biRef.someChildFunction = someChildFunction;
    
       return <div>
           <Button onClick={onButtonClick} />
       </div>;
    }
    
    // Parent component.
    function MyParentComponent(props) {
    
       function someParentFunction() {
          // The child component can call this function.
       }
    
       function onButtonClick() {
           // Call the function inside the child component.
           biRef.child.someChildFunction();
       }
    
       // Add all the functions here that the child can call.
       var biRef = {
          parent: {
              someParentFunction: someParentFunction
          }
       }
    
       return <div>
           <MyChildComponent biRef={biRef} />
           <Button onClick={onButtonClick} />
       </div>;
    }
    
    
    // Child component
    function MyChildComponent(props) {
    
       function someChildFunction() {
          // The parent component can call this function.
       }
    
    
       function onButtonClick() {
          // Call the parent function.
          props.biRef.parent.someParentFunction();
       }
    
       // Add all the child functions to props.biRef that you want the parent
       // to be able to call.
       props.biRef {
           child: {
                someChildFunction: someChildFunction
           }
       }
    
       return <div>
           <Button onClick={onButtonClick} />
       </div>;
    }
    
    class Parent extends Component {
      ///// 
      getAlert = () => {} // initial value for getAlert
    
      setGetAlertMethod = (newMethod) => {
        this.getAlert = newMethod;
      }
      /////
    
      render() {
        return (
          <Child setGetAlertMethod={this.setGetAlertMethod}>
            <button onClick={this.getAlert}>Click</button>
          </Child>
          );
        }
      }
    
    
    
    class Child extends Component {
      /////
      componentDidMount() {
        this.props.setGetAlertMethod(this.getAlert);
      }
      /////
    
      getAlert() => {
        alert('clicked');
      }
    
      render() {
        return (
          <h1 ref="hello">Hello</h1>
        );
      }
    }
    
    import React, { forwardRef, useRef, useImperativeHandle } from 'react';
    export default function ParentFunction() {
        const childRef = useRef();
        return (
            <div className="container">
                <div>
                    Parent Component
                </div>
                <button
                    onClick={() => { childRef.current.showAlert() }}
                >
                Call Function
                </button>
                <Child ref={childRef}/>
            </div>
        )
    }
    const Child = forwardRef((props, ref) => {
        useImperativeHandle(
            ref,
            () => ({
                showAlert() {
                    alert("Child Function Called")
                }
            }),
        )
        return (
           <div>Child Component</div>
        )
    })
    
    import s from './Child.css';
    
    class Child extends Component {
     getAlert() {
        alert('clicked');
     }
     render() {
      return (
        <h1>Hello</h1>
      );
     }
    }
    
    export default Child;
    
    class Parent extends Component {
     render() {
      onClick() {
        this.refs.child.getAlert();
      }
      return (
        <div>
          <Child ref="child" />
          <button onClick={this.onClick}>Click</button>
        </div>
      );
     }
    }
    
    import React, { useEffect, useState, useRef } from "react";
    import child from "../../child"
    
    const parent: React.FunctionComponent = () => {
      const childRef: any = useRef();
    }
    
    const onDropDownChange: any = (event): void => {
        const target = event.target;
        childRef.current.onFilterChange(target.value);
      };
    
     return <child ref={childRef} />
    
    export default parent;
    
    import React, {   useState,   useEffect,   forwardRef,   useRef,   useImperativeHandle, } from "react";
    
    const Child = forwardRef((props, ref) => {
     useImperativeHandle(ref, () => ({
        onFilterChange(id) {
          console.log("Value from parent", id)
        },
      }));
    })
    
    Child.displayName = "Child";
    
    export default Child;