function getJSReport(browser){ return browser <del> .waitForCondition("typeof window.jasmine != 'undefined'", 5e3) </del> <ins> .waitFor(wd.asserters.jsCondition("typeof window.jasmine != 'undefined'"), 5e3, 50) </ins> .fail(function(error){ throw Error("The test page didn't load properly. " + error); }) <del> .waitForCondition("typeof window.jasmine.getJSReport != 'undefined'", 10e3) .waitForCondition("window.postDataToURL.running <= 0", 30e3) </del> <ins> .waitFor(wd.asserters.jsCondition("typeof window.jasmine.getJSReport != 'undefined'"), 60e3, 100) .waitFor(wd.asserters.jsCondition("window.postDataToURL.running <= 0"), 30e3, 500) </ins> .eval("jasmine.getJSReport().passed"); }


urls.unshift('../node_modules/es5-shim/es5-shim.js'); } <del> var cacheBust = '?_=' + Date.now().toString(36); </del> <ins> var cacheBust = '?_=' + (+new Date).toString(36); </ins> for (var urls_index = -1, urls_length = urls.length; ++urls_index < urls_length;) { document.write('<script src="' + urls[urls_index] + cacheBust + '"></script>');


* @protected */ setState: function(partialState, callback) { <ins> invariant( typeof partialState === 'object' || partialState == null, 'setState(...): takes an object of state variables to update.' ); if (__DEV__){ if (partialState == null) { console.warn( 'setState(...): You passed an undefined or null state object; ' + 'instead, use forceUpdate().' ); } } </ins> // Merge with `_pendingState` if it exists, otherwise with existing state. this.replaceState( merge(this._pendingState || this.state, partialState),


checkMergeArrayArgs: function(one, two) { invariant( Array.isArray(one) && Array.isArray(two), <del> 'Critical assumptions about the merge functions have been violated. ' + 'This is the fault of the merge functions themselves, not necessarily ' + 'the callers.' </del> <ins> 'Tried to merge arrays, instead got %s and %s.', one, two </ins> ); },


checkMergeObjectArg: function(arg) { invariant( !isTerminal(arg) && !Array.isArray(arg), <del> 'Critical assumptions about the merge functions have been violated. ' + 'This is the fault of the merge functions themselves, not necessarily ' + 'the callers.' </del> <ins> 'Tried to merge an object, instead got %s.', arg </ins> ); },


* CSS properties which accept numbers but are not in units of "px". */ var isUnitlessNumber = { <ins> columnCount: true, </ins> fillOpacity: true, <ins> flex: true, flexGrow: true, flexShrink: true, </ins> fontWeight: true, lineHeight: true, opacity: true, <ins> order: true, </ins> orphans: true, <ins> pitchRange: true, richness: true, stress: true, volume: true, widows: true, </ins> zIndex: true, zoom: true };


}); it('should not append `px` to styles that might need a number', function() { <del> expect(CSSPropertyOperations.createMarkupForStyles({ fillOpacity: 1, fontWeight: 2, opacity: 3, orphans: 4, zIndex: 5, zoom: 6, lineHeight: 7 })).toBe( 'fill-opacity:1;font-weight:2;opacity:3;orphans:4;z-index:5;zoom:6;' + 'line-height:7;' ); </del> <ins> var unitlessProperties = [ 'columnCount', 'fillOpacity', 'flex', 'flexGrow', 'flexShrink', 'fontWeight', 'lineHeight', 'opacity', 'order', 'orphans', 'pitchRange', 'richness', 'stress', 'volume', 'widows', 'zIndex', 'zoom' ]; unitlessProperties.forEach(function(property) { var styles = {}; styles[property] = 1; expect(CSSPropertyOperations.createMarkupForStyles(styles)) .toMatch(/:1;$/); }); </ins> }); it('should set style attribute when styles exist', function() {


"url": "https://github.com/facebook/react" }, "dependencies": { <del> "commoner": "~0.8.14", </del> <ins> "commoner": "~0.9.0", </ins> "esprima-fb": "~2001.1001.0-dev-harmony-fb", "jstransform": "~2.0.2" },


var mocks = require('mocks'); <ins> var ExecutionEnvironment; </ins> var React; <ins> var ReactMarkupChecksum; </ins> var ReactMount; <ins> var ReactReconcileTransaction; </ins> var ReactTestUtils; var ReactServerRendering; <del> var ReactMarkupChecksum; var ExecutionEnvironment; </del> var ID_ATTRIBUTE_NAME;


beforeEach(function() { require('mock-modules').dumpCache(); React = require('React'); <ins> ReactMarkupChecksum = require('ReactMarkupChecksum'); </ins> ReactMount = require('ReactMount'); ReactTestUtils = require('ReactTestUtils'); <ins> ReactReconcileTransaction = require('ReactReconcileTransaction'); </ins> ExecutionEnvironment = require('ExecutionEnvironment'); ExecutionEnvironment.canUseDOM = false; ReactServerRendering = require('ReactServerRendering'); <del> ReactMarkupChecksum = require('ReactMarkupChecksum'); </del> var DOMProperty = require('DOMProperty'); ID_ATTRIBUTE_NAME = DOMProperty.ID_ATTRIBUTE_NAME;


'a valid ReactComponent.' ); }); <ins> it('allows setState in componentWillMount without using DOM', function() { var Component = React.createClass({ componentWillMount: function() { this.setState({text: 'hello, world'}); }, render: function() { return <div>{this.state.text}</div>; } }); ReactReconcileTransaction.prototype.perform = function() { // We shouldn't ever be calling this on the server throw new Error('Browser reconcile transaction should not be used'); }; var markup = ReactServerRendering.renderComponentToString( <Component /> ); expect(markup.indexOf('hello, world') >= 0).toBe(true); }); </ins> }); });


// componentDidUpdate) but we need to check here too in order to catch // updates enqueued by setState callbacks. while (dirtyComponents.length) { <ins> var allUnmounted = true; for (var i = 0, l = dirtyComponents.length; i < l; i++) { if (dirtyComponents[i].isMounted()) { allUnmounted = false; break; } } if (allUnmounted) { // All the "dirty" components are unmounted, which probably means that // they were marked dirty due to setState calls in componentWillMount // handlers and the components are currently in the process of mounting. // `runBatchedUpdates` will be a noop. In that case, initializing the // DOM-dependent ReactReconcileTransaction is thus not what we want to // do, especially when using server rendering, so we skip it. dirtyComponents.length = 0; return; } </ins> var transaction = ReactUpdatesFlushTransaction.getPooled(); transaction.perform(runBatchedUpdates, null, transaction); ReactUpdatesFlushTransaction.release(transaction);


* **Computed data:** Don't worry about precomputing values based on state — it's easier to ensure that your UI is consistent if you do all computation within `render()`. For example, if you have an array of list items in state and you want to render the count as a string, simply render `this.state.listItems.length + ' list items'` in your `render()` method rather than storing it on state. * **React components:** Build them in `render()` based on underlying props and state. <del> * **Duplicated data from props:** Try to use props as the source of truth where possible. Because props can change over time, it's appropriate to store props in state to be able to know its previous values. </del> <ins> * **Duplicated data from props:** Try to use props as the source of truth where possible. One valid use to store props in state is to be able to know it's previous values, because props can change over time. </ins>


invariant( one[key] === undefined, 'mergeObjectsWithNoDuplicateKeys(): ' + <del> 'Tried to merge two objects with the same key: %s', </del> <ins> 'Tried to merge two objects with the same key: `%s`. This conflict ' + 'may be due to a mixin; in particular, this may be caused by two ' + 'getInitialState() or getDefaultProps() methods returning objects ' + 'with clashing keys.', </ins> key ); one[key] = value;


instance = ReactTestUtils.renderIntoDocument(instance); }).toThrow( 'Invariant Violation: mergeObjectsWithNoDuplicateKeys(): ' + <del> 'Tried to merge two objects with the same key: x' </del> <ins> 'Tried to merge two objects with the same key: `x`. This conflict ' + 'may be due to a mixin; in particular, this may be caused by two ' + 'getInitialState() or getDefaultProps() methods returning objects ' + 'with clashing keys.' </ins> ); });


