[javascript] 부모로부터 자식 메서드 호출

두 가지 구성 요소가 있습니다.

  1. 부모 구성 요소
  2. 하위 구성 요소

부모님으로부터 자녀의 방법을 호출하려고했지만이 방법을 시도했지만 결과를 얻을 수 없었습니다.

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

부모로부터 자식 메서드를 호출하는 방법이 있습니까?

참고 : 하위 및 상위 구성 요소는 서로 다른 두 파일에 있습니다.



답변

먼저, 이것이 일반적으로 React 땅에서 물건을 다루는 방법이 아니라고 표현하겠습니다 . 일반적으로 소품으로 어린이에게 기능을 전달하고 이벤트에서 어린이의 알림을 전달하는 것이 좋습니다 dispatch.

그러나 자식 구성 요소에 명령 적 방법을 노출 해야하는 경우 refs 를 사용할 수 있습니다 . 이것은 탈출구이며 일반적으로 더 나은 디자인을 사용할 수 있음을 나타냅니다.

이전에는 클래스 기반 구성 요소에 대해서만 참조가 지원되었습니다. React Hooks 가 등장하면서 더 이상 그렇지 않습니다.

후크 및 기능 구성 요소 사용 ( >= react@16.8)

const { forwardRef, useRef, useImperativeHandle } = React;

// We need to wrap component in `forwardRef` in order to gain
// access to the ref object that is assigned using the `ref` prop.
// This ref is passed as the second parameter to the function component.
const Child = forwardRef((props, ref) => {

  // The component instance will be extended
  // with whatever you return from the callback passed
  // as the second argument
  useImperativeHandle(ref, () => ({

    getAlert() {
      alert("getAlert from Child");
    }

  }));

  return <h1>Hi</h1>;
});

const Parent = () => {
  // In order to gain access to the child component instance,
  // you need to assign it to a `ref`, so we call `useRef()` to get one
  const childRef = useRef();

  return (
    <div>
      <Child ref={childRef} />
      <button onClick={() => childRef.current.getAlert()}>Click</button>
    </div>
  );
};

ReactDOM.render(
  <Parent />,
  document.getElementById('root')
);
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>

<div id="root"></div>

설명서 useImperativeHandle()다음과 같습니다.

useImperativeHandle를 사용할 때 상위 구성 요소에 노출되는 인스턴스 값을 사용자 정의합니다 ref.

클래스 구성 요소 사용 ( >= react@16.4)

const { Component } = React;

class Parent extends Component {
  constructor(props) {
    super(props);
    this.child = React.createRef();
  }

  onClick = () => {
    this.child.current.getAlert();
  };

  render() {
    return (
      <div>
        <Child ref={this.child} />
        <button onClick={this.onClick}>Click</button>
      </div>
    );
  }
}

class Child extends Component {
  getAlert() {
    alert('getAlert from Child');
  }

  render() {
    return <h1>Hello</h1>;
  }
}

ReactDOM.render(<Parent />, document.getElementById('root'));
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
<div id="root"></div>

레거시 API ( <= react@16.3)

역사적으로 16.3 이전의 React 버전에서 사용하는 콜백 기반 스타일은 다음과 같습니다.

const { Component } = React;
const { render } = ReactDOM;

class Parent extends Component {
  render() {
    return (
      <div>
        <Child ref={instance => { this.child = instance; }} />
        <button onClick={() => { this.child.getAlert(); }}>Click</button>
      </div>
    );
  }
}

class Child extends Component {
  getAlert() {
    alert('clicked');
  }

  render() {
    return (
      <h1>Hello</h1>
    );
  }
}


render(
  <Parent />,
  document.getElementById('app')
);
<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="app"></div>


답변

여기서 다른 패턴을 사용할 수 있습니다.

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

clickChild자식이 마운트 될 때 부모의 방법 을 설정하는 것입니다. 이런 식으로 부모의 버튼을 클릭하면 clickChildchild ‘s를 호출합니다 getAlert.

이것은 자녀가 포장되어 해킹이 connect()필요하지 않은 경우에도 작동합니다 getWrappedInstance().

onClick={this.clickChild}부모가 렌더링 될 때 자식이 마운트 this.clickChild되지 않았으므로 아직 할당되지 않았 으므로 부모에서 사용할 수 없습니다 . onClick={() => this.clickChild()}버튼을 클릭하면 this.clickChild이미 할당되어 있어야 하기 때문에 사용하는 것이 좋습니다.


