avant-propos
Dans un composant parent, nous souhaitons y obtenir l'élément de nœud ou l'instance du composant enfant, afin d'appeler directement la méthode dessus. Les composants de classe et les composants de fonction sont deux manières différentes d'écrire.
1. Utilisez ref dans le composant Class
Dans le composant Class de React, nous createRef
créons ref par
class Parent extends React.Component {
constructor(props) {
super(props)
this.inputRef = React.createRef();
}
componentDidMount() {
console.log(this.inputRef)
this.inputRef.current.focus();
}
render() {
return <input ref={
this.inputRef} />
}
}
Dans l'exemple de code ci-dessus, nous avions l'habitude d' createRef
en créer un ref
et de l'accrocher à l'entrée de l'élément DOM natif. À ce stade, nous pouvons ref.current
faire passer cet élément DOM et appeler la méthode ci-dessus.
Si ref est monté sur un composant Class, ref.current obtient l'instance du composant Class et peut également accéder aux méthodes du composant Class.
Prenons la page ci-dessus comme exemple, le [Plan de dessin] suivant est un sous-composant, lorsque nous montons ref
sur le sous-composant, le composant parent correspondant peut this.ref.current
appeler la méthode sur le sous-composant, comme la liste déroulante pour développer les rappels, les rappels pour les modifications de valeur de la liste déroulante, etc.
2. Composants fonctionnels
ref 回调函数
Une fois le composant monté,l'instance du composant sera transmise à la fonction.Le composant fonction est différent du composant Class et le composant fonction n'a pas d'instance . Ainsi, dans des circonstances normales, la référence ne peut pas être montée sur des composants fonctionnels.
Cependant, les composants de fonction peuvent créer des références. Contrairement aux composants de classe, les composants de fonction utilisent useRef
.
import React, {
memo, useEffect, useRef, useState } from 'react';
const Parent = () => {
const inputRef = useRef(null)
input childRef = useRef(null)
return (
<>
<input ref={
inputRef} onChange={
onChange} />
<Child ref={
childRef} handSave={
handSave} />
</>
)
}
export default memo(Parent)
Remarque : Cette façon d'écrire est grammaticalement correcte, mais si vous souhaitez ref.current
obtenir une instance d'un élément ou d'un sous-composant DOM dans un composant de fonction, vous ne pouvez pas l'obtenir et vous avez besoin d'une autre façon d'écrire.
3. La différence entre createRef et useRef
- createRef ne peut être utilisé que dans les composants de classe Class et useRef ne peut être utilisé que dans les composants fonctionnels.
- createRef renvoie une nouvelle référence à chaque rendu, useRef renvoie la même référence à chaque fois.
- Si la référence créée par createRef est utilisée dans un composant fonctionnel, sa valeur sera continuellement initialisée au fur et à mesure de la réexécution du composant fonctionnel .
4. Conclusions partielles
En résumé, les points suivants peuvent être résumés :
- Élément DOM natif : le courant de ref pointe vers ce nœud
- composant de classe de classe : le courant de la référence pointe vers l'instance du composant
- Composant fonctionnel : le courant de ref pointe vers null, car le composant fonctionnel n'a pas d'instance.
Donc, pour les composants fonctionnels, n'y a-t-il vraiment aucun moyen pour nous d'obtenir et d'appeler les méthodes sur les sous-composants ?
Réponse : Comment est-ce possible, nous pouvons forwardRef
résoudre ce problème en utilisant .
5. forwardRef
forwardRef (passage par référence) est une technique permettant de transmettre automatiquement une référence de référence d'un composant à un composant enfant.
En une phrase : React utilise forwardRef pour terminer la transmission transparente de ref, afin que les composants fonctionnels puissent normalement obtenir les méthodes sur les sous-composants.
5.1 Écriture du code
import React, {
memo, forwardRef, useRef, useImperativeHandle } from 'react';
const App = () => {
const childRef = useRef(null)
const getFocus = () => {
// 调用子组件的方法
childRef.current.inputFocus()
// 也可以调用暴露出来的其他值
childRef.current.setData(20)
}
return (
<>
<Child ref={
childRef}/>
<button onClick ={
getFocus}>点击获取焦点<button/>
</>
)
}
// 子组件
const Child = forwardRef((props, ref) => {
const inputRef = useRef(null)
const [data, setData] = useState('10')
// 使输入框获取焦点的方法
const inputFocus = () => {
inputRef.current.ocus()
}
// 输入框内容改变回调
const changeValue = () => {
console.log('哈哈哈')
}
// 将该方法暴露给父组件
useImperativeHandle(ref, () => ({
inputFocus,
changeValue,
data,
setData
}))
return <input ref={
inputRef} onChange={
changeValue}>
});
5.2 Analyse forwardRef
forwardRef
Vous pouvez directement encapsuler un composant fonctionnel , et le composant fonctionnel encapsulé se verra attribuer la référence (en tant que deuxième paramètre). Si vous attribuez directement ref à un composant fonctionnel qui n'est pas encapsulé par forwardRef, React signalera une erreur dans la console.
forwardRef
Un composant React sera créé, qui pourra transmettre l'attribut ref qu'il accepte à un autre composant sous son arborescence de composants, c'est-à-dire une transmission transparente.
Remarque : le paramètre de forWardRef doit être une fonction
6. useImperativeHandleAnalyse
Lorsqu'il est utilisé directement forwardRef
, nous ne pouvons pas contrôler la valeur à exposer au composant parent, nous l'utilisons donc pour useImperativeHandle
contrôler ce qu'il faut exposer au composant parent.
Remarque : useImperativeHandle doit être utilisé avec forwardRef.
La méthode d'appel est affichée dans l'exemple de code ci-dessus.
6.1 Passage de paramètres
- Le premier paramètre : ref : Reçoit la référence transmise par forwardRef.
- Le deuxième paramètre : createHandle : Fonction de gestion, la valeur de retour est exposée en tant qu'objet ref au composant parent.
- Le troisième paramètre : deps : dépendances deps, les modifications de dépendance forment un nouvel objet ref, ne peuvent pas être transmises
useImperativeHandle nous fournit un élément semblable à une instance qui nous aide à monter le contenu de l'objet renvoyé sur la référence actuelle de la pièce jointe via le deuxième paramètre de useImperativeHandle.
7. Résumé
Les étapes lorsque les composants parent et enfant utilisent les hooks sont les suivantes :
- Le composant parent utilise pour
useRef
créer un objet ref et affecter cet objet ref à la propriété ref du composant enfant. - Le composant enfant s'enveloppe
forwardRef
lui-même avec un , permettant à la référence d'être utilisée comme composant de fonction lui-même. Utilisez ensuiteuseImperativeHandle
la fonction hook pour renvoyer un état ou une méthode dans le deuxième paramètre de fonction de la fonction hook, et l'état ou la méthode renvoyée est accessible par le composant parent. - Le composant parent utilise la propriété de l'objet ref créé
current
pour obtenir l'état ou la méthode exposée par le composant enfant.
8. Points d'attention particuliers :
forwardRef
Lors de l'utilisation et dans les composants fonctionnels useImperativeHandle
, il y a un point particulier qui mérite une attention particulière : la méthode de transmission des paramètres dans les sous-composants . Comme suit:
// 可以使用这样的写法
<Child ref={
childRef} list={
drawingPlanList} editable={
!isDisabled}/>
// 但不用采用这样的写法:这样的 写法有问题,具体原因待排查
const childProps = {
ref: {
childRef},
list: {
drawingPlanList},
editable: {
!isDisabled}
}
< Child {
...childProps}/>