ChatGPT解决这个技术问题 Extra ChatGPT

如何将道具传递给 {this.props.children}

我试图找到正确的方法来定义一些可以以通用方式使用的组件:

<Parent>
  <Child value="1">
  <Child value="2">
</Parent>

当然,在父组件和子组件之间进行渲染是有逻辑的,您可以将 <select><option> 想象为这种逻辑的示例。

出于问题的目的,这是一个虚拟实现:

var Parent = React.createClass({
  doSomething: function(value) {
  },
  render: function() {
    return (<div>{this.props.children}</div>);
  }
});

var Child = React.createClass({
  onClick: function() {
    this.props.doSomething(this.props.value); // doSomething is undefined
  },
  render: function() {
    return (<div onClick={this.onClick}></div>);
  }
});

问题是每当您使用 {this.props.children} 定义包装组件时,您如何将某些属性传递给它的所有子组件?

我从这个问题的答案中学到了很多东西。我认为 Context API 是当今 React 领域的最佳解决方案。但是如果你想使用 React.cloneElement,我遇到的一个问题是没有正确地用 React.Children.map() 迭代孩子。在 How To Pass Props to {react.children} 中查看更多信息

D
Dominic

用新道具克隆孩子

您可以使用 React.Children 来迭代子元素,然后使用 React.cloneElement 克隆每个带有新道具(浅合并)的元素。例如:

