Gọi phương thức con từ cha mẹ


474

Tôi có hai thành phần.

  1. Thành phần phụ huynh
  2. Thành phần con

Tôi đã cố gắng gọi phương pháp của con từ Cha mẹ, tôi đã thử cách này nhưng không thể có kết quả

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

Có cách nào để gọi phương pháp của con từ cha mẹ không?

Lưu ý: Thành phần cha mẹ và con nằm trong hai tệp khác nhau


Mặc dù tôi rất muộn về vấn đề này, nhưng tôi cũng đang học React vì vậy tôi muốn biết về trường hợp mà cha mẹ cần gọi phương thức con. Bạn vui lòng giải thích?
Akshay Raut

Bất cứ ai cũng biết làm thế nào để điều này từ các chức năng mũi tên? stackoverflow.com/questions/60015693/ hy
Thomas Segato

@AkshayRaut IMO một trường hợp sử dụng tốt: một biểu mẫu mục đích chung với các hàm đặt lại và gửi, sau này trả về các giá trị của biểu mẫu.
Julian K

Câu trả lời:


702

Trước hết, hãy để tôi bày tỏ rằng đây thường không phải là cách để giải quyết mọi thứ ở vùng đất React. Thông thường những gì bạn muốn làm là truyền lại chức năng cho trẻ em trong các đạo cụ và truyền thông báo từ trẻ em trong các sự kiện (hoặc tốt hơn nữa dispatch:).

Nhưng nếu bạn phải đưa ra một phương thức bắt buộc trên một thành phần con, bạn có thể sử dụng ref . Hãy nhớ rằng đây là một lối thoát và thường chỉ ra một thiết kế tốt hơn có sẵn.

Trước đây, ref chỉ được hỗ trợ cho các thành phần dựa trên Class. Với sự ra đời của React Hook , đó không còn là vấn đề nữa

