reactjs - HOC to add prop if it's a certain type -
i trying write hoc adds prop if it's type. iterating through depth first. when try set prop says it's not extensible, trying add prop of value heehaw:
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 field 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; } } ) } am doing wrong?
well came own solution. i'm not mutating props, added complication of holding on mutable version of tree. can use cleaning.
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 field found const viewelementnew = { node: view, parentelement: null }; const tree = [viewelementnew]; // stack // parentelement ref parentelement in elements const elementsbydepth = {}; // key depth, value array of element's @ depth const elementsbyparentid = {}; // key 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 clone, set true if props 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 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); } } } // react.cloneelement deepest first if needsclone === true let depth = depthmax + 1; while (depth--) { // console.log('doing elementsbydepth[depth] of depth:', depth); (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 { // 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; } } usage:
import react 'react' import reactdom 'react-dom' import addpropsifhoc 'add-props-if' // 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); // app component class app extends react.purecomponent { render() { return ( <div classname="app"> <blah /> </div> ) } } // render reactdom.render(<app />, document.getelementbyid('app')) here working - https://codesandbox.io/s/6y1lrn7yww
here demo adds props <field> children: https://codesandbox.io/s/9zp9207nvy
Comments
Post a Comment