From 7325ebe4d6e5b7ccf5a78128b825c8a6e383caa6 Mon Sep 17 00:00:00 2001
From: Brian Vaughn <brian.david.vaughn@gmail.com>
Date: Thu, 13 Dec 2018 09:40:59 -0800
Subject: [PATCH] Inject overrideProps() fn to DevTools (#14427)

* Inject overrideProps() fn to DevTools

This function will enable editing props for function components, host nodes, and special types like memo and forwardRef.
---
 .../src/ReactFiberReconciler.js               | 40 +++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/packages/react-reconciler/src/ReactFiberReconciler.js b/packages/react-reconciler/src/ReactFiberReconciler.js
index 665e02938f164..b75057c527862 100644
--- a/packages/react-reconciler/src/ReactFiberReconciler.js
+++ b/packages/react-reconciler/src/ReactFiberReconciler.js
@@ -62,6 +62,7 @@ import {
   current as ReactCurrentFiberCurrent,
 } from './ReactCurrentFiber';
 import {StrictMode} from './ReactTypeOfMode';
+import {Sync} from './ReactFiberExpirationTime';
 
 type OpaqueRoot = FiberRoot;
 
@@ -339,10 +340,49 @@ export function findHostInstanceWithNoPortals(
   return hostFiber.stateNode;
 }
 
+let overrideProps = null;
+
+if (__DEV__) {
+  const copyWithSetImpl = (
+    obj: Object | Array<any>,
+    path: Array<string | number>,
+    idx: number,
+    value: any,
+  ) => {
+    if (idx >= path.length) {
+      return value;
+    }
+    const key = path[idx];
+    const updated = Array.isArray(obj) ? obj.slice() : {...obj};
+    // $FlowFixMe number or string is fine here
+    updated[key] = copyWithSetImpl(obj[key], path, idx + 1, value);
+    return updated;
+  };
+
+  const copyWithSet = (
+    obj: Object | Array<any>,
+    path: Array<string | number>,
+    value: any,
+  ): Object | Array<any> => {
+    return copyWithSetImpl(obj, path, 0, value);
+  };
+
+  // Support DevTools props for function components, forwardRef, memo, host components, etc.
+  overrideProps = (fiber: Fiber, path: Array<string | number>, value: any) => {
+    flushPassiveEffects();
+    fiber.pendingProps = copyWithSet(fiber.memoizedProps, path, value);
+    if (fiber.alternate) {
+      fiber.alternate.pendingProps = fiber.pendingProps;
+    }
+    scheduleWork(fiber, Sync);
+  };
+}
+
 export function injectIntoDevTools(devToolsConfig: DevToolsConfig): boolean {
   const {findFiberByHostInstance} = devToolsConfig;
   return injectInternals({
     ...devToolsConfig,
+    overrideProps,
     findHostInstanceByFiber(fiber: Fiber): Instance | TextInstance | null {
       const hostFiber = findCurrentHostFiber(fiber);
       if (hostFiber === null) {