Sử dụng móc và các thành phần chức năng ( >= 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>

Tài liệu cho đâyuseImperativeHandle() là :

useImperativeHandletùy chỉnh giá trị cá thể được hiển thị cho các thành phần cha mẹ khi sử dụng ref.

Sử dụng các thành phần lớp ( >= 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 kế thừa ( <= react@16.3)

Đối với mục đích lịch sử, đây là kiểu dựa trên cuộc gọi lại mà bạn sử dụng với các phiên bản React trước 16.3:

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>


23
Tôi mệt mỏi, nhưng kết thúc với lỗi này "_this2.refs.child.getAlert không phải là một chức năng"
N8FURY

22
Đó là bởi vì connecttrả về một thành phần bậc cao hơn bao bọc cá thể ban đầu của bạn. Bạn sẽ cần gọi getWrappedInstance()vào thành phần được kết nối trước để có được thành phần ban đầu của bạn. Sau đó, bạn có thể gọi các phương thức ví dụ trên đó.
rossipedia

16
Đây không thực sự là một mô hình tốt. Không đề cập đến refs chuỗi được nhăn mặt. Tốt hơn là chuyển các đạo cụ vào thành phần con và sau đó nhấp vào nút cha mẹ thay đổi trạng thái của cha mẹ và truyền một mục trạng thái vào con sẽ kích hoạt đứa trẻ componentWillReceivePropsvà sử dụng nó làm kích hoạt.
ffxsam

8
Không, nó thường không phải mẫu tốt nhất, nó sẽ là một lối thoát khi bạn cần nó và chỉ nên được sử dụng trong trường hợp khẩn cấp. Ngoài ra, câu trả lời này được viết khi các chuỗi giới thiệu vẫn còn, và bạn đúng rằng chúng không phải là cách làm "chính xác" trong những ngày này.
rossipedia

35
Nếu thực hành tốt nhất là tạo ra một mê cung logic để làm một việc đơn giản như gọi phương thức của thành phần con - thì tôi không đồng ý với thực tiễn tốt nhất.
aaaaaa

149

Bạn có thể sử dụng một mẫu khác ở đây:

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

Những gì nó làm là thiết lập clickChildphương thức của cha mẹ khi con được gắn kết. Theo cách này khi bạn nhấp vào nút trong cha mẹ, nó sẽ gọi cuộc gọi clickChildnào là con getAlert.

Điều này cũng hoạt động nếu con bạn được bao bọc connect()vì vậy bạn không cần getWrappedInstance()hack.

Lưu ý bạn không thể sử dụng onClick={this.clickChild}trong cha mẹ vì khi kết xuất cha mẹ con không được gắn kết nên this.clickChildchưa được chỉ định. Sử dụng onClick={() => this.clickChild()}là tốt bởi vì khi bạn nhấp vào nút this.clickChildđã được chỉ định.


5
Tôi hiểu _this2.clickChild is not a functiontại sao?
tatsu

1
đừng bao giờ làm việc này với tôi: github.com/kriasoft/react-starter-kit/issues/
mẹo

5
không làm việc chỉ có câu trả lời này hoạt động: github.com/kriasoft/react-starter-kit/issues/
mẹo

2
Đây là một kỹ thuật thú vị. Nó khá sạch sẽ và dường như không phá vỡ bất kỳ quy tắc nào. Nhưng tôi nghĩ rằng câu trả lời của bạn sẽ đầy đủ hơn (và đáp ứng mong đợi) nếu bạn thêm một ràng buộc. Tôi thích câu trả lời rất nhiều, tôi đã đăng nó về vấn đề Github liên quan này .
joeytwiddle

7
Đây phải là câu trả lời được chấp nhận
Jesus Gomez

27

https://facebook.github.io/react/tips/expose-component-fifts.html để biết thêm câu trả lời tham khảo tại đây Gọi phương thức trên các thành phần trẻ em React

Bằng cách xem xét các phần giới thiệu của thành phần "lý do", bạn sẽ phá vỡ đóng gói và không thể cấu trúc lại thành phần đó mà không kiểm tra cẩn thận tất cả các vị trí mà nó sử dụng. Vì điều này, chúng tôi thực sự khuyên bạn nên coi ref là riêng tư đối với một thành phần, giống như trạng thái.

Nói chung, dữ liệu nên được truyền xuống cây thông qua các đạo cụ. Có một vài trường hợp ngoại lệ cho việc này (chẳng hạn như gọi .f Focus () hoặc kích hoạt hoạt ảnh một lần không thực sự "thay đổi" trạng thái) nhưng bất cứ khi nào bạn phơi bày một phương thức gọi là "set", các đạo cụ thường một sự lựa chọn tốt hơn Cố gắng làm cho nó để thành phần đầu vào bên trong lo lắng về kích thước và hình dạng của nó để không có tổ tiên nào làm được.


5
Đây là nguồn gốc của câu trả lời này: thảo luận.reactjs.org / t / . Không có vấn đề với việc trích dẫn người khác, nhưng ít nhất là đưa vào một số tài liệu tham khảo.
Jodo

1
Làm thế nào chính xác điều này phá vỡ đóng gói nhiều hơn đạo cụ?
Timmmm

16

Phương pháp thay thế với useEffect:

Cha mẹ:

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

Bọn trẻ:

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

2
Điều này sẽ nhận được nhiều phiếu bầu hơn
Ali Al Amine

Thi thiên Nếu mong muốn của bạn chỉ là hiển thị lại biểu mẫu (ví dụ: để đặt lại các trường đầu vào) thì bạn thậm chí không cần bao gồm useEffect, bạn có thể làm cho prop được gửi vào thay đổi thành phần
Matt Fletcher

8

Chúng ta có thể sử dụng ref theo cách khác như-

Chúng ta sẽ tạo một phần tử Parent, nó sẽ kết xuất một <Child/>thành phần. Như bạn có thể thấy, thành phần sẽ được kết xuất, bạn cần thêm thuộc tính ref và cung cấp tên cho nó.
Sau đó, triggerChildAlerthàm, nằm trong lớp cha sẽ truy cập thuộc tính refs của bối cảnh này (khi triggerChildAlertchức năng được kích hoạt sẽ truy cập tham chiếu con và nó sẽ có tất cả các chức năng của phần tử con).

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

Bây giờ, thành phần con, như được thiết kế theo lý thuyết trước đây, sẽ trông như sau:

class Child extends React.Component {
    callChildMethod() {
        alert('Hello World');
        // to return some value
        // return this.state.someValue;
    }

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

Đây là mã nguồn-
Hy vọng sẽ giúp bạn!


1
Chuỗi refs không được dùng nữa. Reacjs.org/docs/refs-and-the-dom.html#legacy-api-opes-refs
Cory McAboy

4

Nếu bạn đang làm điều này đơn giản chỉ vì bạn muốn Trẻ cung cấp một đặc điểm có thể sử dụng lại cho cha mẹ của nó, thì bạn có thể xem xét việc đó bằng cách sử dụng đạo cụ kết xuất thay thế.

Kỹ thuật đó thực sự làm đảo lộn cấu trúc. Các Childnay kết thúc tốt đẹp phụ huynh, vì vậy tôi đã đổi tên nó để AlertTraitbên dưới. Tôi giữ tên Parentcho sự liên tục, mặc dù bây giờ nó không thực sự là cha mẹ.

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

Trong trường hợp này, AlertTrait cung cấp một hoặc nhiều đặc điểm mà nó truyền lại dưới dạng đạo cụ cho bất kỳ thành phần nào được cung cấp trong chỗ dựa của nó renderComponent.

Phụ huynh nhận được doAlertnhư một chỗ dựa và có thể gọi nó khi cần thiết.

(Để rõ ràng, tôi đã gọi prop renderComponenttrong ví dụ trên. Nhưng trong các tài liệu React được liên kết ở trên, họ chỉ gọi nó render.)

Thành phần Trait có thể kết xuất nội dung xung quanh Parent, trong chức năng kết xuất của nó, nhưng nó không kết xuất bất cứ thứ gì bên trong cha mẹ. Trên thực tế, nó có thể kết xuất những thứ bên trong Parent, nếu nó truyền một prop khác (ví dụ renderChild) cho cha mẹ, mà sau đó cha mẹ có thể sử dụng trong phương thức render của nó.

Điều này hơi khác so với những gì OP yêu cầu, nhưng một số người có thể kết thúc ở đây (như chúng tôi đã làm) vì họ muốn tạo ra một đặc điểm có thể tái sử dụng và nghĩ rằng một thành phần trẻ em là một cách tốt để làm điều đó.


Có một danh sách các mẫu tiện dụng để tạo các đặc điểm có thể sử dụng lại ở đây: Reacjs.org/blog/2016/07/13/ mẹo
joeytwiddle

Điều gì nếu bạn có N đồng hồ bấm giờ và một nút để khởi động lại tất cả. Làm thế nào để đạo cụ render tiện dụng ở đây?
vsync

@vsync Tôi không chắc chắn rằng phương pháp này có thể giúp cho nhiệm vụ của bạn. Nhưng câu trả lời của brickingup có thể giúp ích. Lưu ý rằng họ đã đặt this.clickChild = clicknhưng nhiều đồng hồ bấm giờ của bạn sẽ vượt qua nhiều chức năng, vì vậy bạn sẽ cần lưu trữ tất cả chúng:this.watchRestartFuncs[watchId] = restartWatch
joeytwiddle

1

Bạn có thể đạt được điều này một cách dễ dàng theo cách này

Bước-

  1. Tạo một biến boolean ở trạng thái trong lớp cha. Cập nhật điều này khi bạn muốn gọi một chức năng.
  2. Tạo một biến prop và gán biến boolean.
  3. Từ truy cập thành phần con đó sử dụng biến đó bằng cách sử dụng các đạo cụ và thực hiện phương thức bạn muốn bằng cách có một điều kiện 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>
        );
       }
    }