const Child = ({ doSomething, value }) => ( ); function Parent({ children }) { function doSomething(value) { console.log("doSomething 由 child 调用,具有 value:", value); } const childrenWithProps = React.Children.map(children, child => { // 检查 isValidElement 是安全的方法,并且也避免了打字稿 // 错误。 if (React.isValidElement(child)) { return React.cloneElement(child, { doSomething }); } 返回孩子; }); return

{childrenWithProps}
} function App() { return ( ); } ReactDOM.render(, document.getElementById("container"));

将孩子作为函数调用

或者,您可以使用 render props 将道具传递给孩子。在这种方法中,孩子(可以是 children 或任何其他道具名称)是一个可以接受您想要传递的任何参数并返回孩子的函数:

const Child = ({ doSomething, value }) => ( ); function Parent({ children }) { function doSomething(value) { console.log("doSomething 由 child 调用,具有 value:", value); } // 请注意,children 作为函数调用,我们可以将 args 传递给它。 return

{children(doSomething)}
} function App() { // doSomething 是我们在 Parent 中传递的参数, // 我们现在将其传递给 Child。 return ( {doSomething => ( ) } ); } ReactDOM.render(, document.getElementById("container"));

如果您愿意,您也可以返回一个数组,而不是 <React.Fragment> 或简单的 <>


这对我不起作用。这没有在 React.cloneElement() 中定义
这个答案不起作用,传递给 doSomethingvalue 丢失了。
@DominicTobias Arg,抱歉,我将 console.log 切换为 alert 并忘记将两个参数连接到单个字符串。
这个答案非常有帮助,但我遇到了一个这里没有提到的问题,我想知道它是否是一些改变的新事物,或者它是否对我来说很奇怪。当我克隆我的子元素时,它的子元素被设置为旧元素,直到我将 this.props.children.props.children 添加到 cloneElement 的第三个参数。
如果孩子是通过从单独的路由页面加载的路由(v4)加载的怎么办?
m
mysl

要获得更清洁的方法,请尝试:

<div>
    {React.cloneElement(this.props.children, { loggedIn: this.state.loggedIn })}
</div>

编辑:要与多个单独的孩子一起使用(孩子本身必须是一个组件),您可以这样做。在 16.8.6 中测试

<div>
    {React.cloneElement(this.props.children[0], { loggedIn: true, testPropB: true })}
    {React.cloneElement(this.props.children[1], { loggedIn: true, testPropA: false })}
</div>

我使用的是评分最高的答案,但这个答案更直接!这个解决方案也是他们在 react-router 示例页面上使用的。
有人可以解释这是如何工作的(或它实际上是做什么的)吗?阅读 the docs,我看不出这将如何影响孩子并将该道具添加到每个孩子 - 这是它的意图吗?如果是这样,我们怎么知道它会做什么?将不透明的数据结构 (this.props.children) 传递给 cloneElement ... 这一点也不明显,这需要一个 ... 元素。
确切地说,这似乎不适用于一个以上的孩子。
因此,您可以编写代码,当某人只将一个子元素传递给组件时,但当他们添加另一个子元素时,它会崩溃……这听起来不太好?对于 OP 来说,这似乎是一个陷阱,他们专门询问是否将道具传递给所有孩子。
@GreenAsJade 只要您的组件期待一个孩子就可以了。您可以通过您的组件 propTypes 定义它需要一个孩子。 React.Children.only 函数返回唯一的孩子,如果有多个则抛出异常(如果没有用例,则不会存在)。
M
Michael Freidgeim

尝试这个

<div>{React.cloneElement(this.props.children, {...this.props})}</div>

使用 react-15.1 对我有用。

https://reactjs.org/docs/jsx-in-depth.html#spread-attributes 中建议使用 {...this.props}


是否可以直接返回 React.cloneElement() 而无需将其括在 <div> 标记中?因为如果孩子是 <span>(或其他)并且我们想要保留其标签元素类型怎么办?
如果是一个孩子,你可以省略包装,这个解决方案只适用于一个孩子,所以是的。
为我工作。不包含
是可以的。
如果您需要明确强制您只接收一个孩子,您可以执行 React.cloneElement(React.Children.only(this.props.children), {...this.props}),如果传递多个孩子,则会引发错误。然后你不需要包装在一个div中。
这个答案可能会产生一个 TypeError: cyclic object value。除非您希望孩子的道具之一是它自己,否则请使用 let {children, ...acyclicalProps} = this.props,然后使用 React.cloneElement(React.Children.only(children), acyclicalProps)
M
Mike

将道具传递给指导孩子。

查看所有其他答案

通过上下文通过组件树传递共享的全局数据

Context 旨在共享可被视为 React 组件树“全局”的数据,例如当前经过身份验证的用户、主题或首选语言。 1

免责声明:这是一个更新的答案,上一个使用旧的上下文 API

它基于消费者/提供原则。首先,创建你的上下文

const { Provider, Consumer } = React.createContext(defaultValue);

然后通过

<Provider value={/* some value */}>
  {children} /* potential consumers */
</Provider>

<Consumer>
  {value => /* render something based on the context value */}
</Consumer>

每当 Provider 的 value 属性发生变化时,所有作为 Provider 后代的 Consumer 都会重新渲染。从 Provider 到其后代 Consumer 的传播不受 shouldComponentUpdate 方法的约束,因此即使祖先组件退出更新,Consumer 也会更新。 1

完整示例,半伪代码。

import React from 'react';

const { Provider, Consumer } = React.createContext({ color: 'white' });

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: { color: 'black' },
    };
  }

  render() {
    return (
      <Provider value={this.state.value}>
        <Toolbar />
      </Provider>
    );
  }
}

class Toolbar extends React.Component {
  render() {
    return ( 
      <div>
        <p> Consumer can be arbitrary levels deep </p>
        <Consumer> 
          {value => <p> The toolbar will be in color {value.color} </p>}
        </Consumer>
      </div>
    );
  }
}

1 https://facebook.github.io/react/docs/context.html


与接受的答案不同,即使父项下包含其他元素,这也可以正常工作。这绝对是最好的答案。
道具!=上下文
您不能依赖通过上下文传播的更改。在可能发生变化时使用道具。
也许我不明白,但说“上下文使道具可用”不是错的吗?当我上次使用上下文时,它是一个单独的东西(即 this.context)——它并没有神奇地将上下文与道具合并。你必须有意识地设置和使用上下文,这是另一回事。
你完全理解,这是不正确的。我已经编辑了我的答案。
K
Kenneth Truong