<ins> /** * Copyright 2014-2015, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * * @emails react-core */ 'use strict'; require('mock-modules') .dontMock('shallowEqual'); var shallowEqual; describe('shallowEqual', function() { beforeEach(function() { shallowEqual = require('shallowEqual'); }); it('returns false if either argument is null', function() { expect(shallowEqual(null, {})).toBe(false); expect(shallowEqual({}, null)).toBe(false); }); it('returns true if both arguments are null or undefined', function() { expect(shallowEqual(null, null)).toBe(true); expect(shallowEqual(undefined, undefined)).toBe(true); }); it('returns true if arguments are shallow equal', function() { expect( shallowEqual( {a: 1, b: 2, c: 3}, {a: 1, b: 2, c: 3} ) ).toBe(true); }); it('returns false if first argument has too many keys', function() { expect( shallowEqual( {a: 1, b: 2, c: 3}, {a: 1, b: 2} ) ).toBe(false); }); it('returns false if second argument has too many keys', function() { expect( shallowEqual( {a: 1, b: 2}, {a: 1, b: 2, c: 3} ) ).toBe(false); }); it('returns false if arguments are not shallow equal', function() { expect( shallowEqual( {a: 1, b: 2, c: {}}, {a: 1, b: 2, c: {}} ) ).toBe(false); }); }); </ins>


if (objA === objB) { return true; } <ins> if (!objA || !objB) { return false; } </ins> var key; // Test for A's keys different from B. for (key in objA) {


