How is props.children added inside opening and closing tags in React JS with children="xyz" attribute?

huangapple go评论64阅读模式
英文:

How is props.children added inside opening and closing tags in React JS with children="xyz" attribute?

问题

以下是代码部分的中文翻译:

这是我对在React中理解 props.children 的方式:

class ThemedButton extends React.Component {
  render() {
    console.log(this.props);
    return (
      <button>
        {this.props.children}
      </button>
    );
  }
}

function Toolbar(props) {
  return (
    <ThemedButton onClick={props.changeTheme}>
      Change Theme
    </ThemedButton>
  );
}

ReactDOM.render(<Toolbar />, document.getElementById('root'));
// 这将生成<button>Change Theme 12345</button>

所以,ThemedButton 的任何子节点都会放在 props.children 的位置。这是有道理的,但不太清楚的是,如果我省略 props.children 而只传递 {...props} 作为属性,或者在按钮标签上使用 children 属性作为属性,它仍然会插入子节点。以下是示例:

class ThemedButton extends React.Component {
  render() {
    console.log(this.props);
    return (
      <button {...this.props}></button> // 子节点会自动添加
    );
  }
}

class ThemedButton2 extends React.Component {
  render() {
    console.log(this.props);
    return (
      <button children="XYZ"></button>
    );
  }
}

function Toolbar(props) {
  return (
    <React.Fragment>
      <ThemedButton onClick={props.changeTheme}>
        Change Theme
      </ThemedButton>
      <ThemedButton2>Change theme2</ThemedButton2>
    </React.Fragment>
  );
}

ReactDOM.render(<Toolbar />, document.getElementById('root'));

正如您所见,button 上的 {...props} 似乎会将 ThemedButton 的实际子节点作为 button 的 children 属性传递。在 ThemedButton2 中,我手动提供了 children="xyz",它会自动插入 xyz 作为 button 的子节点。

为什么会发生这种情况?React 在官方文档中是否有解释?

英文:

This is how I understand props.children in React:

<!-- begin snippet: js hide: false console: true babel: true -->

<!-- language: lang-js -->

class ThemedButton extends React.Component {
  render() {
    console.log(this.props);
    return ( &lt;
      button &gt; {
        this.props.children
      }
      &quot; 12345&quot; &lt;
      /button&gt;
    );
  }
}

function Toolbar(props) {
  return ( &lt;
    ThemedButton onClick = {
      props.changeTheme
    } &gt;
    Change Theme &lt;
    /ThemedButton&gt;
  );
}



