[英]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
的三元操作运行不正常,我不知道为什么......
childrenHandler
passing its children.如果它有孩子,克隆这个元素并调用childrenHandler
传递它的孩子。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
有孩子, array
或object
,并且如果在传递的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;
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.