HTML to JSX Compiler


}, "preferGlobal": true, "commonerConfig": { <del> "version": 6 </del> <ins> "version": 7 </ins> }, "scripts": { "test": "jest",


CallExpression: { exit: function(node, parent) { if (this.get('callee').isIdentifier({name: 'invariant'})) { <del> // Truncate the arguments of invariant(condition, ...) // statements to just the condition based on NODE_ENV // (dead code removal will remove the extra bytes). return t.conditionalExpression( DEV_EXPRESSION, node, t.callExpression(node.callee, [node.arguments[0]]) </del> <ins> // Turns this code: // // invariant(condition, argument, argument); // // into this: // // if (!condition) { //   if ("production" !== process.env.NODE_ENV) { //     invariant(false, argument, argument); //   } else { //     invariant(false); //   } // } // // Specifically this does 2 things: // 1. Checks the condition first, preventing an extra function call. // 2. Adds an environment check so that verbose error messages aren't //    shipped to production. // The generated code is longer than the original code but will dead // code removal in a minifier will strip that out. var condition = node.arguments[0]; return t.ifStatement( t.unaryExpression('!', condition), t.blockStatement([ t.ifStatement( DEV_EXPRESSION, t.blockStatement([ t.expressionStatement( t.callExpression( node.callee, [t.literal(false)].concat(node.arguments.slice(1)) ) ) ]), t.blockStatement([ t.expressionStatement( t.callExpression( node.callee, [t.literal(false)] ) ) ]) ) ]) </ins> ); } else if (this.get('callee').isIdentifier({name: 'warning'})) { <del> // Eliminate warning(condition, ...) statements based on NODE_ENV // (dead code removal will remove the extra bytes). return t.conditionalExpression( </del> <ins> // Turns this code: // // warning(condition, argument, argument); // // into this: // // if ("production" !== process.env.NODE_ENV) { //   warning(condition, argument, argument); // } // // The goal is to strip out warning calls entirely in production. We // don't need the same optimizations for conditions that we use for // invariant because we don't care about an extra call in __DEV__ return t.ifStatement( </ins> DEV_EXPRESSION, <del> node, t.literal(null) </del> <ins> t.blockStatement([ t.expressionStatement( node ) ]) </ins> ); } }


itemRef: MUST_USE_ATTRIBUTE, // property is supported for OpenGraph in meta tags. property: null, <ins> // IE-only attribute that specifies security restrictions on an iframe // as an alternative to the sandbox attribute on IE<10 security: MUST_USE_ATTRIBUTE, </ins> // IE-only attribute that controls focus behavior unselectable: MUST_USE_ATTRIBUTE, },


var grunt = require('grunt'); var UglifyJS = require('uglify-js'); var uglifyify = require('uglifyify'); <del> var _ = require('lodash'); </del> <ins> var derequire = require('derequire'); </ins> var SIMPLE_TEMPLATE = '/**n


debug: false, standalone: 'React', transforms: [envify({NODE_ENV: 'development'})], <del> after: [es3ify.transform, simpleBannerify] </del> <ins> after: [es3ify.transform, derequire, simpleBannerify] </ins> }; <del> var min = _.merge({}, basic, { </del> <ins> var min = { entries: [ './build/modules/React.js' ], </ins> outfile: './build/react.min.js', debug: false, <ins> standalone: 'React', </ins> transforms: [envify({NODE_ENV: 'production'}), uglifyify], <del> after: [minify, bannerify] }); </del> <ins> after: [es3ify.transform, derequire, minify, bannerify] }; </ins> var transformer = { entries:[


outfile: './build/JSXTransformer.js', debug: false, standalone: 'JSXTransformer', <del> after: [es3ify.transform, simpleBannerify] </del> <ins> transforms: [], after: [es3ify.transform, derequire, simpleBannerify] </ins> }; var addons = {


outfile: './build/react-with-addons.js', debug: false, standalone: 'React', <del> transforms: [envify({NODE_ENV: 'development'})], </del> packageName: 'React (with addons)', <del> after: [es3ify.transform, simpleBannerify] </del> <ins> transforms: [envify({NODE_ENV: 'development'})], after: [es3ify.transform, derequire, simpleBannerify] </ins> }; <del> var addonsMin = _.merge({}, addons, { </del> <ins> var addonsMin = { entries: [ './build/modules/ReactWithAddons.js' ], </ins> outfile: './build/react-with-addons.min.js', debug: false, <ins> standalone: 'React', packageName: 'React (with addons)', </ins> transforms: [envify({NODE_ENV: 'production'}), uglifyify], <del> after: [minify, bannerify] }); </del> <ins> after: [es3ify.transform, derequire, minify, bannerify] }; </ins> var withCodeCoverageLogging = { entries: [


// grunt.config.requires('entries'); config.transforms = config.transforms || []; config.after = config.after || []; <del> if (typeof config.after === 'function') { config.after = [config.after]; } </del> // create the bundle we'll work with var entries = grunt.file.expand(config.entries); <del> var bundle = browserify(entries); // Make sure the things that need to be exposed are. var requires = config.requires || {}; if (requires instanceof Array) { grunt.file.expand({ nonull: true, // Keep IDs that don't expand to anything. cwd: "src" }, requires).forEach(function(name) { bundle.require("./build/modules/" + name, { expose: name.replace(/.js$/i, "") }); }); } else if (typeof requires === "object") { Object.keys(requires).forEach(function(name) { bundle.require(requires[name], { expose: name }); }); } </del> // Extract other options var options = { <ins> entries: entries, </ins> debug: config.debug, // sourcemaps standalone: config.standalone // global }; <del> // TODO: make sure this works, test with this too </del> <ins> var bundle = browserify(options); </ins> config.transforms.forEach(function(transform) { bundle.transform({}, transform); }); // Actually bundle it up var _this = this; <del> bundle.bundle(options, function(err, src) { </del> <ins> bundle.bundle(function(err, buf) { </ins> if (err) { grunt.log.error(err); <del> done(); </del> <ins> return done(); </ins> } <ins> var src = buf.toString(); </ins> config.after.forEach(function(fn) { src = fn.call(_this, src); });


"node": ">=0.10.0" }, "dependencies": { <del> "envify": "^2.0.0" </del> <ins> "envify": "^3.0.0" </ins> }, "browserify": { "transform": ["envify"]


"dependencies": { "commoner": "^0.10.0", "esprima-fb": "^6001.1.0-dev-harmony-fb", <del> "jstransform": "^6.2.0" </del> <ins> "jstransform": "^6.3.2" </ins> }, "devDependencies": { "benchmark": "~1.0.0", <del> "browserify": "^4.1.10", </del> <ins> "browserify": "^6.1.0", </ins> "coverify": "~1.0.4", <del> "envify": "^2.0.0", </del> <ins> "derequire": "^1.2.0", "envify": "^3.0.0", </ins> "es3ify": "~0.1.2", "es5-shim": "^4.0.0", "grunt": "~0.4.2", "grunt-cli": "~0.1.9", "grunt-compare-size": "~0.4.0", <del> "grunt-contrib-clean": "~0.5.0", "grunt-contrib-compress": "^0.9.1", </del> <ins> "grunt-contrib-clean": "^0.6.0", "grunt-contrib-compress": "^0.12.0", </ins> "grunt-contrib-connect": "~0.6.0", <del> "grunt-contrib-copy": "~0.5.0", </del> <ins> "grunt-contrib-copy": "^0.6.0", </ins> "grunt-contrib-jshint": "^0.10.0", "gzip-js": "~0.3.2", "jasmine-tapreporter": "~0.2.2", "jest-cli": "~0.1.5", "lodash": "~2.4.1", <del> "microtime": "^0.6.0", </del> "optimist": "~0.6.0", "phantomjs": "~1.9", "platform": "^1.1.0", "populist": "~0.1.6", <del> "recast": "^0.6.10", </del> <ins> "recast": "^0.7.2", </ins> "sauce-tunnel": "~1.1.0", <del> "semver": "^2.3.0", </del> "tmp": "~0.0.18", "uglify-js": "~2.4.0", "uglifyify": "^2.4.0",


"rootDir": "", "scriptPreprocessor": "jest/preprocessor.js", "setupEnvScriptFile": "jest/environment.js", <del> "modulePathIgnorePatterns": ["/build/", "/node_modules/", "/.module-cache/"], "testPathIgnorePatterns": ["/build/", "/node_modules/"], "unmockedModulePathPatterns": [""] </del> <ins> "modulePathIgnorePatterns": [ "/build/", "/node_modules/", "/.module-cache/" ], "testPathIgnorePatterns": [ "/build/", "/node_modules/" ], "unmockedModulePathPatterns": [ "" ] </ins> } }


topLevelTypes.topContextMenu, topLevelTypes.topFocus, topLevelTypes.topKeyDown, <ins> topLevelTypes.topKeyUp, </ins> topLevelTypes.topMouseDown, topLevelTypes.topMouseUp, topLevelTypes.topSelectionChange,


It is a good idea to avoid spamming the console with duplicate warnings: <del> ````js </del> <ins> ```js </ins> var warning = require('warning'); var didWarnAboutMath = false;


In a traditional JavaScript application, you need to look at what data changed and imperatively make changes to the DOM to keep it up-to-date. Even AngularJS, <del> which provides a declarative interface via directives and data binding requires a linking function to manually update DOM nodes. </del> <ins> which provides a declarative interface via directives and data binding [requires a linking function to manually update DOM nodes](http://docs.angularjs.org/guide/directive#reasonsbehindthecompilelinkseparation). </ins> React takes a different approach.


- Facebook has dynamic charts that render to `<canvas>` instead of HTML. - Instagram is a "single page" web app built entirely with React and `Backbone.Router`. Designers regularly contribute React code with JSX. <del> - We've built an internal prototype that runs React apps in a web worker. </del> <ins> - We've built internal prototypes that run React apps in a web worker and use React to drive **native iOS views** via an Objective-C bridge. </ins> - You can run React [on the server](http://github.com/petehunt/react-server-rendering) for SEO, performance, code sharing and overall flexibility.


ReactCache = require('react-cache'); Suspense = React.Suspense; container = document.createElement('div'); <ins> document.body.appendChild(container); </ins> TextResource = ReactCache.unstable_createResource(([text, ms = 0]) => { return new Promise((resolve, reject) =>


}, ([text, ms]) => text); }); <ins> afterEach(() => { document.body.removeChild(container); }); </ins> function advanceTimers(ms) { // Note: This advances Jest's virtual time but not React's. Use // ReactNoop.expire for that.


); }, ); <ins> // Regression test for https://github.com/facebook/react/issues/14188 it('can call findDOMNode() in a suspended component commit phase', async () => { const log = []; const Lazy = React.lazy( () => new Promise(resolve => resolve({ default() { return 'lazy'; }, }), ), ); class Child extends React.Component { componentDidMount() { log.push('cDM ' + this.props.id); ReactDOM.findDOMNode(this); } componentDidUpdate() { log.push('cDU ' + this.props.id); ReactDOM.findDOMNode(this); } render() { return 'child'; } } const buttonRef = React.createRef(); class App extends React.Component { state = { suspend: false, }; handleClick = () => { this.setState({suspend: true}); }; render() { return ( <React.Suspense fallback="Loading"> <Child id="first" /> <button ref={buttonRef} onClick={this.handleClick}> Suspend </button> <Child id="second" /> {this.state.suspend && <Lazy />} </React.Suspense> ); } } ReactDOM.render(<App />, container); expect(log).toEqual(['cDM first', 'cDM second']); log.length = 0; buttonRef.current.dispatchEvent(new MouseEvent('click', {bubbles: true})); await Lazy; expect(log).toEqual(['cDU first', 'cDU second']); }); </ins> });


Scheduler.flushAll(); expect(root).toMatchRenderedOutput('hello'); }); <ins> // Regression test for https://github.com/facebook/react/issues/15732 it('resets hooks when an error is thrown in the middle of a list of hooks', async () => { const {useEffect, useState} = React; class ErrorBoundary extends React.Component { state = {hasError: false}; static getDerivedStateFromError() { return {hasError: true}; } render() { return ( <Wrapper> {this.state.hasError ? 'Error!' : this.props.children} </Wrapper> ); } } function Wrapper({children}) { return children; } let setShouldThrow; function Thrower() { const [shouldThrow, _setShouldThrow] = useState(false); setShouldThrow = _setShouldThrow; if (shouldThrow) { throw new Error('Throw!'); } useEffect(() => {}, []); return 'Throw!'; } const root = ReactTestRenderer.create( <ErrorBoundary> <Thrower /> </ErrorBoundary>, ); expect(root).toMatchRenderedOutput('Throw!'); act(() => setShouldThrow(true)); expect(root).toMatchRenderedOutput('Error!'); }); </ins> });


} case Profiler: if (enableProfilerTimer) { <del> workInProgress.effectTag |= Update; </del> <ins> // Profiler should only call onRender when one of its descendants actually rendered. const hasChildWork = workInProgress.childExpirationTime >= renderExpirationTime; if (hasChildWork) { workInProgress.effectTag |= Update; } </ins> } break; case SuspenseComponent: {


); }); <ins> it('does not report work done on a sibling', () => { const callback = jest.fn(); const DoesNotUpdate = React.memo(function DoesNotUpdateInner() { Scheduler.unstable_advanceTime(10); return null; }, () => true); let updateProfilerSibling; function ProfilerSibling() { const [count, setCount] = React.useState(0); updateProfilerSibling = () => setCount(count + 1); return null; } function App() { return ( <React.Fragment> <React.Profiler id="test" onRender={callback}> <DoesNotUpdate /> </React.Profiler> <ProfilerSibling /> </React.Fragment> ); } const renderer = ReactTestRenderer.create(<App />); expect(callback).toHaveBeenCalledTimes(1); let call = callback.mock.calls[0]; expect(call).toHaveLength(enableSchedulerTracing ? 7 : 6); expect(call[0]).toBe('test'); expect(call[1]).toBe('mount'); expect(call[2]).toBe(10); // actual time expect(call[3]).toBe(10); // base time expect(call[4]).toBe(0); // start time expect(call[5]).toBe(10); // commit time expect(call[6]).toEqual(enableSchedulerTracing ? new Set() : undefined); // interaction events callback.mockReset(); Scheduler.unstable_advanceTime(20); // 10 -> 30 // Updating a parent should report a re-render, // since React technically did a little bit of work between the Profiler and the bailed out subtree. renderer.update(<App />); expect(callback).toHaveBeenCalledTimes(1); call = callback.mock.calls[0]; expect(call).toHaveLength(enableSchedulerTracing ? 7 : 6); expect(call[0]).toBe('test'); expect(call[1]).toBe('update'); expect(call[2]).toBe(0); // actual time expect(call[3]).toBe(10); // base time expect(call[4]).toBe(30); // start time expect(call[5]).toBe(30); // commit time expect(call[6]).toEqual(enableSchedulerTracing ? new Set() : undefined); // interaction events callback.mockReset(); Scheduler.unstable_advanceTime(20); // 30 -> 50 // Updating a sibling should not report a re-render. ReactTestRenderer.act(updateProfilerSibling); expect(callback).not.toHaveBeenCalled(); }); </ins> it('logs render times for both mount and update', () => { const callback = jest.fn();


Scheduler.unstable_advanceTime(5); // 0 -> 5 ReactTestRenderer.create( <del> <> </del> <ins> <React.Fragment> </ins> <React.Profiler id="parent" onRender={callback}> <AdvanceTime byAmount={10}> <React.Profiler id="child" onRender={callback}>


</React.Profiler> </AdvanceTime> </React.Profiler> <del> </>, </del> <ins> </React.Fragment>, </ins> ); expect(callback).toHaveBeenCalledTimes(2);


Scheduler.unstable_advanceTime(5); // 0 -> 5 ReactTestRenderer.create( <del> <> </del> <ins> <React.Fragment> </ins> <React.Profiler id="first" onRender={callback}> <AdvanceTime byAmount={20} /> </React.Profiler> <React.Profiler id="second" onRender={callback}> <AdvanceTime byAmount={5} /> </React.Profiler> <del> </>, </del> <ins> </React.Fragment>, </ins> ); expect(callback).toHaveBeenCalledTimes(2);


Scheduler.unstable_advanceTime(5); // 0 -> 5 ReactTestRenderer.create( <del> <> </del> <ins> <React.Fragment> </ins> <AdvanceTime byAmount={20} /> <React.Profiler id="test" onRender={callback}> <AdvanceTime byAmount={5} /> </React.Profiler> <AdvanceTime byAmount={20} /> <del> </>, </del> <ins> </React.Fragment>, </ins> ); expect(callback).toHaveBeenCalledTimes(1);


} } <del> class Pure extends React.PureComponent { render() { return this.props.children; } } </del> const renderer = ReactTestRenderer.create( <React.Profiler id="outer" onRender={callback}> <Updater> <del> <React.Profiler id="middle" onRender={callback}> <Pure> <React.Profiler id="inner" onRender={callback}> <div /> </React.Profiler> </Pure> </del> <ins> <React.Profiler id="inner" onRender={callback}> <div /> </ins> </React.Profiler> </Updater> </React.Profiler>, ); // All profile callbacks are called for initial render <del> expect(callback).toHaveBeenCalledTimes(3); </del> <ins> expect(callback).toHaveBeenCalledTimes(2); </ins> callback.mockReset();


}); }); <del> // Only call profile updates for paths that have re-rendered // Since "inner" is beneath a pure component, it isn't called expect(callback).toHaveBeenCalledTimes(2); expect(callback.mock.calls[0][0]).toBe('middle'); expect(callback.mock.calls[1][0]).toBe('outer'); </del> <ins> // Only call onRender for paths that have re-rendered. // Since the Updater's props didn't change, // React does not re-render its children. expect(callback).toHaveBeenCalledTimes(1); expect(callback.mock.calls[0][0]).toBe('outer'); </ins> }); it('decreases actual time but not base time when sCU prevents an update', () => {


render() { instance = this; return ( <del> <> </del> <ins> <React.Fragment> </ins> <Yield value="first" /> {this.state.count} <Yield value="last" /> <del> </> </del> <ins> </React.Fragment> </ins> ); } }


); if (__DEV__) { const inst = workInProgress.stateNode; <del> if (inst.props !== nextProps) { </del> <ins> if (shouldUpdate && inst.props !== nextProps) { </ins> if (!didWarnAboutReassigningProps) { console.error( 'It looks like %s is reassigning its own `this.props` while rendering. ' +


cloneUpdateQueue(current, workInProgress); <del> const oldProps = workInProgress.memoizedProps; instance.props = </del> <ins> const unresolvedOldProps = workInProgress.memoizedProps; const oldProps = </ins> workInProgress.type === workInProgress.elementType <del> ? oldProps : resolveDefaultProps(workInProgress.type, oldProps); </del> <ins> ? unresolvedOldProps : resolveDefaultProps(workInProgress.type, unresolvedOldProps); instance.props = oldProps; const unresolvedNewProps = workInProgress.pendingProps; </ins> const oldContext = instance.context; const contextType = ctor.contextType;


(typeof instance.UNSAFE_componentWillReceiveProps === 'function' || typeof instance.componentWillReceiveProps === 'function') ) { <del> if (oldProps !== newProps || oldContext !== nextContext) { </del> <ins> if ( unresolvedOldProps !== unresolvedNewProps || oldContext !== nextContext ) { </ins> callComponentWillReceiveProps( workInProgress, instance,


newState = workInProgress.memoizedState; if ( <del> oldProps === newProps && </del> <ins> unresolvedOldProps === unresolvedNewProps && </ins> oldState === newState && !hasContextChanged() && !checkHasForceUpdateAfterProcessing()


// effect even though we're bailing out, so that cWU/cDU are called. if (typeof instance.componentDidUpdate === 'function') { if ( <del> oldProps !== current.memoizedProps || </del> <ins> unresolvedOldProps !== current.memoizedProps || </ins> oldState !== current.memoizedState ) { workInProgress.effectTag |= Update;


} if (typeof instance.getSnapshotBeforeUpdate === 'function') { if ( <del> oldProps !== current.memoizedProps || </del> <ins> unresolvedOldProps !== current.memoizedProps || </ins> oldState !== current.memoizedState ) { workInProgress.effectTag |= Snapshot;


expect(root).toMatchRenderedOutput('SiblingB'); }); <ins> it('resolves defaultProps without breaking bailout due to unchanged props and state, #17151', async () => { class LazyImpl extends React.Component { static defaultProps = {value: 0}; render() { const text = `${this.props.label}: ${this.props.value}`; return <Text text={text} />; } } const Lazy = lazy(() => fakeImport(LazyImpl)); const instance1 = React.createRef(null); const instance2 = React.createRef(null); const root = ReactTestRenderer.create( <> <LazyImpl ref={instance1} label="Not lazy" /> <Suspense fallback={<Text text="Loading..." />}> <Lazy ref={instance2} label="Lazy" /> </Suspense> </>, { unstable_isConcurrent: true, }, ); expect(Scheduler).toFlushAndYield(['Not lazy: 0', 'Loading...']); expect(root).not.toMatchRenderedOutput('Not lazy: 0Lazy: 0'); await Promise.resolve(); expect(Scheduler).toFlushAndYield(['Lazy: 0']); expect(root).toMatchRenderedOutput('Not lazy: 0Lazy: 0'); // Should bailout due to unchanged props and state instance1.current.setState(null); expect(Scheduler).toFlushAndYield([]); expect(root).toMatchRenderedOutput('Not lazy: 0Lazy: 0'); // Should bailout due to unchanged props and state instance2.current.setState(null); expect(Scheduler).toFlushAndYield([]); expect(root).toMatchRenderedOutput('Not lazy: 0Lazy: 0'); }); it('resolves defaultProps without breaking bailout in PureComponent, #17151', async () => { class LazyImpl extends React.PureComponent { static defaultProps = {value: 0}; state = {}; render() { const text = `${this.props.label}: ${this.props.value}`; return <Text text={text} />; } } const Lazy = lazy(() => fakeImport(LazyImpl)); const instance1 = React.createRef(null); const instance2 = React.createRef(null); const root = ReactTestRenderer.create( <> <LazyImpl ref={instance1} label="Not lazy" /> <Suspense fallback={<Text text="Loading..." />}> <Lazy ref={instance2} label="Lazy" /> </Suspense> </>, { unstable_isConcurrent: true, }, ); expect(Scheduler).toFlushAndYield(['Not lazy: 0', 'Loading...']); expect(root).not.toMatchRenderedOutput('Not lazy: 0Lazy: 0'); await Promise.resolve(); expect(Scheduler).toFlushAndYield(['Lazy: 0']); expect(root).toMatchRenderedOutput('Not lazy: 0Lazy: 0'); // Should bailout due to shallow equal props and state instance1.current.setState({}); expect(Scheduler).toFlushAndYield([]); expect(root).toMatchRenderedOutput('Not lazy: 0Lazy: 0'); // Should bailout due to shallow equal props and state instance2.current.setState({}); expect(Scheduler).toFlushAndYield([]); expect(root).toMatchRenderedOutput('Not lazy: 0Lazy: 0'); }); </ins> it('sets defaultProps for modern lifecycles', async () => { class C extends React.Component { static defaultProps = {text: 'A'};


const nodeRequire = module && module[requireString]; // assuming we're in node, let's try to get node's // version of setImmediate, bypassing fake timers if any. <del> enqueueTaskImpl = nodeRequire('timers').setImmediate; </del> <ins> enqueueTaskImpl = nodeRequire.call(module, 'timers').setImmediate; </ins> } catch (_err) { // we're in a browser // we can't use regular timers because they may still be faked


return JSON.parse(raw); } } catch (error) {} <del> return true; </del> <ins> return false; </ins> } export function setBreakOnConsoleErrors(value: boolean): void {


} function mountFiberRecursively( <del> fiber: Fiber, </del> <ins> firstChild: Fiber, </ins> parentFiber: Fiber | null, traverseSiblings: boolean, traceNearestHostComponentUpdate: boolean, ) { <del> if (__DEBUG__) { debug('mountFiberRecursively()', fiber, parentFiber); } </del> <ins> // Iterate over siblings rather than recursing. // This reduces the chance of stack overflow for wide trees (e.g. lists with many items). let fiber: Fiber | null = firstChild; while (fiber !== null) { if (__DEBUG__) { debug('mountFiberRecursively()', fiber, parentFiber); } </ins> <del> // If we have the tree selection from previous reload, try to match this Fiber. // Also remember whether to do the same for siblings. const mightSiblingsBeOnTrackedPath = updateTrackedPathStateBeforeMount( fiber, ); </del> <ins> // If we have the tree selection from previous reload, try to match this Fiber. // Also remember whether to do the same for siblings. const mightSiblingsBeOnTrackedPath = updateTrackedPathStateBeforeMount( fiber, ); </ins> <del> const shouldIncludeInTree = !shouldFilterFiber(fiber); if (shouldIncludeInTree) { recordMount(fiber, parentFiber); } </del> <ins> const shouldIncludeInTree = !shouldFilterFiber(fiber); if (shouldIncludeInTree) { recordMount(fiber, parentFiber); } </ins> <del> if (traceUpdatesEnabled) { if (traceNearestHostComponentUpdate) { const elementType = getElementTypeForFiber(fiber); // If an ancestor updated, we should mark the nearest host nodes for highlighting. if (elementType === ElementTypeHostComponent) { traceUpdatesForNodes.add(fiber.stateNode); traceNearestHostComponentUpdate = false; </del> <ins> if (traceUpdatesEnabled) { if (traceNearestHostComponentUpdate) { const elementType = getElementTypeForFiber(fiber); // If an ancestor updated, we should mark the nearest host nodes for highlighting. if (elementType === ElementTypeHostComponent) { traceUpdatesForNodes.add(fiber.stateNode); traceNearestHostComponentUpdate = false; } </ins> } <del> } // We intentionally do not re-enable the traceNearestHostComponentUpdate flag in this branch, // because we don't want to highlight every host node inside of a newly mounted subtree. } </del> <ins> // We intentionally do not re-enable the traceNearestHostComponentUpdate flag in this branch, // because we don't want to highlight every host node inside of a newly mounted subtree. } </ins> <del> const isSuspense = fiber.tag === ReactTypeOfWork.SuspenseComponent; if (isSuspense) { const isTimedOut = fiber.memoizedState !== null; if (isTimedOut) { // Special case: if Suspense mounts in a timed-out state, // get the fallback child from the inner fragment and mount // it as if it was our own child. Updates handle this too. const primaryChildFragment = fiber.child; const fallbackChildFragment = primaryChildFragment ? primaryChildFragment.sibling : null; const fallbackChild = fallbackChildFragment ? fallbackChildFragment.child : null; if (fallbackChild !== null) { mountFiberRecursively( fallbackChild, shouldIncludeInTree ? fiber : parentFiber, true, traceNearestHostComponentUpdate, ); </del> <ins> const isSuspense = fiber.tag === ReactTypeOfWork.SuspenseComponent; if (isSuspense) { const isTimedOut = fiber.memoizedState !== null; if (isTimedOut) { // Special case: if Suspense mounts in a timed-out state, // get the fallback child from the inner fragment and mount // it as if it was our own child. Updates handle this too. const primaryChildFragment = fiber.child; const fallbackChildFragment = primaryChildFragment ? primaryChildFragment.sibling : null; const fallbackChild = fallbackChildFragment ? fallbackChildFragment.child : null; if (fallbackChild !== null) { mountFiberRecursively( fallbackChild, shouldIncludeInTree ? fiber : parentFiber, true, traceNearestHostComponentUpdate, ); } } else { let primaryChild: Fiber | null = null; const areSuspenseChildrenConditionallyWrapped = OffscreenComponent === -1; if (areSuspenseChildrenConditionallyWrapped) { primaryChild = fiber.child; } else if (fiber.child !== null) { primaryChild = fiber.child.child; } if (primaryChild !== null) { mountFiberRecursively( primaryChild, shouldIncludeInTree ? fiber : parentFiber, true, traceNearestHostComponentUpdate, ); } </ins> } } else { <del> let primaryChild: Fiber | null = null; const areSuspenseChildrenConditionallyWrapped = OffscreenComponent === -1; if (areSuspenseChildrenConditionallyWrapped) { primaryChild = fiber.child; } else if (fiber.child !== null) { primaryChild = fiber.child.child; } if (primaryChild !== null) { </del> <ins> if (fiber.child !== null) { </ins> mountFiberRecursively( <del> primaryChild, </del> <ins> fiber.child, </ins> shouldIncludeInTree ? fiber : parentFiber, true, traceNearestHostComponentUpdate, ); } } <del> } else { if (fiber.child !== null) { mountFiberRecursively( fiber.child, shouldIncludeInTree ? fiber : parentFiber, true, traceNearestHostComponentUpdate, ); } } // We're exiting this Fiber now, and entering its siblings. // If we have selection to restore, we might need to re-activate tracking. updateTrackedPathStateAfterMount(mightSiblingsBeOnTrackedPath); </del> <ins> // We're exiting this Fiber now, and entering its siblings. // If we have selection to restore, we might need to re-activate tracking. updateTrackedPathStateAfterMount(mightSiblingsBeOnTrackedPath); </ins> <del> if (traverseSiblings && fiber.sibling !== null) { mountFiberRecursively( fiber.sibling, parentFiber, true, traceNearestHostComponentUpdate, ); </del> <ins> fiber = traverseSiblings ? fiber.sibling : null; </ins> } }


expect(store).toMatchSnapshot('2: add host nodes'); }); <ins> // This test is not the same cause as what's reported on GitHub, // but the resulting behavior (owner mounting after descendant) is the same. // Thec ase below is admittedly contrived and relies on side effects. // I'mnot yet sure of how to reduce the GitHub reported production case to a test though. // See https://github.com/facebook/react/issues/21445 it('should handle when a component mounts before its owner', () => { const promise = new Promise(resolve => {}); let Dynamic = null; const Owner = () => { Dynamic = <Child />; throw promise; }; const Parent = () => { return Dynamic; }; const Child = () => null; const container = document.createElement('div'); act(() => ReactDOM.render( <> <React.Suspense fallback="Loading..."> <Owner /> </React.Suspense> <Parent /> </>, container, ), ); expect(store).toMatchInlineSnapshot(` [root] <Suspense> ▾ <Parent> <Child> `); }); </ins> describe('collapseNodesByDefault:false', () => { beforeEach(() => { store.collapseNodesByDefault = false;


const elementType = getElementTypeForFiber(fiber); const {_debugOwner} = fiber; <del> const ownerID = _debugOwner != null ? getFiberIDThrows(_debugOwner) : 0; </del> <ins> // Ideally we should call getFiberIDThrows() for _debugOwner, // since owners are almost always higher in the tree (and so have already been processed), // but in some (rare) instances reported in open source, a descendant mounts before an owner. // Since this is a DEV only field it's probably okay to also just lazily generate and ID here if needed. // See https://github.com/facebook/react/issues/21445 const ownerID = _debugOwner != null ? getOrGenerateFiberID(_debugOwner) : 0; </ins> const parentID = parentFiber ? getFiberIDThrows(parentFiber) : 0; const displayNameStringID = getStringID(displayName);


return false; } <ins> // Column numbers are representated differently between tools/engines. // Error.prototype.stack columns are 1-based (like most IDEs) but ASTs are 0-based. // // In practice this will probably never matter, // because this code matches the 1-based Error stack location for the hook Identifier (e.g. useState) // with the larger 0-based VariableDeclarator (e.g. [foo, setFoo] = useState()) // so the ranges should always overlap. // // For more info see https://github.com/facebook/react/pull/21833#discussion_r666831276 column -= 1; </ins> if ( (line === start.line && column < start.column) || (line === end.line && column > end.column)


line: lineNumber, // Column numbers are representated differently between tools/engines. <ins> // Error.prototype.stack columns are 1-based (like most IDEs) but ASTs are 0-based. </ins> // For more info see https://github.com/facebook/react/issues/21792#issuecomment-873171991 column: columnNumber - 1, });


<ins> ## 4.4.0 * No changes, this was an automated release together with React 18. </ins> ## 4.3.0 * Support ESLint 8. ([@MichaelDeBoey](https://github.com/MichaelDeBoey) in [#22248](https://github.com/facebook/react/pull/22248))


The examples in the React repository are declared a bit differently than a third-party renderer would be. In particular, the `HostConfig` object mentioned above is never explicitly declared, and instead is a *module* in our code. However, its exports correspond directly to properties on a `HostConfig` object you'd need to declare in your code: * [React ART](https://github.com/facebook/react/blob/main/packages/react-art/src/ReactART.js) and its [host config](https://github.com/facebook/react/blob/main/packages/react-art/src/ReactARTHostConfig.js) <del> * [React DOM](https://github.com/facebook/react/blob/main/packages/react-dom/src/client/ReactDOM.js) and its [host config](https://github.com/facebook/react/blob/main/packages/react-dom/src/client/ReactDOMHostConfig.js) </del> <ins> * [React DOM](https://github.com/facebook/react/blob/main/packages/react-dom/src/client/ReactDOM.js) and its [host config](https://github.com/facebook/react/blob/main/packages/react-dom-bindings/src/client/ReactDOMHostConfig.js) </ins> * [React Native](https://github.com/facebook/react/blob/main/packages/react-native-renderer/src/ReactNativeRenderer.js) and its [host config](https://github.com/facebook/react/blob/main/packages/react-native-renderer/src/ReactNativeHostConfig.js) If these links break please file an issue and we’ll fix them. They intentionally link to the latest versions since the API is still evolving. If you have more questions please file an issue and we’ll try to help!


<del> /** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * * @providesModule ReactNativeGlobalInteractionHandler * @flow */ 'use strict'; var InteractionManager = require('InteractionManager'); // Interaction handle is created/cleared when responder is granted or // released/terminated. var interactionHandle = null; var ReactNativeGlobalInteractionHandler = { onChange: function(numberActiveTouches: number) { if (numberActiveTouches === 0) { if (interactionHandle) { InteractionManager.clearInteractionHandle(interactionHandle); interactionHandle = null; } } else if (!interactionHandle) { interactionHandle = InteractionManager.createInteractionHandle(); } }, }; module.exports = ReactNativeGlobalInteractionHandler; </del>