Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: facebook/react
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: a5d9d85a94e0e9270c704c62ed5f23e36bd4e23e
Choose a base ref
..
head repository: facebook/react
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 2cb5b8a1bf72e15b3828af78c6209b7efefad4e9
Choose a head ref
Showing with 3,853 additions and 680 deletions.
  1. +2 −2 README.md
  2. +1 −1 package.json
  3. +1 −1 packages/create-subscription/README.md
  4. +5 −1 packages/create-subscription/package.json
  5. +69 −0 packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js
  6. +5 −1 packages/eslint-plugin-react-hooks/package.json
  7. +30 −25 packages/eslint-plugin-react-hooks/src/RulesOfHooks.js
  8. +5 −1 packages/jest-mock-scheduler/package.json
  9. +5 −1 packages/jest-react/package.json
  10. +5 −1 packages/react-art/package.json
  11. +5 −1 packages/react-cache/package.json
  12. +5 −1 packages/react-debug-tools/package.json
  13. +10 −5 packages/react-debug-tools/src/ReactDebugHooks.js
  14. +0 −3 ...-debug-tools/src/__tests__/{ReactHooksInspection-test.internal.js → ReactHooksInspection-test.js}
  15. +0 −3 ...ts__/{ReactHooksInspectionIntegration-test.internal.js → ReactHooksInspectionIntegration-test.js}
  16. +5 −1 packages/react-dom/package.json
  17. +34 −0 packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js
  18. +186 −0 packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.internal.js
  19. +103 −0 packages/react-dom/src/__tests__/ReactDOMHooks-test.js
  20. +100 −0 packages/react-dom/src/__tests__/ReactDOMRoot-test.js
  21. +80 −3 packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.internal.js
  22. +57 −14 packages/react-dom/src/__tests__/ReactDOMServerIntegrationNewContext-test.js
  23. +0 −3 ...rc/__tests__/{ReactDOMSuspensePlaceholder-test.internal.js → ReactDOMSuspensePlaceholder-test.js}
  24. +0 −1 packages/react-dom/src/__tests__/ReactErrorBoundaries-test.internal.js
  25. +9 −3 packages/react-dom/src/__tests__/ReactFunctionComponent-test.js
  26. +51 −8 packages/react-dom/src/client/ReactDOM.js
  27. +51 −8 packages/react-dom/src/fire/ReactFire.js
  28. +1 −7 packages/react-dom/src/server/ReactPartialRenderer.js
  29. +70 −27 packages/react-dom/src/server/ReactPartialRendererHooks.js
  30. +1 −0 packages/react-is/README.md
  31. +5 −1 packages/react-is/package.json
  32. +5 −1 packages/react-native-renderer/package.json
  33. +5 −1 packages/react-noop-renderer/package.json
  34. +5 −1 packages/react-reconciler/package.json
  35. +2 −1 packages/react-reconciler/src/ReactChildFiber.js
  36. +58 −1 packages/react-reconciler/src/ReactFiberBeginWork.js
  37. +1 −8 packages/react-reconciler/src/ReactFiberClassComponent.js
  38. +27 −33 packages/react-reconciler/src/ReactFiberCommitWork.js
  39. +0 −39 packages/react-reconciler/src/ReactFiberDispatcher.js
  40. +1,033 −334 packages/react-reconciler/src/ReactFiberHooks.js
  41. +7 −0 packages/react-reconciler/src/ReactFiberLazyComponent.js
  42. +33 −2 packages/react-reconciler/src/ReactFiberNewContext.js
  43. +19 −14 packages/react-reconciler/src/ReactFiberScheduler.js
  44. +1 −1 packages/react-reconciler/src/ReactFiberUnwindWork.js
  45. +4 −4 packages/react-reconciler/src/ReactStrictModeWarnings.js
  46. +14 −1 packages/react-reconciler/src/ReactUpdateQueue.js
  47. +754 −10 packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js
  48. +29 −33 packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.internal.js
  49. +3 −1 packages/react-reconciler/src/__tests__/ReactIncrementalSideEffects-test.internal.js
  50. +71 −0 packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js
  51. +25 −1 packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js
  52. +0 −1 packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js
  53. +0 −1 packages/react-reconciler/src/__tests__/ReactSuspenseFuzz-test.internal.js
  54. +0 −1 packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js
  55. +5 −1 packages/react-stream/package.json
  56. +5 −1 packages/react-test-renderer/package.json
  57. +417 −30 packages/react-test-renderer/src/ReactShallowRenderer.js
  58. +36 −0 packages/react-test-renderer/src/__tests__/ReactShallowRenderer-test.js
  59. +307 −0 packages/react-test-renderer/src/__tests__/ReactShallowRendererHooks-test.js
  60. +3 −1 packages/react-test-renderer/src/__tests__/ReactTestRenderer-test.internal.js
  61. +5 −1 packages/react/package.json
  62. +11 −14 packages/react/src/React.js
  63. +1 −1 packages/react/src/ReactCurrentDispatcher.js
  64. +4 −4 packages/react/src/ReactHooks.js
  65. +5 −1 packages/scheduler/package.json
  66. +0 −1 packages/shared/ReactFeatureFlags.js
  67. +0 −1 packages/shared/forks/ReactFeatureFlags.native-fb.js
  68. +0 −1 packages/shared/forks/ReactFeatureFlags.native-oss.js
  69. +0 −1 packages/shared/forks/ReactFeatureFlags.persistent.js
  70. +0 −1 packages/shared/forks/ReactFeatureFlags.test-renderer.js
  71. +0 −1 packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
  72. +0 −3 packages/shared/forks/ReactFeatureFlags.www.js
  73. +19 −2 scripts/release/prepare-stable-commands/check-out-packages.js
  74. +38 −3 yarn.lock
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -60,9 +60,9 @@ You'll notice that we used an HTML-like syntax; [we call it JSX](https://reactjs