将道具传递给嵌套的孩子

随着对 React Hooks 的更新,您现在可以使用 React.createContext 和 useContext。

import * as React from 'react';

// React.createContext accepts a defaultValue as the first param
const MyContext = React.createContext(); 

functional Parent(props) {
  const doSomething = (value) => {
    // Do something here with value
  };

  return (
     <MyContext.Provider value={{ doSomething }}>
       {this.props.children}
     </MyContext.Provider>
  );
}
 
function Child(props: { value: number }) {
  const myContext = React.useContext(MyContext);

  const onClick = () => {
    myContext.doSomething(props.value);
  }

  return (
    <div onClick={onClick}>{this.props.value}</div>
  );
}

// Example of using Parent and Child

import * as React from 'react';

function SomeComponent() {
  return (
    <Parent>
      <Child value={1} />
      <Child value={2} />
    </Parent>
  );
}

React.createContext 在 React.cloneElement 案例无法处理嵌套组件的情况下大放异彩

function SomeComponent() {
  return (
    <Parent>
      <Child value={1} />
      <SomeOtherComp>
        <Child value={2} />
      </SomeOtherComp>
    </Parent>
  );
}

你能解释一下为什么=>函数是一种不好的做法? =>函数有助于绑定事件处理程序以获取 this 上下文
@KennethTruong 因为每次渲染它都会创建一个函数。
@itdoesntwork 这不是真的。它仅在创建类时创建一个新函数。它不是在渲染功能期间创建的..
@KennethTruong reactjs.org/docs/faq-functions.html#arrow-function-in-render 我以为您在谈论渲染中的箭头功能。
我会在您的代码中删除 value=myContext。原因:1)不需要解释上下文。 2)它分散了代码的实际关键点,即myContext的使用。 :)
N
Nick Ovchinnikov

允许您进行属性转移的最佳方法是 children,如函数模式 https://medium.com/merrickchristensen/function-as-child-components-5f3920a9ace9

代码段:https://stackblitz.com/edit/react-fcmubc

例子:

const Parent = ({ children }) => {
    const somePropsHere = {
      style: {
        color: "red"
      }
      // any other props here...
    }
    return children(somePropsHere)
}

const ChildComponent = props => <h1 {...props}>Hello world!</h1>

const App = () => {
  return (
    <Parent>
      {props => (
        <ChildComponent {...props}>
          Bla-bla-bla
        </ChildComponent>
      )}
    </Parent>
  )
}


对我来说,这似乎比公认的答案更直接(并且性能更好?)。
这要求 children 是一个函数,并且不适用于 deply 嵌套组件
@digitalillusion,我不明白 nested components 是什么意思。 React 没有嵌套模式,只有组合。是的,children 必须是一个函数,没有任何冲突,因为这是有效的 JSX 孩子。你能举个 nesting components 的例子吗?
你是对的,深度嵌套的孩子的情况也可以处理<Parent>{props => <Nest><ChildComponent /></Nest>}</Parent>而不是(不工作)<Parent><Nest>{props => <ChildComponent />}</Nest></Parent>所以我同意这是最好的答案
尝试时,我收到以下信息:TypeError: children is not a function
A
Alireza

您可以使用 React.cloneElement,最好在开始在应用程序中使用它之前了解它的工作原理。它在 React v0.13 中进行了介绍,请继续阅读以了解更多信息,因此与此相关的内容对您有用:

<div>{React.cloneElement(this.props.children, {...this.props})}</div>

因此,请使用 React 文档中的内容来了解它是如何工作的以及如何使用它们:

在 React v0.13 RC2 中,我们将引入一个新的 API,类似于 React.addons.cloneWithProps,具有以下签名:

React.cloneElement(element, props, ...children);