Bạn có thể muốn sandbox này. Có vẻ như bạn sẽ kết thúc với một vòng lặp vô hạn vì phương thức con sẽ liên tục chạy vì trạng thái cha mẹ được đặt thành đúng.
Isaac Pak

@IsaacPak Vâng, đó là lý do tại sao tôi để lại nhận xét ở đó, nói rằng bạn phải cập nhật trạng thái theo yêu cầu của bạn. Sau đó, nó sẽ không chạy như một vòng lặp vô hạn.
Kusal Kithmal

1

Tôi đang sử dụng useEffecthook để vượt qua cơn đau đầu khi làm tất cả những điều này vì vậy bây giờ tôi chuyển một biến xuống cho con như thế này:

<ParentComponent>
 <ChildComponent arbitrary={value} />
</ParentComponent>
useEffect(() => callTheFunctionToBeCalled(value) , [value]);

1

Tôi không hài lòng với bất kỳ giải pháp nào được trình bày ở đây. Thực sự có một giải pháp rất đơn giản có thể được thực hiện bằng Javascript thuần túy mà không cần dựa vào một số chức năng React ngoài đối tượng đạo cụ cơ bản - và nó mang lại cho bạn lợi ích của việc giao tiếp theo cả hai hướng (cha mẹ -> con, con -> cha mẹ). Bạn cần truyền một đối tượng từ thành phần cha mẹ sang thành phần con. Đối tượng này là những gì tôi gọi là "tham chiếu hai chiều" hoặc viết tắt là biRef. Về cơ bản, đối tượng chứa một tham chiếu đến các phương thức trong cha mẹ mà cha mẹ muốn phơi bày. Và thành phần con gắn các phương thức vào đối tượng mà cha mẹ có thể gọi. Một cái gì đó như thế này:

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

