Aux fins de débogage dans la console, existe-t-il un mécanisme disponible dans React pour utiliser une instance d'élément DOM afin d'obtenir le composant React de sauvegarde?
Cette question a déjà été posée dans le contexte de son utilisation dans le code de production. Cependant, je me concentre sur les constructions de développement à des fins de débogage.
Je connais l’extension Chrome de débogage pour React , mais elle n’est pas disponible dans tous les navigateurs. En combinant l'explorateur DOM et la console, il est facile d'utiliser le raccourci '$ 0' pour accéder aux informations relatives à l'élément DOM mis en évidence.
J'aimerais écrire quelque chose comme ceci dans la console de débogage: GetComponentFromElement ($ 0) .props
Même dans la version de développement de React, n’existe-t-il aucun mécanisme permettant d’utiliser éventuellement le ReactId de l’élément pour obtenir le composant?
Je viens de lire la documentation et, autant que je sache, aucune des API exposées de manière externe ne vous permet d'entrer directement et de rechercher un composant React par ID. Cependant, vous pouvez mettre à jour votre appel React.render()
initial et conserver la valeur de retour quelque part, par exemple:
window.searchRoot = React.render(React.createElement......
Vous pouvez ensuite référencer searchRoot et parcourir directement cette information ou la parcourir à l'aide du React.addons.TestUtils
. par exemple. cela vous donnera tous les composants:
var componentsArray = React.addons.TestUtils.findAllInRenderedTree(window.searchRoot, function() { return true; });
Il existe plusieurs méthodes intégrées pour filtrer cette arborescence, ou vous pouvez écrire votre propre fonction pour renvoyer uniquement les composants en fonction du contrôle que vous avez écrit.
Plus d'informations sur TestUtils ici: https://facebook.github.io/react/docs/test-utils.html
Voici ce que j'utilise: (mis à jour pour fonctionner avec React <16 et 16+)
window.FindReact = function(dom) {
let key = Object.keys(dom).find(key=>key.startsWith("__reactInternalInstance$"));
let internalInstance = dom[key];
if (internalInstance == null) return null;
if (internalInstance.return) { // react 16+
return internalInstance._debugOwner
? internalInstance._debugOwner.stateNode
: internalInstance.return.stateNode;
} else { // react <16
return internalInstance._currentElement._owner._instance;
}
}
Et puis l'utiliser:
var someElement = document.getElementById("someElement");
FindReact(someElement).setState({test1: test2});
Voici. Cela prend en charge React 16+
window.findReactComponent = function(el) {
for (const key in el) {
if (key.startsWith('__reactInternalInstance$')) {
const fiberNode = el[key];
return fiberNode && fiberNode.return && fiberNode.return.stateNode;
}
}
return null;
};
j'ai écrit ce petit hack pour permettre l'accès à tout composant de réaction de son nœud dom
var ReactDOM = require('react-dom');
(function () {
var _render = ReactDOM.render;
ReactDOM.render = function () {
return arguments[1].react = _render.apply(this, arguments);
};
})();
vous pouvez alors accéder directement à n’importe quel composant en utilisant:
document.getElementById("lol").react
ou en utilisant JQuery
$("#lol").get(0).react
Voici un petit extrait que j'utilise actuellement.
Cela fonctionne avec React 0.14.7.
let searchRoot = ReactDom.render(ROOT, document.getElementById('main'));
var getComponent = (comp) => comp._renderedComponent ? getComponent(comp._renderedComponent) : comp;
var getComponentById = (id)=> {
var comp = searchRoot._reactInternalInstance;
var path = id.substr(1).split('.').map(a=> '.' + a);
if (comp._rootNodeID !== path.shift()) throw 'Unknown root';
while (path.length > 0) {
comp = getComponent(comp)._renderedChildren[path.shift()];
}
return comp._instance;
};
window.$r = (node)=> getComponentById(node.getAttribute('data-reactid'))
pour l'exécuter, ouvrez Devtools, mettez en surbrillance un élément à examiner et entrez le type de console suivant: $r($0)
Installez React devtools et utilisez l'option suivant pour accéder à l'élément de réaction du noeud dom correspondant ($ 0)
pour 0.14.8
var findReactNode = (node) =>Object.values(__REACT_DEVTOOLS_GLOBAL_HOOK__.helpers)[0]
.getReactElementFromNative(node)
._currentElement;
findReactNode($0);
Bien sûr, c'est un hack seulement ..
Réagissez à la version 16+:
Si vous voulez que l'occurrence du composant React la plus proche à laquelle appartient l'élément DOM sélectionné, voici comment vous pouvez la trouver (modifiée à partir de @ Guan-Gui's solution):
window.getComponentFromElement = function(el) {
for (const key in el) {
if (key.startsWith('__reactInternalInstance$')) {
const fiberNode = el[key];
return fiberNode && fiberNode._debugOwner && fiberNode._debugOwner.stateNode;
}
}
return null;
};
Leur astuce consiste ici à utiliser la propriété _debugOwner
, qui est une référence à FiberNode
du composant le plus proche dont fait partie l'élément DOM.
Caveat: les composants ne fonctionneront que dans le mode dev. Ils auront la propriété _debugOwner
. Cela ne fonctionnerait pas en mode de production.
J'ai créé cet extrait pratique que vous pouvez exécuter dans votre console pour pouvoir cliquer sur n'importe quel élément et obtenir l'instance du composant React à laquelle il appartient.
document.addEventListener('click', function(event) {
const el = event.target;
for (const key in el) {
if (key.startsWith('__reactInternalInstance$')) {
const fiberNode = el[key];
const component = fiberNode && fiberNode._debugOwner;
if (component) {
console.log(component.type.displayName || component.type.name);
window.$r = component.stateNode;
}
return;
}
}
});
J'ai adapté la réponse de @ Venryx avec une version ES6 légèrement adaptée à mes besoins. Cette fonction d'assistance renvoie l'élément en cours au lieu de la propriété _owner._instance.
getReactDomComponent(dom) {
const internalInstance = dom[Object.keys(dom).find(key =>
key.startsWith('__reactInternalInstance$'))];
if (!internalInstance) return null;
return internalInstance._currentElement;
}
v15 et v16 compatibles avec svg, html, comment, noeuds de texte
/* Node extends text, svg, html
usage for node $0:
$0.reactive // returns [node, parentNode, rootNode]
$0.react.props // {any:'prop'}
$0.react.setState(...) // update
*/
Object.defineProperties(Node.prototype, {
_react: {writable:true, value:''}
,reactKey: {
get: function(){
let symbol = this._react;
if(symbol){ return symbol; }
// v15, v16 use a string as key, probably a real symbol in the future
symbol = Object.keys(this).find(key => key.startsWith('__reactInternalInstance$'));
return Node.prototype._react = symbol || '';
}
}
// try to find the props/state/React-instance
,react: {
get: function(){
let react = this[ this.reactKey ] || null;
let $0;
if(react){
$0 = react._currentElement;
if($0){ // v15
if($0._owner){
return $0._owner._instance;
}else{
return $0;
};
}
$0 = react.return;
if($0){ // v16
// develop mode only: return react._debugOwner.stateNode
// both develop and prod modes:
return $0.stateNode
}
}else if(this._reactRootContainer){
// v16 _internalRoot === _internalRoot.current.stateNode
return this._reactRootContainer._internalRoot;
}
return react;
}
}
// make a list of self, ancestors that make up this branch of the tree
,reactive: {
get: function(list=[]){
let $0 = this;
while($0 && !$0[ $0.reactKey ] && !$0._reactRootContainer ){
$0 = $0.previousSibling;
};
if($0 && ($0[$0.reactKey] || $0._reactRootContainer)){
list.Push($0);
};
$0 = this;
while($0 = $0.parentNode){
if($0[ $0.reactKey ] || $0._reactRootContainer){
list.Push($0);
}
};
return list;
}
}
});