Refactor class components to functional @ examples (#13398)

**Affected examples**

with-segment-analytics
with-slate
with-portals-ssr ( _with-portals-ssr is based on a package not being updated in the last year_)
with-videojs
with-next-page-transitions
with-firebase-cloud-messaging
with-dynamic-app-layout
with-dynamic-import
with-next-transition
with-carbon-components
with-cerebral
with-custom-babel-config

Here and there I have removed some redundant imports as well. I believe with this PR, there are only 1 or 2 examples left using class-based components. If by any chance you find any, let me know and I'll refactor them too.

If you don't like anything or you want me to change something, please let me know.

**If there is anything else you'd like me to help with, I would be honored to assist.**
This commit is contained in:
TodorTotev 2020-05-27 08:14:26 +03:00 committed by GitHub
parent dcf446d83d
commit 4a02dc5a17
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 247 additions and 301 deletions

View file

@ -1,12 +1,11 @@
import { Component, Fragment } from 'react'
import { Button } from 'carbon-components-react'
export default class DemoApp extends Component {
render() {
return (
<Fragment>
<Button>Hello, world!</Button>
</Fragment>
)
}
const Home = () => {
return (
<>
<Button>Hello, world!</Button>
</>
)
}
export default Home

View file

@ -1,29 +1,26 @@
import { Component } from 'react'
import { Controller } from 'cerebral'
import Devtools from 'cerebral/devtools'
import { Container } from '@cerebral/react'
import Page from '../components/Page'
import clock from '../modules/clock'
export default class Counter extends Component {
constructor(props) {
super(props)
// The controller will be instantiated for every page change and we only
// add the devtools if we indeed are running in the browser
this.controller = Controller({
devtools:
process.env.NODE_ENV === 'production' || typeof window === 'undefined'
? null
: Devtools({ host: 'localhost:8787' }),
modules: { clock },
stateChanges: props.stateChanges,
})
}
render() {
return (
<Container controller={this.controller}>
<Page title="Index Page" linkTo="/other" />
</Container>
)
}
const Home = (props) => {
const { stateChanges } = props
const controller = Controller({
devtools:
process.env.NODE_ENV === 'production' || typeof window === 'undefined'
? null
: Devtools({ host: 'localhost:8787' }),
modules: { clock },
stateChanges: stateChanges,
})
return (
<Container controller={controller}>
<Page title="Index Page" linkTo="/other" />
</Container>
)
}
export default Home

View file

@ -1,29 +1,26 @@
import { Component } from 'react'
import { Controller } from 'cerebral'
import Devtools from 'cerebral/devtools'
import { Container } from '@cerebral/react'
import Page from '../components/Page'
import clock from '../modules/clock'
export default class Counter extends Component {
constructor(props) {
super(props)
// The controller will be instantiated for every page change and we only
// add the devtools if we indeed are running in the browser
this.controller = Controller({
devtools:
process.env.NODE_ENV === 'production' || typeof window === 'undefined'
? null
: Devtools({ host: 'localhost:8787' }),
modules: { clock },
stateChanges: props.stateChanges,
})
}
render() {
return (
<Container controller={this.controller}>
<Page title="Other Page" linkTo="/" />
</Container>
)
}
const Other = (props) => {
const { stateChanges } = props
const controller = Controller({
devtools:
process.env.NODE_ENV === 'production' || typeof window === 'undefined'
? null
: Devtools({ host: 'localhost:8787' }),
modules: { clock },
stateChanges: stateChanges,
})
return (
<Container controller={controller}>
<Page title="Index Page" linkTo="/other" />
</Container>
)
}
export default Other

View file

@ -1,48 +1,37 @@
import { Component } from 'react'
export default class MyLuckNo extends Component {
constructor(...args) {
super(...args)
this.state = { randomNo: null }
import { useState, useEffect } from 'react'
const MyLuckNo = () => {
const [randomNumber, setRandomNumber] = useState(null)
const recalculate = () => {
setRandomNumber(Math.ceil(Math.random() * 100))
}
componentDidMount() {
this.recalculate()
}
useEffect(() => {
recalculate()
}, [])
recalculate() {
this.setState({
randomNo: Math.ceil(Math.random() * 100),
})
}
render() {
const { randomNo } = this.state
if (randomNo === null) {
return <p>Please wait..</p>
const message = do {
if (randomNumber < 30) {
// eslint-disable-next-line no-unused-expressions
;('Do not give up. Try again.')
} else if (randomNumber < 60) {
// eslint-disable-next-line no-unused-expressions
;('You are a lucky guy')
} else {
// eslint-disable-next-line no-unused-expressions
;('You are soooo lucky!')
}
// This is an experimental JavaScript feature where we can get with
// using babel-preset-stage-0
const message = do {
if (randomNo < 30) {
// eslint-disable-next-line no-unused-expressions
;('Do not give up. Try again.')
} else if (randomNo < 60) {
// eslint-disable-next-line no-unused-expressions
;('You are a lucky guy')
} else {
// eslint-disable-next-line no-unused-expressions
;('You are soooo lucky!')
}
}
return (
<div>
<h3>Your Lucky number is: "{randomNo}"</h3>
<p>{message}</p>
<button onClick={() => this.recalculate()}>Try Again</button>
</div>
)
}
if (randomNumber === null) return <p>Please wait..</p>
return (
<div>
<h3>Your Lucky number is: "{randomNumber}"</h3>
<p>{message}</p>
<button onClick={() => recalculate()}>Try Again</button>
</div>
)
}
export default MyLuckNo

View file

@ -1,4 +1,3 @@
import React from 'react'
import App from 'next/app'
const Noop = ({ children }) => children

View file

@ -1,13 +1,12 @@
import { Component } from 'react'
import { useEffect } from 'react'
import { firebaseCloudMessaging } from '../utils/webPush'
class Index extends Component {
componentDidMount() {
const Index = () => {
useEffect(() => {
firebaseCloudMessaging.init()
}
render() {
return <div>Next.js with firebase cloud messaging.</div>
}
}, [])
return <div>Next.js with firebase cloud messaging.</div>
}
export default Index

View file

@ -1,43 +1,35 @@
import React from 'react'
import { useState, useEffect } from 'react'
import PropTypes from 'prop-types'
import Link from 'next/link'
class About extends React.Component {
static pageTransitionDelayEnter = true
const About = (props) => {
const [loaded, setLoaded] = useState(false)
const { pageTransitionReadyToEnter } = props
constructor(props) {
super(props)
this.state = {
loaded: false,
}
}
componentDidMount() {
this.timeoutId = setTimeout(() => {
this.props.pageTransitionReadyToEnter()
this.setState({ loaded: true })
useEffect(() => {
const timeoutId = setTimeout(() => {
pageTransitionReadyToEnter()
setLoaded(true)
}, 2000)
}
return () => {
clearTimeout(timeoutId)
}
}, [pageTransitionReadyToEnter])
componentWillUnmount() {
if (this.timeoutId) clearTimeout(this.timeoutId)
}
if (!loaded) return null
render() {
if (!this.state.loaded) return null
return (
<div className="container bg-success page">
<h1>About us</h1>
<p>
Notice how a loading spinner showed up while my content was "loading"?
Pretty neat, huh?
</p>
<Link href="/">
<a className="btn btn-light">Go back home</a>
</Link>
</div>
)
}
return (
<div className="container bg-success page">
<h1>About us</h1>
<p>
Notice how a loading spinner showed up while my content was "loading"?
Pretty neat, huh?
</p>
<Link href="/">
<a className="btn btn-light">Go back home</a>
</Link>
</div>
)
}
About.propTypes = {

View file

@ -7,7 +7,7 @@
"dependencies": {
"@jesstelford/react-portal-universal": "1.0.0",
"next": "latest",
"react": "^16.8.0",
"react-dom": "^16.8.0"
"react": "16.13.1",
"react-dom": "16.13.1"
}
}

View file

@ -1,71 +1,60 @@
import { Component } from 'react'
import { useState } from 'react'
import { UniversalPortal } from '@jesstelford/react-portal-universal'
export default class Index extends Component {
constructor() {
super(...arguments)
this.state = { opened: true }
}
const Index = () => {
const [isOpen, toggle] = useState(true)
open = () => {
this.setState({ opened: true })
}
return (
<>
{/* A portal that is adjacent to its target */}
<div id="target" />
<UniversalPortal selector="#target">
<h1>Hello Portal</h1>
</UniversalPortal>
close = () => {
this.setState({ opened: false })
}
render() {
return (
<>
{/* A portal that is adjacent to its target */}
<div id="target" />
<UniversalPortal selector="#target">
<h1>Hello Portal</h1>
</UniversalPortal>
{/* Open a modal in a portal that is elsewhere in the react tree */}
<button type="button" onClick={this.open}>
Open Modal
</button>
{this.state.opened && (
<UniversalPortal selector="#modal">
{/* Open a modal in a portal that is elsewhere in the react tree */}
<button onClick={() => toggle(!isOpen)} type="button">
Open Modal
</button>
{isOpen && (
<UniversalPortal selector="#modal">
<div
style={{
position: 'fixed',
backgroundColor: 'rgba(0, 0, 0, 0.7)',
top: 0,
right: 0,
bottom: 0,
left: 0,
}}
>
<div
style={{
position: 'fixed',
backgroundColor: 'rgba(0, 0, 0, 0.7)',
top: 0,
right: 0,
bottom: 0,
left: 0,
backgroundColor: 'white',
position: 'absolute',
top: '10%',
right: '10%',
bottom: '10%',
left: '10%',
padding: '1em',
}}
>
<div
style={{
backgroundColor: 'white',
position: 'absolute',
top: '10%',
right: '10%',
bottom: '10%',
left: '10%',
padding: '1em',
}}
>
<p>
This modal is rendered using{' '}
<a href="https://www.npmjs.com/package/@jesstelford/react-portal-universal">
<code>@jesstelford/react-portal-universal</code>
</a>
.
</p>
<button type="button" onClick={this.close}>
Close Modal
</button>
</div>
<p>
This modal is rendered using{' '}
<a href="https://www.npmjs.com/package/@jesstelford/react-portal-universal">
<code>@jesstelford/react-portal-universal</code>
</a>
.
</p>
<button type="button" onClick={() => toggle(!isOpen)}>
Close Modal
</button>
</div>
</UniversalPortal>
)}
</>
)
}
</div>
</UniversalPortal>
)}
</>
)
}
export default Index

View file

@ -8,7 +8,7 @@
"dependencies": {
"@segment/snippet": "^4.0.1",
"next": "latest",
"react": "^16.7.0",
"react-dom": "^16.7.0"
"react": "16.13.1",
"react-dom": "16.13.1"
}
}

View file

@ -1,49 +1,47 @@
import { Component } from 'react'
import { useState } from 'react'
export default class Contact extends Component {
state = { message: '' }
const Contact = () => {
const [message, setMessage] = useState('')
render() {
return (
<div>
<h1>This is the Contact page</h1>
<form onSubmit={this.handleSubmit}>
<label>
<span>Message:</span>
<textarea onChange={this.handleInput} value={this.state.message} />
</label>
<button type="submit">submit</button>
</form>
<style jsx>{`
label span {
display: block;
margin-bottom: 12px;
}
textarea {
min-width: 300px;
min-height: 120px;
}
button {
margin-top: 12px;
display: block;
}
`}</style>
</div>
)
}
handleInput = (e) => {
this.setState({ message: e.target.value })
}
handleSubmit = (e) => {
const handleSubmit = (e) => {
e.preventDefault()
global.analytics.track('Form Submitted', {
message: this.state.message,
message,
})
this.setState({ message: '' })
setMessage('')
}
return (
<div>
<h1>This is the Contact page</h1>
<form onSubmit={handleSubmit}>
<label>
<span>Message:</span>
<textarea
onChange={(e) => setMessage(e.target.value)}
value={message}
/>
</label>
<button type="submit">submit</button>
</form>
<style jsx>{`
label span {
display: block;
margin-bottom: 12px;
}
textarea {
min-width: 300px;
min-height: 120px;
}
button {
margin-top: 12px;
display: block;
}
`}</style>
</div>
)
}
export default Contact

View file

@ -1,21 +1,18 @@
import { Component } from 'react'
import Link from 'next/link'
import Editor from '../components/NextEditor'
class MultipleEditors extends Component {
render() {
return (
<>
<Link href="/">
<a>Go to Home</a>
</Link>
<hr />
<Editor slateKey="foo" defaultValue="Foo" />
<hr />
<Editor slateKey="bar" defaultValue="Bar" />
</>
)
}
const MultipleEditors = () => {
return (
<>
<Link href="/">
<a>Go to Home</a>
</Link>
<hr />
<Editor slateKey="foo" defaultValue="Foo" />
<hr />
<Editor slateKey="bar" defaultValue="Bar" />
</>
)
}
export default MultipleEditors

View file

@ -1,34 +1,25 @@
import { Component } from 'react'
import { useCallback, useEffect, useState } from 'react'
import videojs from 'video.js'
import 'videojs-youtube'
class Player extends Component {
componentDidMount() {
// instantiate Video.js
this.player = videojs(this.videoNode, this.props, function onPlayerReady() {
console.log('onPlayerReady', this)
})
}
const Player = (props) => {
const [videoEl, setVideoEl] = useState(null)
const onVideo = useCallback((el) => {
setVideoEl(el)
}, [])
// destroy player on unmount
componentWillUnmount() {
if (this.player) {
this.player.dispose()
useEffect(() => {
const player = videojs(videoEl, props)
return () => {
player.dispose()
}
}
}, [props, videoEl])
// wrap the player in a div with a `data-vjs-player` attribute
// so videojs won't create additional wrapper in the DOM
// see https://github.com/videojs/video.js/pull/3856
render() {
return (
<div>
<div data-vjs-player>
<video ref={(node) => (this.videoNode = node)} className="video-js" />
</div>
</div>
)
}
return (
<div data-vjs-player>
<video ref={onVideo} className="video-js" playsInline />
</div>
)
}
export default Player

View file

@ -8,8 +8,8 @@
},
"dependencies": {
"next": "^9.1.8-canary.11",
"react": "^16.7.0",
"react-dom": "^16.7.0",
"react": "16.13.1",
"react-dom": "16.13.1",
"video.js": "^6.7.3",
"videojs-youtube": "^2.4.1"
},

View file

@ -1,20 +1,19 @@
import { Component } from 'react'
import Player from '../components/Player'
export default class Index extends Component {
render() {
const videoJsOptions = {
techOrder: ['youtube'],
autoplay: false,
controls: true,
sources: [
{
src: 'https://www.youtube.com/watch?v=IxQB14xVas0',
type: 'video/youtube',
},
],
}
return <Player {...videoJsOptions} />
const Index = () => {
const videoJsOptions = {
techOrder: ['youtube'],
autoplay: false,
controls: true,
sources: [
{
src: 'https://www.youtube.com/watch?v=IxQB14xVas0',
type: 'video/youtube',
},
],
}
return <Player {...videoJsOptions} />
}
export default Index