Repository: preactjs/preact (2023-01-08T19:22:21Z)

Issue:
Differences in Preact.Children API and React.Children API
Hey friends!

I noticed a small difference in how `React.Children` is implemented between `preact/compat` and React.

`preact/compat` children: https://github.com/preactjs/preact/blob/master/compat/src/Children.js#L3
`react` children: https://github.com/facebook/react/blob/121af3143c7164a196420b080cb31d0ef07d5dff/packages/react/src/ReactChildren.js#L223

The different here being that the React implementation allows for a `context` arg, while the `preact/compat` version does not. While it's easily fixable on our end, it seemed like the kind of thing which might lead to incompatibilities in library code.



Discussion:
Is this issue still open?
Yes. It's unlikely to be fixed, as no issues have ever been opened citing this as a real-world compatibility issue.
Does this mean I can't work on it? I saw the "beginner-friendly" tag.



Patch:
diff --git a/compat/src/Children.js b/compat/src/Children.js
index 0295d936e8..24c9c33fb1 100644
--- a/compat/src/Children.js
+++ b/compat/src/Children.js
@@ -1,8 +1,8 @@
 import { toChildArray } from 'preact';
 
-const mapFn = (children, fn) => {
+const mapFn = (children, fn, context) => {
 	if (children == null) return null;
-	return toChildArray(toChildArray(children).map(fn));
+	return toChildArray(toChildArray(children).map(fn.bind(context)));
 };
 
 // This API is completely unnecessary for Preact, so it's basically passthrough.
diff --git a/compat/src/index.d.ts b/compat/src/index.d.ts
index ce437a1065..45c4441e0d 100644
--- a/compat/src/index.d.ts
+++ b/compat/src/index.d.ts
@@ -407,11 +407,13 @@ declare namespace React {
 	export const Children: {
 		map<T extends preact1.ComponentChild, R>(
 			children: T | T[],
-			fn: (child: T, i: number) => R
+			fn: (child: T, i: number) => R,
+			context: any
 		): R[];
 		forEach<T extends preact1.ComponentChild>(
 			children: T | T[],
-			fn: (child: T, i: number) => void
+			fn: (child: T, i: number) => void,
+			context: any
 		): void;
 		count: (children: preact1.ComponentChildren) => number;
 		only: (children: preact1.ComponentChildren) => preact1.ComponentChild;


Test patch:
diff --git a/compat/test/browser/Children.test.js b/compat/test/browser/Children.test.js
index 53c0c776bf..4f4f9434fa 100644
--- a/compat/test/browser/Children.test.js
+++ b/compat/test/browser/Children.test.js
@@ -5,6 +5,7 @@ import {
 } from '../../../test/_util/helpers';
 import { div, span } from '../../../test/_util/dom';
 import React, { createElement, Children, render } from 'preact/compat';
+import { vi } from 'vitest';
 
 describe('Children', () => {
 	/** @type {HTMLDivElement} */
@@ -106,6 +107,17 @@ describe('Children', () => {
 			expect(serializeHtml(scratch)).to.equal('<div><span>0</span></div>');
 		});
 
+		it('should propagate "this" context', () => {
+			const context = {};
+			const spy = vi.fn(child => child); // noop
+			const Foo = ({ children }) => {
+				return React.Children.map(children, spy, context);
+			};
+			render(<Foo>foo</Foo>, scratch);
+
+			expect(spy.mock.contexts[0]).to.equal(context);
+		});
+
 		it('should flatten result', () => {
 			const ProblemChild = ({ children }) => {
 				return React.Children.map(children, child => {