如何将道具递归注入树中的每个React组件?

Dis*_*les 6 javascript reactjs

所以,我已经使用emotion-js了一段时间了,我喜欢它!但是我真的很讨厌e2e测试。所有选择器看起来都像这样:div > div > div > p,因为emotion注入的类名是随机生成的字符串。因此,我想到了将data-属性注入DisplayName每个元素,以便能够以更简洁的方式测试它们:[data-test-id*="DateButton"]或类似的东西。所以我写了这个简单的包装器:https : //gist.github.com/sergeyvlakh/3072a4e2e27456bda853a1e1a213a568

我这样使用它:

import Injector from './injector';

export default props => 
    (
        <Injector>
            <MyReactTree />
        </Injector>
    )
Run Code Online (Sandbox Code Playgroud)

这里的问题是我不是“动态”注入数据属性。我想像使用以下任何HoC一样使用它recomposeexport default Injector(App)

甚至使用动态道具名称,例如:export default Injector('data-test-id')(App)。但是... Injector在这种情况下...的孩子将是不确定的,所以我不知道如何进行:)

更新: 感谢remix23我这样做是这样的:https : //gist.github.com/sergeyvlakh/f99310cdef018c06451333a36e764372

但是,我强烈建议使用他的代码。

rem*_*x23 2

您可以使用以下方法将 props 注入到任何 React 元素中React.cloneElement(element, newPropsToMerge, newChildren)

您可以通过访问每个元素children 等来递归地深入跟踪children。

也许成本更高,但更直接,这也应该有效:


    function Injector(Target) {
         class InjectedTarget extends Component {
              render() {
                  const { chilren, ...rest } = this.props;
                  return (
                      <Target
                          data-test-id={Target.DisplayName}
                          {...rest}
                      >
                          {React.Children.map(children, (child) => {
                              const isComponent = 
                                  child &&
                                  child.type &&
                                  typeof child.type !== 'string' && 
                                  Object.prototype.isPrototypeOf.apply(
                                      React.Component.prototype,
                                      [child.type.prototype]
                                  );
                              if (!isComponent) {
                                  return child;
                              }
                              return React.createElement(Injector(child.type), { ...child.props, 'data-test-id': Target.DisplayName });
                          })}
                      </Target>
                  );
              }
         }
         return InjectedTarget;
    }
Run Code Online (Sandbox Code Playgroud)

我认为这在性能方面会非常糟糕,但这是为了测试,对吗?