답변

https://facebook.github.io/react/tips/expose-component-functions.html
자세한 답변은 여기를 참조하십시오 React 하위 구성 요소에 대한 메소드 호출

“이유”구성 요소의 참조를 살펴보면 캡슐화가 깨지고 사용 된 모든 위치를 신중하게 검사하지 않고 해당 구성 요소를 리팩터링 할 수 없습니다. 이 때문에 ref는 상태와 매우 유사하게 구성 요소에 대한 비공개로 처리하는 것이 좋습니다.

일반적으로 데이터는 소품을 통해 트리로 전달되어야합니다. 이에 대한 몇 가지 예외가 있습니다 (예 : .focus () 호출 또는 상태를 실제로 “변경”하지 않는 일회성 애니메이션 트리거). “set”이라는 메서드를 노출 할 때마다 소품은 일반적으로 더 나은 선택입니다. 내부 입력 구성 요소가 크기와 모양에 대해 걱정하여 조상이 처리하지 않도록하십시오.


답변

useEffect를 사용한 대체 방법 :

부모의:

const [refresh, doRefresh] = useState(0);
<Button onClick={()=>doRefresh(refresh+1)} />
<Children refresh={refresh} />

어린이:

useEffect(() => {
    refresh(); //children function of interest
  }, [props.refresh]);


답변

다른 방법으로 심판을 사용할 수 있습니다.

Parent 요소를 만들려고합니다 <Child/>. 구성 요소 를 렌더링합니다 . 보다시피, 렌더링 될 컴포넌트는 ref 속성 을 추가하고 그 이름을 제공해야합니다.
그런 다음 triggerChildAlert부모 클래스에있는 triggerChildAlert함수는 이 컨텍스트의 refs 속성에 액세스합니다 ( 함수가 트리거되면 자식 참조에 액세스하고 자식 요소의 모든 기능을 갖습니다).

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

소스 코드 는 다음과 같습니다 .
희망이 당신을 도울 것입니다!


답변

Child가 재사용 가능한 특성을 부모에게 제공하기를 원하기 때문에이 작업을 수행하는 경우 render-props사용하여 수행하는 것을 고려할 수 있습니다. 대신 좋습니다.

이 기술은 실제로 구조를 거꾸로 뒤집습니다. 는 Child내가로 이름을 바꾼 그래서 지금, 부모를 감싸고 AlertTrait아래. Parent지금은 부모가 아니지만 연속성을 위해 이름 을 유지했습니다.

// Use it like this:

  <AlertTrait renderComponent={Parent}/>


class AlertTrait extends Component {
  // You may need to bind this function, if it is stateful
  doAlert() {
    alert('clicked');
  }
  render() {
    return this.props.renderComponent(this.doAlert);
  }
}

class Parent extends Component {
  render() {
    return (
      <button onClick={this.props.doAlert}>Click</button>
    );
  }
}

이 경우, AlertTrait은 하나 이상의 특성을 제공하며, 이는 특성에 제공된 구성 요소에 대한 특성으로 소품으로 전달됩니다 renderComponent.

부모는 doAlert소품으로 받고 필요할 때 전화를 걸 수 있습니다.

(명확하게하기 renderComponent위해 위 예제에서 prop 을 호출했지만 위의 React docs에서는 그냥 호출했습니다 render.)

Trait 컴포넌트는 렌더링 기능에서 부모를 둘러싼 물건을 렌더링 할 수 있지만 부모 내부에는 아무것도 렌더링하지 않습니다. 실제로 다른 소품을 전달하면 부모 내부에 물건을 렌더링 할 수 있습니다 (예 :renderChild 할 수 있습니다. 그러면 부모는 렌더링 방법 중에 사용할 수 있습니다.

이것은 OP가 요청한 것과는 다소 다르지만 일부 사람들은 재사용 가능한 특성을 만들고 싶었고 자식 구성 요소가 그렇게하는 좋은 방법이라고 생각했기 때문에 여기에서 끝날 수 있습니다.


답변

이런 식으로 쉽게 달성 할 수 있습니다

단계

  1. 부모 클래스의 상태에서 부울 변수를 만듭니다. 함수를 호출하려고 할 때 이것을 업데이트하십시오.
  2. prop 변수를 작성하고 부울 변수를 지정하십시오.
  3. 자식 구성 요소에서 props를 사용하여 해당 변수에 액세스하고 if 조건을 사용하여 원하는 메소드를 실행하십시오.

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