The main purpose of this repository is to continue to evolve React core, making it faster and easier to use. Development of React happens in the open on GitHub, and we are grateful to the community for contributing bugfixes and improvements. Read below to learn how you can take part in improving React.

### [Code of Conduct](https://code.facebook.com/codeofconduct)
### [Code of Conduct](https://code.fb.com/codeofconduct)

Facebook has adopted a Code of Conduct that we expect project participants to adhere to. Please read [the full text](https://code.facebook.com/codeofconduct) so that you can understand what actions will and will not be tolerated.
Facebook has adopted a Code of Conduct that we expect project participants to adhere to. Please read [the full text](https://code.fb.com/codeofconduct) so that you can understand what actions will and will not be tolerated.

### [Contributing Guide](https://reactjs.org/contributing/how-to-contribute.html)

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -58,7 +58,7 @@
"flow-bin": "^0.72.0",
"glob": "^6.0.4",
"glob-stream": "^6.1.0",
"google-closure-compiler": "20180506.0.0",
"google-closure-compiler": "20190106.0.0",
"gzip-size": "^3.0.0",
"jasmine-check": "^1.0.0-rc.0",
"jest": "^23.1.0",
2 changes: 1 addition & 1 deletion packages/create-subscription/README.md
Original file line number Diff line number Diff line change
@@ -36,7 +36,7 @@ This abstraction can handle a variety of subscription types, including:
yarn add create-subscription

# NPM
npm install create-subscription --save
npm install create-subscription
```

# Usage
6 changes: 5 additions & 1 deletion packages/create-subscription/package.json
Original file line number Diff line number Diff line change
@@ -2,7 +2,11 @@
"name": "create-subscription",
"description": "utility for subscribing to external data sources inside React components",
"version": "16.7.0",
"repository": "facebook/react",
"repository": {
"type" : "git",
"url" : "https://github.com/facebook/react.git",
"directory": "packages/create-subscription"
},
"files": [
"LICENSE",
"README.md",
Original file line number Diff line number Diff line change
@@ -270,6 +270,75 @@ eslintTester.run('react-hooks', ReactHooksESLintRule, {
useState();
}
`,
`
// Valid because the loop doesn't change the order of hooks calls.
function RegressionTest() {
const res = [];
const additionalCond = true;
for (let i = 0; i !== 10 && additionalCond; ++i ) {
res.push(i);
}
React.useLayoutEffect(() => {});
}
`,
`
// Is valid but hard to compute by brute-forcing
function MyComponent() {
// 40 conditions
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
if (c) {} else {}
// 10 hooks
useHook();
useHook();
useHook();
useHook();
useHook();
useHook();
useHook();
useHook();
useHook();
useHook();
}
`,
],
invalid: [
{
6 changes: 5 additions & 1 deletion packages/eslint-plugin-react-hooks/package.json
Original file line number Diff line number Diff line change
@@ -3,7 +3,11 @@
"name": "eslint-plugin-react-hooks",
"description": "ESLint rules for React Hooks",
"version": "0.0.0",
"repository": "facebook/react",
"repository": {
"type" : "git",
"url" : "https://github.com/facebook/react.git",
"directory": "packages/eslint-plugin-react-hooks"
},
"files": [
"LICENSE",
"README.md",
55 changes: 30 additions & 25 deletions packages/eslint-plugin-react-hooks/src/RulesOfHooks.js
Original file line number Diff line number Diff line change
@@ -149,7 +149,14 @@ export default {
paths += countPathsFromStart(prevSegment);
}
}
cache.set(segment.id, paths);

// If our segment is reachable then there should be at least one path
// to it from the start of our code path.
if (segment.reachable && paths === 0) {
cache.delete(segment.id);
} else {
cache.set(segment.id, paths);
}

return paths;
}
@@ -374,13 +381,14 @@ export default {
for (const hook of reactHooks) {
// Report an error if a hook may be called more then once.
if (cycled) {
context.report(
hook,
`React Hook "${context.getSource(hook)}" may be executed ` +
context.report({
node: hook,
message:
`React Hook "${context.getSource(hook)}" may be executed ` +
'more than once. Possibly because it is called in a loop. ' +
'React Hooks must be called in the exact same order in ' +
'every component render.',
);
});
}

// If this is not a valid code path for React hooks then we need to
@@ -394,16 +402,15 @@ export default {
//
// Special case when we think there might be an early return.
if (!cycled && pathsFromStartToEnd !== allPathsFromStartToEnd) {
context.report(
hook,
const message =
`React Hook "${context.getSource(hook)}" is called ` +
'conditionally. React Hooks must be called in the exact ' +
'same order in every component render.' +
(possiblyHasEarlyReturn
? ' Did you accidentally call a React Hook after an' +
' early return?'
: ''),
);
'conditionally. React Hooks must be called in the exact ' +
'same order in every component render.' +
(possiblyHasEarlyReturn
? ' Did you accidentally call a React Hook after an' +
' early return?'
: '');
context.report({node: hook, message});
}
} else if (
codePathNode.parent &&
@@ -418,13 +425,12 @@ export default {
// call in a class, if it works, is unambigously *not* a hook.
} else if (codePathFunctionName) {
// Custom message if we found an invalid function name.
context.report(
hook,
const message =
`React Hook "${context.getSource(hook)}" is called in ` +
`function "${context.getSource(codePathFunctionName)}" ` +
'which is neither a React function component or a custom ' +
'React Hook function.',
);
`function "${context.getSource(codePathFunctionName)}" ` +
'which is neither a React function component or a custom ' +
'React Hook function.';
context.report({node: hook, message});
} else if (codePathNode.type === 'Program') {
// For now, ignore if it's in top level scope.
// We could warn here but there are false positives related
@@ -436,12 +442,11 @@ export default {
// enough in the common case that the incorrect message in
// uncommon cases doesn't matter.
if (isSomewhereInsideComponentOrHook) {
context.report(
hook,
const message =
`React Hook "${context.getSource(hook)}" cannot be called ` +
'inside a callback. React Hooks must be called in a ' +
'React function component or a custom React Hook function.',
);
'inside a callback. React Hooks must be called in a ' +
'React function component or a custom React Hook function.';
context.report({node: hook, message});
}
}
}
6 changes: 5 additions & 1 deletion packages/jest-mock-scheduler/package.json
Original file line number Diff line number Diff line change
@@ -4,7 +4,11 @@
"version": "0.1.0",
"description": "Jest matchers and utilities for testing the scheduler package.",
"main": "index.js",
"repository": "facebook/react",
"repository": {
"type" : "git",
"url" : "https://github.com/facebook/react.git",
"directory": "packages/jest-mock-scheduler"
},
"keywords": [
"jest",
"scheduler"
6 changes: 5 additions & 1 deletion packages/jest-react/package.json
Original file line number Diff line number Diff line change
@@ -3,7 +3,11 @@
"version": "0.5.0",
"description": "Jest matchers and utilities for testing React components.",
"main": "index.js",
"repository": "facebook/react",
"repository": {
"type" : "git",
"url" : "https://github.com/facebook/react.git",
"directory": "packages/jest-react"
},
"keywords": [
"react",
"jest",
6 changes: 5 additions & 1 deletion packages/react-art/package.json
Original file line number Diff line number Diff line change
@@ -3,7 +3,11 @@
"description": "React ART is a JavaScript library for drawing vector graphics using React. It provides declarative and reactive bindings to the ART library. Using the same declarative API you can render the output to either Canvas, SVG or VML (IE8).",
"version": "16.7.0",
"main": "index.js",
"repository": "facebook/react",
"repository": {
"type" : "git",
"url" : "https://github.com/facebook/react.git",
"directory": "packages/react-art"
},
"keywords": [
"react",
"art",
6 changes: 5 additions & 1 deletion packages/react-cache/package.json
Original file line number Diff line number Diff line change
@@ -3,7 +3,11 @@
"name": "react-cache",
"description": "A basic cache for React applications",
"version": "2.0.0-alpha.0",
"repository": "facebook/react",
"repository": {
"type" : "git",
"url" : "https://github.com/facebook/react.git",
"directory": "packages/react-cache"
},
"files": [
"LICENSE",
"README.md",
6 changes: 5 additions & 1 deletion packages/react-debug-tools/package.json
Original file line number Diff line number Diff line change
@@ -17,7 +17,11 @@
"cjs/"
],
"main": "index.js",
"repository": "facebook/react",
"repository": {
"type" : "git",
"url" : "https://github.com/facebook/react.git",
"directory": "packages/react-debug-tools"
},
"engines": {
"node": ">=0.10.0"
},
15 changes: 10 additions & 5 deletions packages/react-debug-tools/src/ReactDebugHooks.js
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@
import type {ReactContext, ReactProviderType} from 'shared/ReactTypes';
import type {Fiber} from 'react-reconciler/src/ReactFiber';
import type {Hook} from 'react-reconciler/src/ReactFiberHooks';
import typeof {Dispatcher as DispatcherType} from 'react-reconciler/src/ReactFiberDispatcher';
import type {Dispatcher as DispatcherType} from 'react-reconciler/src/ReactFiberHooks';

import ErrorStackParser from 'error-stack-parser';
import ReactSharedInternals from 'shared/ReactSharedInternals';
@@ -115,13 +115,18 @@ function useState<S>(
return [state, (action: BasicStateAction<S>) => {}];
}

function useReducer<S, A>(
function useReducer<S, I, A>(
reducer: (S, A) => S,
initialState: S,
initialAction: A | void | null,
initialArg: I,
init?: I => S,
): [S, Dispatch<A>] {
let hook = nextHook();
let state = hook !== null ? hook.memoizedState : initialState;
let state;
if (hook !== null) {
state = hook.memoizedState;
} else {
state = init !== undefined ? init(initialArg) : ((initialArg: any): S);
}
hookLog.push({
primitive: 'Reducer',
stackError: new Error(),
Original file line number Diff line number Diff line change
@@ -16,9 +16,6 @@ let ReactDebugTools;
describe('ReactHooksInspection', () => {
beforeEach(() => {
jest.resetModules();
let ReactFeatureFlags = require('shared/ReactFeatureFlags');
// TODO: Switch this test to non-internal once the flag is on by default.
ReactFeatureFlags.enableHooks = true;
React = require('react');
ReactDebugTools = require('react-debug-tools');
});
Original file line number Diff line number Diff line change
@@ -17,9 +17,6 @@ let ReactDebugTools;
describe('ReactHooksInspectionIntergration', () => {
beforeEach(() => {
jest.resetModules();
let ReactFeatureFlags = require('shared/ReactFeatureFlags');
// TODO: Switch this test to non-internal once the flag is on by default.
ReactFeatureFlags.enableHooks = true;
React = require('react');
ReactTestRenderer = require('react-test-renderer');
ReactDebugTools = require('react-debug-tools');
6 changes: 5 additions & 1 deletion packages/react-dom/package.json
Original file line number Diff line number Diff line change
@@ -3,7 +3,11 @@
"version": "16.7.0",
"description": "React package for working with the DOM.",
"main": "index.js",
"repository": "facebook/react",
"repository": {
"type" : "git",
"url" : "https://github.com/facebook/react.git",
"directory": "packages/react-dom"
},
"keywords": [
"react"
],
34 changes: 34 additions & 0 deletions packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js
Original file line number Diff line number Diff line change
@@ -1201,6 +1201,40 @@ describe('ReactComponentLifeCycle', () => {
expect(log).toEqual([]);
});

it('should pass previous state to shouldComponentUpdate even with getDerivedStateFromProps', () => {
const divRef = React.createRef();
class SimpleComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
value: props.value,
};
}

static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.value === prevState.value) {
return null;
}
return {value: nextProps.value};
}

shouldComponentUpdate(nextProps, nextState) {
return nextState.value !== this.state.value;
}

render() {
return <div ref={divRef}>value: {this.state.value}</div>;
}
}

const div = document.createElement('div');

ReactDOM.render(<SimpleComponent value="initial" />, div);
expect(divRef.current.textContent).toBe('value: initial');
ReactDOM.render(<SimpleComponent value="updated" />, div);
expect(divRef.current.textContent).toBe('value: updated');
});

it('should call getSnapshotBeforeUpdate before mutations are committed', () => {
const log = [];

Loading