5

想象一下有 React 组件

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

li我想创建修改所有节点样式的高阶组件。

function makeRed(component) {
    return function(props) {
         const element = React.createElement(component, 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
                )
            )
        );
    }
}

但。这行不通。孩子们是空的。

有趣的是,如果我直接创建组件,这会起作用,比如

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

问题:如何访问任何 React 元素的子孙?

4

1 回答 1

2

正如@hamms 所指出的,这是一种反模式。使用普通的旧 CSS在 React 中实现主题有更好的方法。

就是说,这是对您的用例的一个工作示例的破解 - https://codesandbox.io/s/ymqwyww22z

基本上,这就是我所做的:

  1. 制作List一个基于类的组件。将一个功能组件封装成一个组件并没有太大的麻烦。

    import React, { Component } from "react";
    
    export default class List extends Component {
      render() {
        return (
          <ul>
            <li>1</li>
            <li>2</li>
          </ul>
        );
      }
    }
    
  2. render在动态类中实现Red<Component>以首先获取从基本组件的渲染返回的元素树,然后对其进行编辑。

    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 componentElement = super.render();
          let { children, ...rest } = componentElement.props;
          children = React.Children.map(children, child => {
            return React.cloneElement(child, {
              ...child.props,
              style: {
                backgroundColor: "red"
              }
            });
          });
          return React.cloneElement(componentElement, rest, ...children);
        }
      };
    }
    

createElement这和版本有什么区别makeRed

作为makeRed返回一个 HOC,当您在App组件中使用它时,您不会为它分配道具。像这样的东西...

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

createElement因此,在用于创建新实例的动态组件函数内部,component.props不要携带任何子项。由于List创建了自己的孩子,您需要获取并修改它们,而不是从props.

于 2018-08-27T08:43:14.353 回答