Ưu điểm khác của giải pháp này là bạn có thể thêm nhiều chức năng hơn trong cha mẹ và con trong khi truyền chúng từ cha mẹ sang con chỉ bằng một thuộc tính duy nhất.

Một cải tiến đối với mã ở trên là không thêm trực tiếp các hàm cha và con vào đối tượng biRef mà là các thành viên phụ. Các chức năng cha mẹ nên được thêm vào một thành viên gọi là "cha mẹ" trong khi các chức năng con nên được thêm vào một thành viên gọi là "con".

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

Bằng cách đặt các hàm cha và con vào các thành viên riêng biệt của đối tượng biRef, bạn sẽ có một sự tách biệt rõ ràng giữa hai hàm và dễ dàng xem những hàm nào thuộc về cha mẹ hoặc con. Nó cũng giúp ngăn thành phần con vô tình ghi đè hàm cha nếu cùng một hàm xuất hiện trong cả hai.

Một điều cuối cùng là nếu bạn lưu ý, thành phần cha mẹ tạo đối tượng biRef với var trong khi thành phần con truy cập nó thông qua đối tượng đạo cụ. Có thể không muốn xác định đối tượng biRef trong cha mẹ và truy cập nó từ cha mẹ thông qua tham số đạo cụ riêng của nó (có thể là trường hợp trong hệ thống phân cấp các thành phần UI). Điều này là rủi ro vì đứa trẻ có thể nghĩ rằng một chức năng mà nó đang gọi cha mẹ thuộc về cha mẹ khi nó thực sự có thể thuộc về ông bà. Không có gì sai với điều này miễn là bạn biết về nó. Trừ khi bạn có lý do để hỗ trợ một số hệ thống phân cấp ngoài mối quan hệ cha / con, tốt nhất là tạo biRef trong thành phần cha mẹ của bạn.



0

Tôi nghĩ rằng cách cơ bản nhất để gọi các phương thức là bằng cách đặt một yêu cầu trên thành phần con. Sau đó, ngay khi đứa trẻ xử lý yêu cầu, nó gọi một phương thức gọi lại để đặt lại yêu cầu.

Cơ chế thiết lập lại là cần thiết để có thể gửi cùng một yêu cầu nhiều lần.

Trong thành phần cha mẹ

Trong phương thức kết xuất của cha mẹ:

const { request } = this.state;
return (<Child request={request} onRequestHandled={()->resetRequest()}/>);

Cha mẹ cần 2 phương thức, để giao tiếp với con theo 2 hướng.

sendRequest() {
  const request = { param: "value" };
  this.setState({ request });
}

resetRequest() {
  const request = null;
  this.setState({ request });
}

Trong thành phần con

Đứa trẻ cập nhật trạng thái nội bộ của nó, sao chép yêu cầu từ các đạo cụ.

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

Sau đó, cuối cùng nó xử lý yêu cầu và gửi thiết lập lại cho cha mẹ:

componentDidMount() {
  const { request } = this.state;
  // todo handle request.

  const { onRequestHandled } = this.props;
  if (onRequestHandled != null) onRequestHandled();
}

0

Một cách khác để kích hoạt chức năng con từ cha mẹ là sử dụng componentDidUpdatechức năng trong Thành phần con. Tôi chuyển một chỗ triggerChildFuncdựa từ Cha mẹ sang Con cái, ban đầu là vậy null. Giá trị thay đổi thành chức năng khi nhấp vào nút và Thông báo con thay đổi trongcomponentDidUpdate và gọi chức năng bên trong của chính nó.

Vì prop triggerChildFuncthay đổi thành một chức năng, chúng tôi cũng nhận được một cuộc gọi lại cho Phụ huynh. Nếu Chánh không cần phải biết khi hàm được gọi là giá trị triggerChildFunccó thể ví dụ như thay đổi từ nullđể truethay thế.

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

class Parent extends Component {
  state = {
    triggerFunc: null
  }

  render() {
    return (
      <div>
        <Child triggerChildFunc={this.state.triggerFunc} />
        <button onClick={() => {
          this.setState({ triggerFunc: () => alert('Callback in parent')})
        }}>Click
        </button>
      </div>
    );
  }
}

class Child extends Component {
  componentDidUpdate(prevProps) {
    if (this.props.triggerChildFunc !== prevProps.triggerChildFunc) {
      this.onParentTrigger();
    }
  }