与 cloneWithProps 不同,这个新函数没有任何用于合并 style 和 className 的神奇内置行为,原因与我们在 transferPropsTo 中没有该功能的原因相同。没有人确切知道魔法事物的完整列表是什么,这使得当样式具有不同的签名时(例如在即将到来的 React Native 中)难以推理代码并且难以重用。 React.cloneElement 几乎等同于:

<element.type {...element.props} {...props}>{children}</element.type>

但是,与 JSX 和 cloneWithProps 不同的是,它还保留了 refs。这意味着如果你得到一个带有 ref 的孩子,你不会不小心从你的祖先那里偷走它。您将获得附加到新元素的相同 ref。一种常见的模式是映射你的孩子并添加一个新的道具。有很多关于 cloneWithProps 丢失 ref 的问题报告,这使得你的代码更难推理。现在遵循与 cloneElement 相同的模式将按预期工作。例如:

var newChildren = React.Children.map(this.props.children, function(child) {
  return React.cloneElement(child, { foo: true })
});

注意:React.cloneElement(child, { ref: 'newRef' }) 确实会覆盖 ref,因此两个父级仍然不可能拥有同一个子级的 ref,除非您使用回调引用。这是进入 React 0.13 的一个关键特性,因为 props 现在是不可变的。升级路径通常是克隆元素,但这样做可能会丢失 ref。因此,我们需要一个更好的升级路径。当我们在 Facebook 升级调用站点时,我们意识到我们需要这种方法。我们从社区得到了同样的反馈。因此,我们决定在最终版本之前制作另一个 RC 以确保我们能够将其纳入。我们计划最终弃用 React.addons.cloneWithProps。我们还没有这样做,但这是开始考虑自己的用途并考虑改用 React.cloneElement 的好机会。在我们实际删除它之前,我们一定会发布带有弃用通知的版本,因此无需立即采取行动。

更多here...


o
olenak

我需要修复上面接受的答案,以使其使用它而不是这个指针来工作。这在 map 函数的范围内没有定义 doSomething 函数。

var Parent = React.createClass({
doSomething: function() {
    console.log('doSomething!');
},

render: function() {
    var that = this;
    var childrenWithProps = React.Children.map(this.props.children, function(child) {
        return React.cloneElement(child, { doSomething: that.doSomething });
    });

    return <div>{childrenWithProps}</div>
}})

更新:此修复适用于 ECMAScript 5,在 ES6 中不需要 var that=this


或只使用 bind()
或使用绑定到词法范围的箭头函数,我更新了我的答案
如果 doSomething 获取一个对象,例如 doSomething: function(obj) { console.log(obj) },并且在 Child 中调用 this.props.doSomething(obj) 以注销 "obj",会怎样?
@plus- 我知道这很旧,但是在这里使用 bind 是一个糟糕的主意, bind 创建了一个新函数,将上下文绑定到一个新函数。基本上是一个调用 apply 方法的函数。在渲染函数中使用 bind() 将在每次调用渲染方法时创建一个新函数。
p
poynting

没有一个答案解决了拥有不是 React 组件的子项的问题,例如文本字符串。解决方法可能是这样的:

// Render method of Parent component
render(){
    let props = {
        setAlert : () => {alert("It works")}
    };
    let childrenWithProps = React.Children.map( this.props.children, function(child) {
        if (React.isValidElement(child)){
            return React.cloneElement(child, props);
        }
          return child;
      });
    return <div>{childrenWithProps}</div>

}

p
pkoch

考虑一个或多个孩子的更清洁的方式

<div>
   { React.Children.map(this.props.children, child => React.cloneElement(child, {...this.props}))}
</div>

这个对我不起作用,它给出了一个错误:孩子没有定义。
@Deelux this.props.children 而不是孩子
这会将孩子作为其自己的孩子在 this.props 中传递。一般来说,我只建议使用特定道具进行克隆,而不是整个 shebang。
通过 {...this.props} 对我不起作用,{...child.props} 的方式是否正确?
对于功能组件:React.Children.map(children, child => React.cloneElement(child, props))
B
Ben Carp

