如何将prop只传递给未知元素的React元素数组中的第一个元素?例如,在以下代码段中,elements
是最多3个自定义的Bar
元素的数组,我只希望第一个传递给任意道具。
function Foo(props) {
const myProp = 'test';
const elements = [
(isP && <Bar prop1={'p'} />),
(isQ && <Bar prop1={'q'} />),
(isR && <Bar prop1={'r'} />),
].filter(x => x);
// Now do something like 'elements[0].props.myProp = myProp'
return elements;
}
为此,我想在侧边栏中显示三个面板。第一个应显示其标题和正文,其他应仅显示其标题。
我考虑过但不喜欢的一些解决方案:
1)使用React的cloneElement
方法克隆第一个元素并将其传递给prop。 1但是克隆一个React元素只是为了设置一个道具似乎很糟糕。
2)对布尔逻辑进行预处理,以确定首先是哪个元素,然后分配道具。例如,类似下面的代码,但逻辑更聪明:
function Foo(props) {
const myProp = 'test';
const elements = [
(isP && <Bar myProp={isP && myProp}/>),
(isQ && <Bar myProp={!isP && isQ && myProp} />),
(isR && <Bar myProp={!isP && !isQ && isR && myProp} />),
].filter(x => x);
return elements;
}
理想情况下,该解决方案将有效,简洁地实现目标。如果没有比(1)或(2)更好的解决方案,我也将其作为答案。
编辑:我忘了澄清一些观点。
<Bar />
的实例实际上是多种类型(例如Bar
,Bas
,Baz
),以免对答案产生重大影响。 (我错误地简化了原始问题。)答案 0 :(得分:2)
我想我会保持简单并使用push
:
function Foo(props) {
const myProp = 'test';
const elements = [];
if (isP) {
elements.push(<Bar myProp={myProp}/>);
}
if (isQ) {
elements.push(elements.length ? <Bar/> : <Bar myProp={myProp}/>);
}
if (isR) {
elements.push(elements.length ? <Bar/> : <Bar myProp={myProp}/>);
}
return elements;
}
如果myProp
可以伪造,则后两个变得更简单:
// ...
if (isQ) {
elements.push(<Bar myProp={elements.length || myProp}/>);
}
// ...
如果不正确,但undefined
是:
// ...
if (isQ) {
elements.push(<Bar myProp={elements.length ? undefined : myProp}/>);
}
// ...
当然不是特别漂亮。 :-)或循环:
function Foo(props) {
const myProp = 'test';
const elements = [];
for (const flag of [isP, isQ, isR]) {
if (flag) {
elements.push(elements.length ? <Bar/> : <Bar myProp={myProp}/>);
}
}
return elements;
}
(再次根据myProp
的规则避免使用条件运算符。)
如果您需要在问题的第一个代码块中使用prop1
,'p'
或'q'
的{{1}},而不是第二个代码块,则只需使用遍历对象数组:
'r'
(再次根据function Foo(props) {
const myProp = 'test';
const elements = [];
const specs = [
[isP, 'p'],
[isQ, 'q'],
[isR, 'r']
];
for (const [flag, prop1] of specs) {
if (flag) {
elements.push(elements.length ? <Bar prop1={prop1}/> : <Bar prop1={prop1} myProp={myProp}/>);
}
}
return elements;
}
的规则避免使用条件运算符。)
等等。
答案 1 :(得分:1)
我忍不住认为这是XY Problem。如果您向我们展示实际代码,我们可能会更有效地帮助您。
无论如何,如果我们在黑暗中刺伤,这是使用销毁分配的另一种方法。如果isP
和isQ
和isR
均为假,将返回一个空数组。
const Foo = (props) =>
{ const specs =
[ [ isP, 'p' ]
, [ isQ, 'q' ]
, [ isR, 'r' ]
]
const [ first, ...rest ] =
specs.reduce
( (acc, [ flag, prop ]) =>
flag ? [ ...acc, prop ] : acc
, []
)
if (first === undefined)
return []
return (
[ <Bar myProp={myProp} prop={first} />
, ...rest.map (prop => <Bar prop={prop} />)
]
)
}
您说过,每种条件下的组件和道具可能都不同。在这种情况下,您可以修改程序以满足您的独特需求-
const Foo = (props) =>
{ const specs =
[ [ isP, Bar, { prop: 'r' } ]
, [ isQ, Qux, { prop: 'q', another: 'a' } ]
, [ isR, Rox, { prop: 'r' } ]
]
return specs
.filter
( ([ flag, _0, _1 ]) => flag
)
.map
( ([ _, Comp, props ], i) =>
i === 0
? <Comp {...props} myProp={myProp} />
: <Comp {...props} />
)
}
答案 2 :(得分:0)
如正在使用redux
所示,理想情况下,应通过调用reducer中的一个函数来预计算源数据,以使数组的长度正确,并在需要时设置props
。这将意味着在组件内部进行不必要的计算,而在任何组件更新时都必须进行渲染。
myArr: [
{ id: 0, someProp: { msg: 'hello' } },
{ id: 1: someProp: {} },
{ id: 2: someProp: {} }
]
或
myArr: [
{ id: 1, someProp: { msg: 'hello' } },
{ id: 2: someProp: {} }
]
然后该组件只需要做
const Foo = (props) => {
const { myArr } = props;
return (
<div>
{
myArr.map(item => (
<Bar key={item.id} {...item.someProp} />
))
}
</div>
);
};
编辑:如果需要不同的类型,则可以在公共lib文件中使用以下内容。
export const COMPONENT_TYPE = {
BAR: 'BAR',
BAS: 'BAS',
BAZ: 'BAZ'
};
现在
import { COMPONENT_TYPE: { BAR, BAS, BAZ } } from '../common';
myArr: [
{ id: 0, someProp: { msg: 'hello' }, componentType: BAR },
{ id: 1: someProp: {}, componentType: BAS },
{ id: 2: someProp: {}, componentType: BAZ }
]
现在在我们的组件中
import { COMPONENT_TYPE: { BAR, BAS, BAZ } } from '../common';
const Foo = (props) => {
const { myArr } = props;
return (
<div>
{
myArr.map(item => (
<div key={item.id}>
{
item.componentType === BAR &&
<Bar {...item.someProp} />
}
{
item.componentType === BAS &&
<Bas {...item.someProp} />
}
{
item.componentType === BAZ &&
<Baz {...item.someProp} />
}
</div>
))
}
</div>
);
};
3个独立的条件语句执行的功能与if / else if / else几乎完全相同,并且更加清晰。如果您的代码中的BAR/BAS/BAZ
如此相似,则只需
const Component = item.componentType;
<Component {...item.someProp} />
只要将枚举从大写字母更改为实际的组件名称,就在map
内