toString children of title (#25838)

children of title can either behave like children or like an attribute.
We're kind of treating it more like an attribute now so we should
support toString/valueOf like we do on attributes.
This commit is contained in:
Sebastian Markbåge
2022-12-07 09:41:50 -05:00
committed by GitHub
parent d4bc16a7d6
commit bfcbf33067
4 changed files with 53 additions and 22 deletions

View File

@@ -587,17 +587,27 @@ export function getResource(
return null;
}
case 'title': {
let child = pendingProps.children;
if (Array.isArray(child) && child.length === 1) {
child = child[0];
const children = pendingProps.children;
let child;
if (Array.isArray(children)) {
child = children.length === 1 ? children[0] : null;
} else {
child = children;
}
if (typeof child === 'string' || typeof child === 'number') {
if (
typeof child !== 'function' &&
typeof child !== 'symbol' &&
child !== null &&
child !== undefined
) {
// eslint-disable-next-line react-internal/safe-string-coercion
const childString = '' + (child: any);
const headRoot: Document = getDocumentFromRoot(resourceRoot);
const headResources = getResourcesFromRoot(headRoot).head;
const key = getTitleKey(child);
const key = getTitleKey(childString);
let resource = headResources.get(key);
if (!resource) {
const titleProps = titlePropsFromRawProps(child, pendingProps);
const titleProps = titlePropsFromRawProps(childString, pendingProps);
resource = {
type: 'title',
props: titleProps,

View File

@@ -652,17 +652,27 @@ export function resourcesFromElement(type: string, props: Props): boolean {
const resources = currentResources;
switch (type) {
case 'title': {
let child = props.children;
if (Array.isArray(child) && child.length === 1) {
child = child[0];
const children = props.children;
let child;
if (Array.isArray(children)) {
child = children.length === 1 ? children[0] : null;
} else {
child = children;
}
if (typeof child === 'string' || typeof child === 'number') {
const key = 'title::' + child;
if (
typeof child !== 'function' &&
typeof child !== 'symbol' &&
child !== null &&
child !== undefined
) {
// eslint-disable-next-line react-internal/safe-string-coercion
const childString = '' + (child: any);
const key = 'title::' + childString;
let resource = resources.headsMap.get(key);
if (!resource) {
resource = {
type: 'title',
props: titlePropsFromRawProps(child, props),
props: titlePropsFromRawProps(childString, props),
flushed: false,
};
resources.headsMap.set(key, resource);

View File

@@ -1473,12 +1473,19 @@ function pushTitleImpl(
}
target.push(endOfStartTag);
const child =
Array.isArray(children) && children.length < 2
? children[0] || null
: children;
if (typeof child === 'string' || typeof child === 'number') {
target.push(stringToChunk(escapeTextForBrowser(child)));
const child = Array.isArray(children)
? children.length < 2
? children[0]
: null
: children;
if (
typeof child !== 'function' &&
typeof child !== 'symbol' &&
child !== null &&
child !== undefined
) {
// eslint-disable-next-line react-internal/safe-string-coercion
target.push(stringToChunk(escapeTextForBrowser('' + child)));
}
target.push(endTag1, stringToChunk('title'), endTag2);
return null;

View File

@@ -5144,8 +5144,10 @@ describe('ReactDOMFizzServer', () => {
}
if (gate(flags => flags.enableFloat)) {
// invalid titles are not emitted on the server when float is on
expect(getVisibleChildren(container)).toEqual(undefined);
// object titles are toStringed when float is on
expect(getVisibleChildren(container)).toEqual(
<title>{'[object Object]'}</title>,
);
} else {
expect(getVisibleChildren(container)).toEqual(<title>hello</title>);
}
@@ -5159,8 +5161,10 @@ describe('ReactDOMFizzServer', () => {
expect(Scheduler).toFlushAndYield([]);
expect(errors).toEqual([]);
if (gate(flags => flags.enableFloat)) {
// invalid titles are not emitted on the server when float is on
expect(getVisibleChildren(container)).toEqual(undefined);
// object titles are toStringed when float is on
expect(getVisibleChildren(container)).toEqual(
<title>{'[object Object]'}</title>,
);
} else {
expect(getVisibleChildren(container)).toEqual(<title>hello</title>);
}