简体   繁体   English

将道具传递给 React 中的特定嵌套子项

[英]Passing props to specific nested children in React

I am trying to configure some props to children.我正在尝试为孩子们配置一些道具。

In this dummy example I am testing the function in order to specifically target any child, nested or not, with the following prop: swipeMe .在这个虚拟示例中,我正在测试 function,以便使用以下道具专门针对任何孩子,无论是否嵌套: swipeMe

It works very well if inside my div on the render function if it contains just a single child, like this:如果在render function上的我的div中,如果它只包含一个孩子,它会很好地工作,如下所示:

    <SwapableItems>
      <div>
        {/*the p element will get the red color as defined on childrenHandler*/}
        <p swipeMe>Add Props</p> 
      </div>
    </SwapableItems>

Yet, if I add more children into my div , somehow I guess that my ternary operation on childrenHandler is not working well and I do not know why...然而,如果我在我的div中添加更多的孩子,不知何故我猜我对childrenHandler的三元操作运行不正常,我不知道为什么......

  • If it has children, clone this element and call childrenHandler passing its children.如果它有孩子,克隆这个元素并调用childrenHandler传递它的孩子。
  • If it has my desired prop, clone de element and do something with it.如果它有我想要的道具,克隆元素并用它做点什么。
  • If none of the above, just clone the element.如果以上都不是,只需克隆该元素。
return childHasChildren
      ? React.cloneElement(child, {}, childHasChildren)
      : child.props.swipeMe
      ? React.cloneElement(child, { ...swipeMeProps })
      : React.cloneElement(child, {});

Below is the full script.下面是完整的脚本。 You can also check it out on Codesandbox您也可以在Codesandbox上查看

import React from "react";
import ReactDOM from "react-dom";

function App() {
  return (
    <SwapableItems>
      <div>
        <p swipeMe>Add Props</p>
        <div>Don't Add Props</div>
      </div>
    </SwapableItems>
  );
}

function SwapableItems({ children }) {
  const content = childrenHandler(children, { style: { color: "red" } });
  return content;
}

const childrenHandler = (children, swipeMeProps) => {
  const childEls = React.Children.toArray(children).map((child) => {
    const childHasChildren =
      child.props.children && React.isValidElement(child.props.children)
        ? childrenHandler(child.props.children, swipeMeProps)
        : undefined;
    return childHasChildren
      ? React.cloneElement(child, {}, childHasChildren)
      : child.props.swipeMe
      ? React.cloneElement(child, { ...swipeMeProps })
      : React.cloneElement(child, {});
  });
  return childEls;
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

I tested this work.我测试了这项工作。 I wrapped nested children by SwapableItems if has children.如果有孩子,我用 SwapableItems 包裹嵌套的孩子。

function SwapableItems({ children }) {
  const props = { style: { color: "red" } };
  return Children.map(children, (child) => {
    let nestedChild = child.props.children;
    const hasNestedChild = nestedChild && typeof nestedChild !== "string"

    if (hasNestedChild) {
      nestedChild = <SwapableItems>{nestedChild}</SwapableItems>;
    }

    return child.props?.swipeMe || hasNestedChild
      ? cloneElement(child, child.props?.swipeMe ? props : {}, [nestedChild])
      : child;
  });
}

https://codesandbox.io/s/kind-snow-8zm6u?file=/src/App.js:345-751 https://codesandbox.io/s/kind-snow-8zm6u?file=/src/App.js:345-751

child.props.children is an array, so React.isValidElement(child.props.children) is always falsy, to fix it try using React.cloneElement on it: child.props.children是一个数组,所以React.isValidElement(child.props.children)总是假的,要修复它,请尝试在其上使用React.cloneElement

React.isValidElement(React.cloneElement(child.props.children)); // true

A style reset example:样式重置示例:

const styleA = {
  color: "blue"
};

const InlineReset = ({ children }) => {
  return React.Children.map(children, child => {
    console.log(child.props);

    return React.cloneElement(child.props.children, { style: null });
  });
};

export default function App() {
  return (
    <InlineReset>
      <div>
        <h1 style={styleA}>Hello </h1>
      </div>
    </InlineReset>
  );
}

编辑子项

This is the solution:这是解决方案:

I have initialized a variable which will hold the recursion outside of the logic and undefined.我已经初始化了一个variable ,它将在逻辑之外保持recursion并且未定义。

let childHasChildren;

I have encapsulated the code inside an if statement with some adaptions: "in case child has children, either an array or object , and if within the passed children there is/are valid React elements"我已经将代码封装在一个if语句中并进行了一些调整:“如果child有孩子, arrayobject ,并且如果在传递的children中有/是有效的React元素”

const deeperChildren = child.props.children;
    const arrayOfChildren = Array.isArray(deeperChildren);
    const singleChildren =
      typeof deeperChildren === "object" && deeperChildren !== null;
    if (
      (arrayOfChildren &&
        deeperChildren.some((c) => React.isValidElement(c))) ||
      (singleChildren && React.isValidElement(deeperChildren))
    ) {

In order to pass the recursion without errors, in case the code within the if statement is called, I have cloned a filter/single object of which children would be React valid elements, then I pass just these/this into the recursion:为了不出错地传递递归,以防调用if语句中的代码,我克隆了一个过滤器/单个 object,其中的子项将是 React 有效元素,然后我只将这些/这个传递到递归中:

const validChildren = arrayOfChildren
        ? deeperChildren.filter((c) => React.isValidElement(c))
        : deeperChildren;

Here is the result这是结果

Now it accepts, one item with children, or an Array.现在它接受一个有孩子的项目,或者一个数组。 This can be configured in order to dynamically pass props, with default ones and other props that could be passed from outside of the component, although the latter is not my case.这可以配置为动态传递道具,默认道具和其他可以从组件外部传递的道具,尽管后者不是我的情况。 This solution was desired in order to achieve more complex stuff without using those solutions, such as render props , props contracts, HOCs, etc.为了在不使用这些解决方案的情况下实现更复杂的东西,例如渲染props 、道具合同、HOC 等,需要此解决方案。

const childrenHandler = (children, swipeMeProps) => {
  const childEls = React.Children.toArray(children).map((child) => {
    let childHasChildren;
    const deeperChildren = child.props.children;
    const arrayOfChildren = Array.isArray(deeperChildren);
    const singleChildren =
      typeof deeperChildren === "object" && deeperChildren !== null;
    if (
      (arrayOfChildren &&
        deeperChildren.some((c) => React.isValidElement(c))) ||
      (singleChildren && React.isValidElement(deeperChildren))
    ) {
      const validChildren = arrayOfChildren
        ? deeperChildren.filter((c) => React.isValidElement(c))
        : deeperChildren;

      childHasChildren = childrenHandler(validChildren, swipeMeProps);
    }

    return childHasChildren
      ? React.cloneElement(child, {}, childHasChildren)
      : child.props.swipeMe
      ? React.cloneElement(child, { ...swipeMeProps })
      : React.cloneElement(child, {});
  });
  return childEls;
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM