如何改变深层嵌套的孩子?

时间:2018-04-28 10:06:46

标签: javascript reactjs ecmascript-6

在以下代码中,我希望所有<p>标签都包含&#34; data-mini-slug&#34;要将<input>标签返回的属性。

以下代码在返回一个<p> dom元素时有效。

如何保留dom结构,如何将所有嵌套<p data-mini-slug="hello">元素转换为输入? React是否有内置的解决方案?

function hoc(WrappedComponent) {
    return class Enhancer extends WrappedComponent {
        render() {
            const elementsTree = super.render();
            let newProps = {};
            if (elementsTree) {
                const miniSlug = elementsTree.props['data-mini-slug']
                if (elementsTree.type === "p" && miniSlug) {
                    newProps = { value: `New props is ${miniSlug}` }
                    const props = Object.assign({}, elementsTree.props, newProps)
                    return <input {...props} />
                }

            }
            return elementsTree
        }
    }
}

class Example extends React.Component {
    render() {
        // return <p data-mini-slug="deepChild" data-new-value="Deep nested child" />
        return (
            <div>
                <h1>Hoc dom element conversion</h1>
                <p data-mini-slug="child" data-new-value="Surface child" />
                <div>
                    <div>
                        <p data-mini-slug="deepChild" data-new-value="Deep nested child" />
                    </div>
                </div>
            </div>
        )
    }
}

export default hoc(Example)

2 个答案:

答案 0 :(得分:2)

您可以通过让函数在克隆元素中调用自身来创建循环。

import React from 'react'

function iterateOverChildren(children) {
    return React.Children.map(children, child => {
        if (!React.isValidElement(child)) {
            return child;
        }

        if (child.props.children) {
            child = React.cloneElement(child, {
                children: iterateOverChildren(child.props.children)
            });
        }

        return alterChild(child);
    });

}

function alterChild(child) {

    let newProps = {};
    const miniSlug = child.props['data-mini-slug']
    if (child.type === "p" && miniSlug) {
        newProps = { value: `New props is ${miniSlug}` }
        const props = Object.assign({}, child.props, newProps)
        child =  <input {...props} />
    }

    return child
}

function hoc(WrappedComponent) {
    return class Enhancer extends WrappedComponent {
        render() {
            const elementsTree = super.render();
            return iterateOverChildren(elementsTree.props.children)
        }
    }
}

class Example extends React.Component {
    render() {
        // return <p data-mini-slug="deepChild" data-new-value="Deep nested child" />
        return (
            <div>
                <h1>Hoc dom element conversion</h1>
                <p data-mini-slug="child" data-new-value="Surface child" />
                <div>
                    <div>
                        <p data-mini-slug="deepChild" data-new-value="Deep nested child" />
                    </div>
                </div>
            </div>
        )
    }
}

export default hoc(Example)

答案 1 :(得分:0)

React解决方案将创建一个组件,可以根据某些支柱提取pinput

function Comp(props){
   if(props.dataMiniSlug)
     return <p/>
   else
     return <input/>
}

如果出于某种原因,您必须按照您尝试的方式修改DOM(虚拟),您可以使用React.Children API递归遍历儿童。

render() {
  const rootNode = super.render();
  return transform (rootNode)
}

transform(node) {
  if(node.props.children){
     return React.Children.map(element.props.children, transform)
  }      
  if (node.type === "p" && node.props['data-mini-slug'] !== undefined) {
      return <input { ...node.props, value: `New props is ${node.props['data-mini-slug']}`}/>
  }
  return node
}

我再强烈建议你重新考虑这整个方法,否则希望它有所帮助。