ReactDOM.render( &lt; Toolbar / &gt; , document.getElementById(&#39;root&#39;));
//this will generate &lt;button&gt;Change Theme 12345&lt;/button&gt;

<!-- language: lang-html -->

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;


&lt;div id=&quot;root&quot;&gt;&lt;/div&gt;

<!-- end snippet -->

So basically any child node(s) of ThemedButton will be put in place of props.children. This makes sense, but what doesn't make sense is if I omit props.children and instead just pass {...props} as attribute or use children attribute as property on the button tag, it still inserts the child node(s). Following is the example:

<!-- begin snippet: js hide: false console: true babel: true -->

<!-- language: lang-js -->

class ThemedButton extends React.Component {
  render() {
    console.log(this.props);
    return ( 
    &lt;button {...this.props}  &gt;&lt;/button&gt;  //child nodes are added automatically     
    );
  }
}

class ThemedButton2 extends React.Component {
  render() {
    console.log(this.props);
    return ( 
    &lt;button children=&quot;XYZ&quot;  &gt;&lt;/button&gt;
    );
  }
}


function Toolbar(props) {
  return ( 
  &lt;React.Fragment&gt;
    &lt;
    ThemedButton onClick = {
      props.changeTheme
    } &gt;
    Change Theme &lt;
    /ThemedButton&gt;
    &lt;ThemedButton2&gt; Change theme2 &lt;/ThemedButton2&gt;
  &lt;/React.Fragment&gt;
  );
}



ReactDOM.render( &lt; Toolbar / &gt; , document.getElementById(&#39;root&#39;));

<!-- language: lang-html -->

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react/16.6.1/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.1/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;

&lt;div id=&quot;root&quot;&gt;&lt;/div&gt;

<!-- end snippet -->

As you can see {...props} on button seemingly brings actual child nodes of ThemedButton&gt; as children property. In ThemedButton2 I manually provided children=&quot;xyz&quot;, which automatically inserts xyz as child nodes of button.

Why is this happening? Where does react explain this in it's official documentation?

答案1

得分: 3

以下是翻译好的部分:

如果您查看类型定义,应该会很清楚:
&lt;button&gt; 的类型是

React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>;

React.DetailedHTMLProps 定义如下:

type DetailedHTMLProps<E extends HTMLAttributes<T>, T> = ClassAttributes<T> & E;

因此,它扩展了 HTMLAttributes,HTMLAttributes 定义如下:

interface HTMLAttributes<T> extends AriaAttributes, DOMAttributes<T> {
...
}

并扩展了 DOMAttributes,DOMAttributes 最终定义如下:

interface DOMAttributes<T> {
children?: ReactNode | undefined;
dangerouslySetInnerHTML?: {
__html: string;
} | undefined;

// Clipboard Events
onCopy?: ClipboardEventHandler<T> | undefined;
onCopyCapture?: ClipboardEventHandler<T> | undefined;
onCut?: ClipboardEventHandler<T> | undefined;
onCutCapture?: ClipboardEventHandler<T> | undefined;
onPaste?: ClipboardEventHandler<T> | undefined;
onPasteCapture?: ClipboardEventHandler<T> | undefined;
...
}

因此,最终,children 实际上是 button 的有效属性,如果您通过以下方式覆盖它:

<button children="TEST" />

它将实际呈现该 children 属性。
在 React 文档中,他们在这里谈到了这一点:https://react.dev/reference/react-dom/components/common,其中说道:

> 所有内置的浏览器组件,如 &lt;div /&gt;,都支持一些常见的属性和事件。

这些属性可以在这里找到:https://react.dev/reference/react-dom/components/common#common-props

其中 children 是其中之一:

> children: 一个 React 节点(一个元素,一个字符串,一个数字,一个 portal,一个空节点,如 null、undefined 和布尔值,或其他 React 节点的数组)。指定组件内部的内容。当您使用 JSX 时,通常会通过嵌套标签来隐式指定 children 属性,比如 <div><span /></div>。

英文:

If you look at type definitions it should be quite clear:
&lt;button&gt; is of type

React.DetailedHTMLProps&lt;React.ButtonHTMLAttributes&lt;HTMLButtonElement&gt;, HTMLButtonElement&gt;;

React.DetailedHTMLProps is defined as:

type DetailedHTMLProps&lt;E extends HTMLAttributes&lt;T&gt;, T&gt; = ClassAttributes&lt;T&gt; &amp; E;

so it extends HTMLAttributes, which is defined as:

    interface HTMLAttributes&lt;T&gt; extends AriaAttributes, DOMAttributes&lt;T&gt; {
...
}

and extends DOMAttributes, which is defined (finally) as:

interface DOMAttributes&lt;T&gt; {
            children?: ReactNode | undefined;
            dangerouslySetInnerHTML?: {
                __html: string;
            } | undefined;
    
            // Clipboard Events
            onCopy?: ClipboardEventHandler&lt;T&gt; | undefined;
            onCopyCapture?: ClipboardEventHandler&lt;T&gt; | undefined;
            onCut?: ClipboardEventHandler&lt;T&gt; | undefined;
            onCutCapture?: ClipboardEventHandler&lt;T&gt; | undefined;
            onPaste?: ClipboardEventHandler&lt;T&gt; | undefined;
            onPasteCapture?: ClipboardEventHandler&lt;T&gt; | undefined;
...
}

So, in the end, children is actually a valid prop of button, and if you overwrite it by stating:

&lt;button children=&quot;TEST&quot; /&gt;

It will actually render that children property.
In React docs they talk about this here: https://react.dev/reference/react-dom/components/common saying that:

> All built-in browser components, such as &lt;div /&gt;, support some common props and events.

and those props are to be found here: https://react.dev/reference/react-dom/components/common#common-props

and children is one of them:

> children: A React node (an element, a string, a number, a portal, an empty node like null, undefined and booleans, or an array of other React nodes). Specifies the content inside the component. When you use JSX, you will usually specify the children prop implicitly by nesting tags like <div><span /></div>.

huangapple
  • 本文由 发表于 2023年5月21日 17:41:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/76299231.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定