方法 1 - 克隆孩子

const Parent = (props) => {
   const attributeToAddOrReplace= "Some Value"
   const childrenWithAdjustedProps = React.Children.map(props.children, child =>
      React.cloneElement(child, { attributeToAddOrReplace})
   );

   return <div>{childrenWithAdjustedProps }</div>
}

Full Demo

方法 2 - 使用可组合上下文

Context 允许您将 prop 传递给深层子组件,而无需将其作为 prop 显式传递给它们之间的组件。

上下文有缺点:

数据不会以常规方式流动——通过道具。使用上下文创建消费者和提供者之间的合同。理解和复制重用组件所需的需求可能会更加困难。

使用可组合的上下文

export const Context = createContext<any>(null);

export const ComposableContext = ({ children, ...otherProps }:{children:ReactNode, [x:string]:any}) => {
    const context = useContext(Context)
    return(
      <Context.Provider {...context} value={{...context, ...otherProps}}>{children}</Context.Provider>
    );
}

function App() {
  return (
      <Provider1>
            <Provider2> 
                <Displayer />
            </Provider2>
      </Provider1>
  );
}

const Provider1 =({children}:{children:ReactNode}) => (
    <ComposableContext greeting="Hello">{children}</ComposableContext>
)

const Provider2 =({children}:{children:ReactNode}) => (
    <ComposableContext name="world">{children}</ComposableContext>
)

const Displayer = () => {
  const context = useContext(Context);
  return <div>{context.greeting}, {context.name}</div>;
};


有点晚了,但您能解释一下 {children}:{children:ReactNode} 中的符号吗?
@camille,这是一个打字稿。现在看,我只会用 Javascript 来回答,即使我会写 Typescript,我也会用不同的方式来做。将来可能会编辑它。
@camille,基本上这意味着具有键 "children" 的值是 ReactNode 类型
@Ben Carp 通过使用方法 1 我如何将 attributeToAddOrReplace 访问到子文件中?
嗨@SamikshaJagtap,我添加了一个演示以更清楚地展示它是如何完成的。希望这可以帮助! stackblitz.com/edit/react-te35fc?file=src/App.js
M
Maksim Kostromin

父.jsx:

import React from 'react';

const doSomething = value => {};

const Parent = props => (
  <div>
    {
      !props || !props.children 
        ? <div>Loading... (required at least one child)</div>
        : !props.children.length 
            ? <props.children.type {...props.children.props} doSomething={doSomething} {...props}>{props.children}</props.children.type>
            : props.children.map((child, key) => 
              React.cloneElement(child, {...props, key, doSomething}))
    }
  </div>
);

Child.jsx:

import React from 'react';

/* but better import doSomething right here,
   or use some flux store (for example redux library) */
export default ({ doSomething, value }) => (
  <div onClick={() => doSomething(value)}/>
);

和 main.jsx:

import React from 'react';
import { render } from 'react-dom';
import Parent from './Parent';
import Child from './Child';

render(
  <Parent>
    <Child/>
    <Child value='1'/>
    <Child value='2'/>
  </Parent>,
  document.getElementById('...')
);

请参阅此处的示例:https://plnkr.co/edit/jJHQECrKRrtKlKYRpIWl?p=preview


N
Nesha Zoric

如果您有多个想要pass props的孩子,您可以使用 React.Children.map 这样做:

render() {
    let updatedChildren = React.Children.map(this.props.children,
        (child) => {
            return React.cloneElement(child, { newProp: newProp });
        });

    return (
        <div>
            { updatedChildren }
        </div>
    );
}

如果您的组件只有一个孩子,则无需映射,您可以直接 cloneElement :

render() {
    return (
        <div>
            {
                React.cloneElement(this.props.children, {
                    newProp: newProp
                })
            }
        </div>
    );
}

D
DonKoko

受到上述所有答案的启发,这就是我所做的。我正在传递一些道具,比如一些数据和一些组件。

import React from "react";

const Parent = ({ children }) => {
  const { setCheckoutData } = actions.shop;
  const { Input, FieldError } = libraries.theme.components.forms;

  const onSubmit = (data) => {
    setCheckoutData(data);
  };

  const childrenWithProps = React.Children.map(
    children,
    (child) =>
      React.cloneElement(child, {
        Input: Input,
        FieldError: FieldError,
        onSubmit: onSubmit,
      })
  );

  return <>{childrenWithProps}</>;
};


<>{childrenWithProps}</> 是没有用的,因为 childrenWithProps 已经是一个数组。返回 childrenWithProps 就足够了。顺便说一句,这个答案与 6 年前选择的答案相同 - 都使用 React.Children.map 然后 cloneElement
s
sidonaldson

除了@and_rest 答案,这就是我克隆孩子并添加课程的方式。

<div className="parent">
    {React.Children.map(this.props.children, child => React.cloneElement(child, {className:'child'}))}
</div>

A
Alexandr Cherednichenko

也许您还可以找到有用的此功能,尽管许多人认为这是一种反模式,但如果您知道自己在做什么并很好地设计解决方案,它仍然可以使用。

Function as Child Components


Z
ZEE

我认为渲染道具是处理这种情况的合适方法

您可以让 Parent 提供在子组件中使用的必要道具,方法是重构 Parent 代码,使其看起来像这样:

const Parent = ({children}) => {
  const doSomething(value) => {}

  return children({ doSomething })
}

然后在子组件中,您可以通过这种方式访问父组件提供的功能:

class Child extends React {

  onClick() => { this.props.doSomething }

  render() { 
    return (<div onClick={this.onClick}></div>);
  }

}

现在 fianl 结构将如下所示:

<Parent>
  {(doSomething) =>
   (<Fragment>
     <Child value="1" doSomething={doSomething}>
     <Child value="2" doSomething={doSomething}>
    <Fragment />
   )}
</Parent>

如果父级只是作为另一个类组件中的文本区域的 {children} 的包装器,该怎么办?
n
nitte93

最巧妙的方法是:

    {React.cloneElement(this.props.children, this.props)}

这不会将 this.props.children 复制到孩子的 this.props.children 中吗?并且实际上将孩子复制到自身中?
S
Shubham Khatri

根据 cloneElement() 的文档

React.cloneElement(
  element,
  [props],
  [...children]
)

使用 element 作为起点克隆并返回一个新的 React 元素。结果元素将具有原始元素的道具和新道具的浅层合并。新的孩子将取代现有的孩子。原始元素的 key 和 ref 将被保留。 React.cloneElement() 几乎等同于: {children} 但是,它也保留了 refs。这意味着如果你得到一个带有 ref 的孩子,你不会不小心从你的祖先那里偷走它。您将获得附加到新元素的相同 ref。

所以 cloneElement 是你用来为孩子们提供自定义道具的东西。但是,组件中可以有多个子组件,您需要对其进行循环。其他答案建议您使用 React.Children.map 映射它们。然而,React.Children.mapReact.cloneElement 不同,它改变了 Element appending 和额外的 .$ 作为前缀的键。检查此问题以获取更多详细信息:React.cloneElement inside React.Children.map is causing element keys to change

如果您想避免它,您应该转而使用 forEach 函数,例如

render() {
    const newElements = [];
    React.Children.forEach(this.props.children, 
              child => newElements.push(
                 React.cloneElement(
                   child, 
                   {...this.props, ...customProps}
                )
              )
    )
    return (
        <div>{newElements}</div>
    )

}

y
yeasayer

您不再需要 {this.props.children}。现在您可以在 Route 中使用 render 包装您的子组件并像往常一样传递您的道具:

<BrowserRouter>
  <div>
    <ul>
      <li><Link to="/">Home</Link></li>
      <li><Link to="/posts">Posts</Link></li>
      <li><Link to="/about">About</Link></li>
    </ul>

    <hr/>

    <Route path="/" exact component={Home} />
    <Route path="/posts" render={() => (
      <Posts
        value1={1}
        value2={2}
        data={this.state.data}
      />
    )} />
    <Route path="/about" component={About} />
  </div>
</BrowserRouter>

渲染道具现在是 React (reactjs.org/docs/render-props.html) 中的标准,值得考虑作为这个问题的新接受答案。
这是如何回答这个问题的?
是的...这不能回答问题,因为问题与反应路由器无关。但是,它确实回答了我与这个问题相关的问题,该问题特定于 react-router。这个基本信息在我能找到的 react-router 网站上的任何地方都不清楚。他们的升级说明中肯定没有提到(非常不完整)。这个答案应该移到它自己的问题上。
u
user10884362

对于任何拥有单个子元素的人来说,都应该这样做。

{React.isValidElement(this.props.children)
                  ? React.cloneElement(this.props.children, {
                      ...prop_you_want_to_pass
                    })
                  : null}

p
pyjamas

这是我的版本,适用于单个、多个和无效的孩子。

const addPropsToChildren = (children, props) => {
  const addPropsToChild = (child, props) => {
    if (React.isValidElement(child)) {
      return React.cloneElement(child, props);
    } else {
      console.log("Invalid element: ", child);
      return child;
    }
  };
  if (Array.isArray(children)) {
    return children.map((child, ix) =>
      addPropsToChild(child, { key: ix, ...props })
    );
  } else {
    return addPropsToChild(children, props);
  }
};

使用示例:

https://codesandbox.io/s/loving-mcclintock-59emq?file=/src/ChildVsChildren.jsx:0-1069


a
amaster

使用功能组件时,您在尝试在 props.children 上设置新属性时经常会收到 TypeError: Cannot add property myNewProp, object is not extensible 错误。可以通过克隆道具然后用新道具克隆孩子本身来解决这个问题。

const MyParentComponent = (props) => {
  return (
    <div className='whatever'>
      {props.children.map((child) => {
        const newProps = { ...child.props }
        // set new props here on newProps
        newProps.myNewProp = 'something'
        const preparedChild = { ...child, props: newProps }
        return preparedChild
      })}
    </div>
  )
}

a
amit_183

这是你要求的吗?

var Parent = React.createClass({
  doSomething: function(value) {
  }
  render: function() {
    return  <div>
              <Child doSome={this.doSomething} />
            </div>
  }
})

var Child = React.createClass({
  onClick:function() {
    this.props.doSome(value); // doSomething is undefined
  },  
  render: function() {
    return  <div onClick={this.onClick}></div>
  }
})

不,我不想将包装器的内容限制为某些特定内容。
K
Kalpesh Popat

我在研究类似需求时来到这篇文章,但我觉得克隆解决方案非常流行,太原始并且让我的注意力从功能上移开。

我在 React 文档中找到了一篇文章Higher Order Components

这是我的示例:

import React from 'react';

const withForm = (ViewComponent) => {
    return (props) => {

        const myParam = "Custom param";

        return (
            <>
                <div style={{border:"2px solid black", margin:"10px"}}>
                    <div>this is poc form</div>
                    <div>
                        <ViewComponent myParam={myParam} {...props}></ViewComponent>
                    </div>
                </div>
            </>
        )
    }
}

export default withForm;


const pocQuickView = (props) => {
    return (
        <div style={{border:"1px solid grey"}}>
            <div>this is poc quick view and it is meant to show when mouse hovers over a link</div>
        </div>
    )
}

export default withForm(pocQuickView);

对我来说,我找到了一个灵活的解决方案来实现高阶组件的模式。

当然,这取决于功能,但如果其他人正在寻找类似的需求,那很好,这比依赖于原始级别的反应代码(如克隆)要好得多。

我积极使用的其他模式是容器模式。一定要阅读它,那里有很多文章。


M
MHD

如果有人想知道如何在有一个或多个子节点的 TypeScript 中正确执行此操作。我正在使用 uuid 库为子元素生成唯一的键属性,当然,如果您只克隆一个元素,则不需要这些属性。

export type TParentGroup = {
  value?: string;
  children: React.ReactElement[] | React.ReactElement;
};

export const Parent = ({
  value = '',
  children,
}: TParentGroup): React.ReactElement => (
  <div className={styles.ParentGroup}>
    {Array.isArray(children)
      ? children.map((child) =>
          React.cloneElement(child, { key: uuidv4(), value })
        )
      : React.cloneElement(children, { value })}
  </div>
);

如您所见,此解决方案负责渲染一个 ReactElement 数组或单个 ReactElement,甚至允许您根据需要将属性向下传递给子组件。


a
aWebDeveloper

某些原因 React.children 不适合我。这对我有用。

我只想为孩子添加一个类。类似于更改道具

 var newChildren = this.props.children.map((child) => {
 const className = "MenuTooltip-item " + child.props.className;
    return React.cloneElement(child, { className });
 });

 return <div>{newChildren}</div>;

这里的诀窍是 React.cloneElement。您可以以类似的方式传递任何道具


o
omeralper

Render props 是解决此问题的最准确方法。与其将子组件作为子 props 传递给父组件,不如让父组件手动渲染子组件。 Render 是 react 内置的 props,它带有函数参数。在此函数中,您可以让父组件使用自定义参数呈现您想要的任何内容。基本上它与子道具做同样的事情,但它更可定制。

class Child extends React.Component {
  render() {
    return <div className="Child">
      Child
      <p onClick={this.props.doSomething}>Click me</p>
           {this.props.a}
    </div>;
  }
}

class Parent extends React.Component {
  doSomething(){
   alert("Parent talks"); 
  }

  render() {
    return <div className="Parent">
      Parent
      {this.props.render({
        anythingToPassChildren:1, 
        doSomething: this.doSomething})}
    </div>;
  }
}

class Application extends React.Component {
  render() {
    return <div>
      <Parent render={
          props => <Child {...props} />
        }/>
    </div>;
  }
}

Example at codepen


V
Vivek sharma

有很多方法可以做到这一点。

您可以将孩子作为道具传递给父母。

示例 1:

function Parent({ChildElement}){
   return <ChildElement propName={propValue} />
}

return <Parent ChildElement={ChildComponent}/>

将孩子作为函数传递

示例 2:

function Parent({children}){
   return children({className: "my_div"})
}

OR

function Parent({children}){
   let Child = children
   return <Child className='my_div' />
}

function Child(props){
  return <div {...props}></div>
}

export <Parent>{props => <Child {...props} />}</Parent>

n
nomadus

我确实很难让列出的答案起作用,但失败了。最终,我发现问题在于正确设置父子关系。仅仅将组件嵌套在其他组件中并不意味着存在父子关系。

示例 1. 亲子关系;

function Wrapper() {
  return (
    <div>
      <OuterComponent>
        <InnerComponent />
      </OuterComponent>
    </div>
  );
}
function OuterComponent(props) {
  return props.children;
}
function InnerComponent() {
  return <div>Hi! I'm in inner component!</div>;
}
export default Wrapper;

示例 2. 嵌套组件:

function Wrapper() {
  return (
    <div>
      <OuterComponent />
    </div>
  );
}
function OuterComponent(props) {
  return <InnerComponent />
}
function InnerComponent() {
  return <div>Hi! I'm in inner component!</div>;
}
export default Wrapper;

正如我上面所说,道具传递在示例 1 的情况下有效。

下面的文章对此进行了解释https://medium.com/@justynazet/passing-props-to-props-children-using-react-cloneelement-and-render-props-pattern-896da70b24f6