  onParentTrigger() {
    alert('parent triggered me');

    // Let's call the passed variable from parent if it's a function
    if (this.props.triggerChildFunc && {}.toString.call(this.props.triggerChildFunc) === '[object Function]') {
      this.props.triggerChildFunc();
    }
  }

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


render(
  <Parent />,
  document.getElementById('app')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id='app'></div>

CodePen: https://codepen.io/calsal/pen/NWPxbJv?editors=1010


0

Đây là bản demo của tôi: https://stackblitz.com/edit/react-dgz1ee?file=styles.css

Tôi đang sử dụng useEffectđể gọi các phương thức của thành phần trẻ em. Tôi đã thử với Proxy and Setter_Getternhưng sor xa useEffectdường như là cách thuận tiện hơn để gọi một phương thức con từ cha mẹ. Để sử dụng Proxy and Setter_Getter, dường như có một số sự tinh tế cần khắc phục trước tiên, bởi vì phần tử được hiển thị trước hết là một phần tử của objectLike thông qua tính ref.current return => <div/>đặc hiệu của. Liên quanuseEffect , bạn cũng có thể tận dụng phương pháp này để đặt trạng thái của cha mẹ tùy thuộc vào những gì bạn muốn làm với trẻ em.

Trong liên kết của bản demo tôi đã cung cấp, bạn sẽ tìm thấy mã ReactJS đầy đủ của tôi với bản nháp của tôi bên trong để bạn có thể đánh giá cao quy trình làm việc của giải pháp của tôi.

Ở đây tôi chỉ cung cấp cho bạn đoạn trích ReactJS của tôi với mã liên quan. :

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

0

Chúng tôi rất vui với một cái móc tùy chỉnh mà chúng tôi gọi useCounterKey. Nó chỉ thiết lập một counterKey hoặc một khóa được tính từ 0. Hàm nó trả về đặt lại khóa (tức là tăng). (Tôi tin rằng đây là cách thành ngữ nhất trong React để đặt lại một thành phần - chỉ cần nhấn phím.)

Tuy nhiên, hook này cũng hoạt động trong mọi tình huống mà bạn muốn gửi tin nhắn một lần cho khách hàng để làm gì đó. Ví dụ, chúng tôi sử dụng nó để tập trung kiểm soát ở trẻ vào một sự kiện phụ huynh nhất định - nó chỉ tự động lấy nét bất cứ khi nào khóa được cập nhật. (Nếu cần thêm đạo cụ, họ có thể được đặt trước khi đặt lại khóa để chúng có sẵn khi sự kiện xảy ra.)

Phương pháp này có một chút về đường cong học tập, nó không đơn giản như một trình xử lý sự kiện thông thường, nhưng có vẻ như cách xử lý thành ngữ này trong React mà chúng ta đã tìm thấy (vì các khóa đã hoạt động theo cách này). Def mở để phản hồi về phương pháp này nhưng nó đang hoạt động tốt!

// Main helper hook:
export function useCounterKey() {
  const [key, setKey] = useState(0);
  return [key, () => setKey(prev => prev + 1)] as const;
}

Tập quán mẫu:

// 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]);

  // ...
}

(Tín dụng cho Kent Dodds cho khái niệm counterKey .)


-1

Đây là một lỗi? để tìm hiểu: Tôi đồng tình với giải pháp của rossipedia bằng cách sử dụng ForwardRef, useRef, useImperativeHandle

Có một số thông tin sai lệch trực tuyến nói rằng các ref chỉ có thể được tạo từ các thành phần React Class, nhưng bạn thực sự có thể sử dụng các Thành phần Chức năng nếu bạn sử dụng các hook đã nói ở trên. Một lưu ý, các hook chỉ hoạt động với tôi sau khi tôi thay đổi tệp thành không sử dụng vớiRouter () khi xuất thành phần. Tức là một sự thay đổi từ

export default withRouter(TableConfig);

thay vào đó là

export default TableConfig;

Nhìn chung, dù sao thì withRouter () không cần thiết cho một thành phần như vậy, nhưng thường thì nó không ảnh hưởng gì đến nó. Trường hợp sử dụng của tôi là tôi đã tạo một thành phần để tạo Bảng để xử lý việc xem và chỉnh sửa các giá trị cấu hình, và tôi muốn có thể yêu cầu thành phần Con này thiết lập lại các giá trị trạng thái của nó bất cứ khi nào nút Đặt lại của biểu mẫu Cha mẹ được nhấn. UseRef () sẽ không nhận được ref hoặc ref.c hiện tại (tiếp tục nhận null) cho đến khi tôi xóa withRouter () khỏi tệp chứa thành phần con TableConfig của tôi

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.