2017-08-18 1 views
1

Ich habe versucht, eine HOC zu schreiben, die eine prop, wenn es ein bestimmter Typ ist. Ich wiederhole zuerst die Tiefe. Aber wenn ich zu setzen versuchen prop es sagt, es ist nicht erweiterbar, ich versuche Stütze value zu HEEHAW hinzuzufügen:HOC Prop hinzufügen, wenn es ein bestimmter Typ ist

function fieldLayoutHOC(WrappedComponent: ComponentType) { 
    return (
     class FieldLayoutWrap extends WrappedComponent { 
      static displayName = wrapDisplayName(WrappedComponent, 'FieldLayoutWrap') 

      render() { 
       const view = super.render() 
       // depth first - stack - last in first out 
       // iterate depth first until a Field is found 
       const elements = [view]; // stack 

       console.log('view:', view); 

       while (elements.length) { 
        const element = elements.pop(); 
        const primative = typeof element; 
        if (primative === 'object') { 
         if (element.type === Field) { 
          // fields.push(element); 
          element.props.value = 'HEEHAW'; /////// not extensible error here 
          console.log('added value HEEHAWW'); 
         } else { 
          if (element.props) { 
           const children = element.props.children; 
           if (children) { 
            if (Array.isArray(children)) { 
             elements.push(...children); 
            } else { 
             elements.push(children); 
            } 
           } 
          } 
         } 
        } 
       } 

       return view; 
      } 
     } 
    ) 
} 

Bin ich es falsch mache?

+0

Es kann ein Weg, dies zu erreichen Arbeit, aber sicherlich React-Dokumentation empfiehlt die Verwendung von [Zusammensetzung statt Vererbung] (https://facebook.github.io/react/docs/composition-vs-inheritance.html). Anstatt eine vorhandene Klasse zu erweitern, können Sie möglicherweise das erreichen, was Sie möchten, indem Sie eins in das andere einfügen. Die äußere Komponente kann eine Logik haben, um die Requisiten zu ändern, die an das Kind übergeben werden. – aherriot

Antwort

1

Nun, ich habe meine eigene Lösung gefunden. Ich mutiere die Requisiten nicht, was die Komplikation hinzufügt, an einer veränderlichen Version des Baumes festzuhalten. Dies kann definitiv etwas Reinigung verwenden.

function addPropsIfHOCFactory(predicate) { // 
    return function addPropsIfHOC(WrappedComponent) { // factory 
    return (
     class FieldLayoutWrap extends WrappedComponent { 

     render() { 
      const view = super.render(); 
      if (!this.addProps) return view; 

      // depth first - stack - last in first out 
      // iterate depth first until a Field is found 
      const viewElementNew = { node: view, parentElement: null }; 
      const tree = [viewElementNew]; // stack // parentElement is ref to parentElement in elements 

      const elementsByDepth = {}; // key is depth, value is array of element's at that depth 
      const elementsByParentId = {}; // key is elementId of parent 
      let elementId = 0; 
      // console.log('view:', view); 

      let depthMax = 0; 

      while (tree.length) { 
      const element = tree.pop(); 

      element.props = element.node.props ? element.node.props : undefined; 
      element.childrenElements = undefined; 
      element.clone = undefined; 
      element.depth = getDepth(element); 
      element.id = elementId++; 
      element.needsClone = false; // if true then clone, its set to true if props are changed 

      if (element.depth > depthMax) depthMax = element.depth; 

      if (!elementsByDepth[element.depth]) { 
       elementsByDepth[element.depth] = []; 
      } 
      elementsByDepth[element.depth].push(element); 

      const node = element.node; 
      const primative = typeof node; 
      if (primative === 'object' && node) { 
       if (predicate(node)) { 
       const addProps = isFunction(this.addProps) ? this.addProps(node) : this.addProps; 
       element.props = Object.assign({}, node.props ? node.props : undefined, addProps); 
       markBranchNeedsClone(element); 
       console.log('added props to node:', element.node); 
       } 
      } 

      if (node.props && node.props.children) { 
       const children = node.props.children; 

       const pushChild = child => { 
       const parent = element; 
       const childElement = { 
        node: child, 
        parentElement: parent 
       } 
       tree.push(childElement); 
       if (!elementsByParentId[parent.id]) elementsByParentId[parent.id] = []; 
       elementsByParentId[parent.id].push(childElement); 

       return childElement; 
       } 

       if (Array.isArray(children)) { 
       element.childrenElements = children.map(pushChild); 
       } else { 
       const child = children; 
       element.childrenElements = pushChild(child); 
       } 
      } 
      } 

      // do React.cloneElement from deepest first IF needsClone === true 
      let depth = depthMax + 1; 
      while (depth--) { 
      // console.log('doing now elementsByDepth[depth] of depth:', depth); 
      for (const element of elementsByDepth[depth]) { 
       if (typeof element.node === 'object' && element.node) { 
       if (!element.needsClone) { 
        element.clone = element.node; 
       } else { 
        let childrenClones = elementsByParentId[element.id]; 
        if (childrenClones) { 
        if (childrenClones.length === 1) { 
         childrenClones = childrenClones[0].clone; 
        } else { 
         childrenClones = childrenClones.map(element => element.clone); 
        } 
        } 
        console.log('CLONING'); 
        element.clone = React.cloneElement(element.node, element.props, childrenClones); 
       } 
       } else { 
       // its a string, number etc 
       element.clone = element.node; 
       } 
      } 
      } 

      // console.log('viewElementNew:', viewElementNew); 
      // console.log('elementsByDepth:', elementsByDepth); 
      // console.log('elementsByParentId:', elementsByParentId); 

      return viewElementNew.clone; 
     } 
     } 
    ) 
    } 
} 

function isFunction(functionToCheck) { 
    var getType = {}; 
    return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]'; 
} 
function getDepth(element) { 
    let depth = 0; 
    let elementCur = element; 
    while (elementCur.parentElement) { 
    elementCur = elementCur.parentElement; 
    depth++; 
    } 
    return depth; 
} 
function markBranchNeedsClone(element) { 
    let elementCur = element; 
    while (elementCur) { 
    elementCur.needsClone = true; 
    elementCur = elementCur.parentElement; 
    } 
} 

Verbrauch:

import React from 'react' 
import ReactDOM from 'react-dom' 
import addPropsIfHOC from 'add-props-if' 

// MY FORM COMPONENT 
class BlahDumb extends React.Component { 
    addProps = { 
    placeholder: 'INJECTED PLACEHOLDER' 
    } 
    render() { 
    return (
     <form> 
     <label htmlFor="url">URL</label> 
     <div> 
      <input id="url" type="text" /> 
      yeppers 
     </div> 
     <div> 
      <input id="foo" type="text" /> 
     </div> 
     </form> 
    ) 
    } 
} 

const BlahPropsAdded = addPropsIfHOC(node => node.type === 'input') 


const Blah = BlahPropsAdded(BlahDumb); 



// MY APP COMPONENT 
class App extends React.PureComponent { 
    render() { 
    return (
      <div className="app"> 
      <Blah /> 
      </div> 
    ) 
    } 
} 

// RENDER 
ReactDOM.render(<App />, document.getElementById('app')) 

Hier arbeitet - https://codesandbox.io/s/6y1lrn7yww

Hier eine Demo, die Requisiten zu <Field> Kinder ergänzt: https://codesandbox.io/s/9zp9207nvy

Verwandte Themen