1/* eslint-disable react/react-in-jsx-scope, react/jsx-no-undef */2/* global React ReactCache ReactDOM SchedulerTracing ScheduleTracing */34const apps = [];56const pieces = React.version.split('.');7const major =8 pieces[0] === '0' ? parseInt(pieces[1], 10) : parseInt(pieces[0], 10);9const minor =10 pieces[0] === '0' ? parseInt(pieces[2], 10) : parseInt(pieces[1], 10);1112// Convenience wrapper to organize API features in DevTools.13function Feature({children, label, version}) {14 return (15 <div className="Feature">16 <div className="FeatureHeader">17 <code className="FeatureCode">{label}</code>18 <small>{version}</small>19 </div>20 {children}21 </div>22 );23}2425// Simplify interaction tracing for tests below.26let trace = null;27if (typeof SchedulerTracing !== 'undefined') {28 trace = SchedulerTracing.unstable_trace;29} else if (typeof ScheduleTracing !== 'undefined') {30 trace = ScheduleTracing.unstable_trace;31} else {32 trace = (_, __, callback) => callback();33}3435// https://github.com/facebook/react/blob/main/CHANGELOG.md36switch (major) {37 case 16:38 switch (minor) {39 case 7:40 if (typeof React.useState === 'function') {41 // Hooks42 function Hooks() {43 const [count, setCount] = React.useState(0);44 const incrementCount = React.useCallback(45 () => setCount(count + 1),46 [count]47 );48 return (49 <div>50 count: {count}{' '}51 <button onClick={incrementCount}>increment</button>52 </div>53 );54 }55 apps.push(56 <Feature key="Hooks" label="Hooks" version="16.7+">57 <Hooks />58 </Feature>59 );60 }61 case 6:62 // memo63 function LabelComponent({label}) {64 return <label>{label}</label>;65 }66 const AnonymousMemoized = React.memo(({label}) => (67 <label>{label}</label>68 ));69 const Memoized = React.memo(LabelComponent);70 const CustomMemoized = React.memo(LabelComponent);71 CustomMemoized.displayName = 'MemoizedLabelFunction';72 apps.push(73 <Feature key="memo" label="memo" version="16.6+">74 <AnonymousMemoized label="AnonymousMemoized" />75 <Memoized label="Memoized" />76 <CustomMemoized label="CustomMemoized" />77 </Feature>78 );7980 // Suspense81 const loadResource = ([text, ms]) => {82 return new Promise((resolve, reject) => {83 setTimeout(() => {84 resolve(text);85 }, ms);86 });87 };88 const getResourceKey = ([text, ms]) => text;89 const Resource = ReactCache.unstable_createResource(90 loadResource,91 getResourceKey92 );93 class Suspending extends React.Component {94 state = {useSuspense: false};95 useSuspense = () => this.setState({useSuspense: true});96 render() {97 if (this.state.useSuspense) {98 const text = Resource.read(['loaded', 2000]);99 return text;100 } else {101 return <button onClick={this.useSuspense}>load data</button>;102 }103 }104 }105 apps.push(106 <Feature key="Suspense" label="Suspense" version="16.6+">107 <React.Suspense fallback={<div>loading...</div>}>108 <Suspending />109 </React.Suspense>110 </Feature>111 );112113 // lazy114 const LazyWithDefaultProps = React.lazy(115 () =>116 new Promise(resolve => {117 function FooWithDefaultProps(props) {118 return (119 <h1>120 {props.greeting}, {props.name}121 </h1>122 );123 }124 FooWithDefaultProps.defaultProps = {125 name: 'World',126 greeting: 'Bonjour',127 };128 resolve({129 default: FooWithDefaultProps,130 });131 })132 );133 apps.push(134 <Feature key="lazy" label="lazy" version="16.6+">135 <React.Suspense fallback={<div>loading...</div>}>136 <LazyWithDefaultProps greeting="Hello" />137 </React.Suspense>138 </Feature>139 );140 case 5:141 case 4:142 // unstable_Profiler143 class ProfilerChild extends React.Component {144 state = {count: 0};145 incrementCount = () =>146 this.setState(prevState => ({count: prevState.count + 1}));147 render() {148 return (149 <div>150 count: {this.state.count}{' '}151 <button onClick={this.incrementCount}>increment</button>152 </div>153 );154 }155 }156 const onRender = (...args) => {};157 const Profiler = React.unstable_Profiler || React.Profiler;158 apps.push(159 <Feature160 key="unstable_Profiler"161 label="unstable_Profiler"162 version="16.4+">163 <Profiler id="count" onRender={onRender}>164 <div>165 <ProfilerChild />166 </div>167 </Profiler>168 </Feature>169 );170 case 3:171 // createContext()172 const LocaleContext = React.createContext();173 LocaleContext.displayName = 'LocaleContext';174 const ThemeContext = React.createContext();175 apps.push(176 <Feature key="createContext" label="createContext" version="16.3+">177 <ThemeContext.Provider value="blue">178 <ThemeContext.Consumer>179 {theme => <div>theme: {theme}</div>}180 </ThemeContext.Consumer>181 </ThemeContext.Provider>182 <LocaleContext.Provider value="en-US">183 <LocaleContext.Consumer>184 {locale => <div>locale: {locale}</div>}185 </LocaleContext.Consumer>186 </LocaleContext.Provider>187 </Feature>188 );189190 // forwardRef()191 const AnonymousFunction = React.forwardRef((props, ref) => (192 <div ref={ref}>{props.children}</div>193 ));194 const NamedFunction = React.forwardRef(function named(props, ref) {195 return <div ref={ref}>{props.children}</div>;196 });197 const CustomName = React.forwardRef((props, ref) => (198 <div ref={ref}>{props.children}</div>199 ));200 CustomName.displayName = 'CustomNameForwardRef';201 apps.push(202 <Feature key="forwardRef" label="forwardRef" version="16.3+">203 <AnonymousFunction>AnonymousFunction</AnonymousFunction>204 <NamedFunction>NamedFunction</NamedFunction>205 <CustomName>CustomName</CustomName>206 </Feature>207 );208209 // StrictMode210 class StrictModeChild extends React.Component {211 render() {212 return 'StrictModeChild';213 }214 }215 apps.push(216 <Feature key="StrictMode" label="StrictMode" version="16.3+">217 <React.StrictMode>218 <StrictModeChild />219 </React.StrictMode>220 </Feature>221 );222223 // unstable_AsyncMode (later renamed to unstable_ConcurrentMode, then ConcurrentMode)224 const ConcurrentMode =225 React.ConcurrentMode ||226 React.unstable_ConcurrentMode ||227 React.unstable_AsyncMode;228 apps.push(229 <Feature230 key="AsyncMode/ConcurrentMode"231 label="AsyncMode/ConcurrentMode"232 version="16.3+">233 <ConcurrentMode>234 <div>235 unstable_AsyncMode was added in 16.3, renamed to236 unstable_ConcurrentMode in 16.5, and then renamed to237 ConcurrentMode in 16.7238 </div>239 </ConcurrentMode>240 </Feature>241 );242 case 2:243 // Fragment244 apps.push(245 <Feature key="Fragment" label="Fragment" version="16.4+">246 <React.Fragment>247 <div>one</div>248 <div>two</div>249 </React.Fragment>250 </Feature>251 );252 case 1:253 case 0:254 default:255 break;256 }257 break;258 case 15:259 break;260 case 14:261 break;262 default:263 break;264}265266function Even() {267 return <small>(even)</small>;268}269270// Simple stateful app shared by all React versions271class SimpleApp extends React.Component {272 state = {count: 0};273 incrementCount = () => {274 const updaterFn = prevState => ({count: prevState.count + 1});275 trace('Updating count', performance.now(), () => this.setState(updaterFn));276 };277 render() {278 const {count} = this.state;279 return (280 <div>281 {count % 2 === 0 ? (282 <span>283 count: {count} <Even />284 </span>285 ) : (286 <span>count: {count}</span>287 )}{' '}288 <button onClick={this.incrementCount}>increment</button>289 </div>290 );291 }292}293apps.push(294 <Feature key="Simple stateful app" label="Simple stateful app" version="any">295 <SimpleApp />296 </Feature>297);298299// This component, with the version prop, helps organize DevTools at a glance.300function TopLevelWrapperForDevTools({version}) {301 let header = <h1>React {version}</h1>;302 if (version.includes('canary')) {303 const commitSha = version.match(/.+canary-(.+)/)[1];304 header = (305 <h1>306 React canary{' '}307 <a href={`https://github.com/facebook/react/commit/${commitSha}`}>308 {commitSha}309 </a>310 </h1>311 );312 } else if (version.includes('alpha')) {313 header = <h1>React next</h1>;314 }315316 return (317 <div>318 {header}319 {apps}320 </div>321 );322}323TopLevelWrapperForDevTools.displayName = 'React';324325ReactDOM.render(326 <TopLevelWrapperForDevTools version={React.version} />,327 document.getElementById('root')328);
Findings
✓ No findings reported for this file.