最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Access children of react element - Stack Overflow

programmeradmin1浏览0评论

Imagine having React ponent

function List() {
   return (<ul>
             <li>1</li>
             <li>2</li>
           </ul>
    );
}

I would like to create high-order ponent which modifies, for example, styles of all li node.

function makeRed(ponent) {
    return function(props) {
         const element = React.createElement(ponent, props);

         return React.cloneElement(
            element,
            element.props,
            React.Children.map(
                element.props.children,
                ch => React.cloneElement(ch, { 
                        ...ch.props, 
                        style: {
                           backgroundColor: "red"
                        }
                    },                    
                    ch.props.children
                )
            )
        );
    }
}

But. This doesn't work. Children are empty.

Interesting that this works if I create ponent directly, like

...    
const element = <ul><li>1</li><li>2</li></ul>;
...

Question: how to access a children and grandchildren of any React element?

Imagine having React ponent

function List() {
   return (<ul>
             <li>1</li>
             <li>2</li>
           </ul>
    );
}

I would like to create high-order ponent which modifies, for example, styles of all li node.

function makeRed(ponent) {
    return function(props) {
         const element = React.createElement(ponent, props);

         return React.cloneElement(
            element,
            element.props,
            React.Children.map(
                element.props.children,
                ch => React.cloneElement(ch, { 
                        ...ch.props, 
                        style: {
                           backgroundColor: "red"
                        }
                    },                    
                    ch.props.children
                )
            )
        );
    }
}

But. This doesn't work. Children are empty.

Interesting that this works if I create ponent directly, like

...    
const element = <ul><li>1</li><li>2</li></ul>;
...

Question: how to access a children and grandchildren of any React element?

Share Improve this question asked Aug 9, 2018 at 22:23 STOSTO 10.7k8 gold badges33 silver badges32 bronze badges 4
  • 9 This very much seems like an anti-pattern in React. Why not instead create a List ponent that can accept styles as a prop, and a higher-order ponent that passes said prop to them? – Hamms Commented Aug 9, 2018 at 22:28
  • 2 can you give a more practical example of what you want to do? your example is much more easily achieved with plain old css – azium Commented Aug 9, 2018 at 22:46
  • I need this to add "sortable (draggable)" behavior to any element with children with HOC. I know this is not a pure react way for normal ponents but that's just the simplest example illustrates problem. – STO Commented Aug 10, 2018 at 8:22
  • @STO this can be done as Hamms already said. – Jordan Enev Commented Aug 27, 2018 at 8:10
Add a ment  | 

1 Answer 1

Reset to default 4 +200

This is an anti-pattern, as @hamms has pointed out. There are better ways to implement themes in React using plain old CSS.

Said that, here's a hack to a working example of your use case - https://codesandbox.io/s/ymqwyww22z.

Basically, here's what I have done:

  1. Make List a class based ponent. It's not too much trouble to wrap a functional ponent into one.

    import React, { Component } from "react";
    
    export default class List extends Component {
      render() {
        return (
          <ul>
            <li>1</li>
            <li>2</li>
          </ul>
        );
      }
    }
    
  2. Implement render in the dynamic class Red<Component> to first fetch the element-tree returned from the base Component's render and then edit it.

    import React from "react";
    
    export default function makeRed(Component) {
      return class RedComponent extends Component {
        constructor(props) {
          super(props);
    
          RedComponent.displayName = `Red${Component.name}`;
        }
    
        render() {
          let ponentElement = super.render();
          let { children, ...rest } = ponentElement.props;
          children = React.Children.map(children, child => {
            return React.cloneElement(child, {
              ...child.props,
              style: {
                backgroundColor: "red"
              }
            });
          });
          return React.cloneElement(ponentElement, rest, ...children);
        }
      };
    }
    

How's this different from the createElement version of makeRed?

As makeRed returns a HOC, when you use it in your App ponent, you don't assign props to it. Something like this...

function App() {
  return <RedList />; // no props!
}

So inside the dynamic ponent function, where you use createElement to create a new instance, ponent.props don't carry any children. Since List creates its own children, you need to grab those and modify them, instead of reading children from props.

发布评论

评论列表(0)

  1. 暂无评论