atomita
所属: 琉球インタラクティブ
package.json
{
"name": "introduction-react",
"version": "0.0.0",
"description": "introduction react",
"repository": "",
"scripts": {
"serve": "parcel --no-cache -p 8080 ./app/index.html",
"test": "jest --coverage --no-cache"
},
"author": "",
"license": "MIT",
"dependencies": {},
"devDependencies": {
"@types/jest": "^24.0.20",
"@types/node": "^12.11.7",
"@types/react": "^16.9.11",
"identity-obj-proxy": "^3.0.0",
"jest": "^24.9.0"
},
"babel": {
"presets": [
[
"@babel/preset-env",
{
"targets": {
"browsers": [
"> 1%",
"last 2 versions",
"not dead",
"ie 11"
]
},
"useBuiltIns": "usage",
"corejs": 3
}
]
]
},
"jest": {
"verbose": true,
"testURL": "http://localhost/",
"transformIgnorePatterns": [],
"transform": {
"^.+\\.jsx?$": "babel-jest",
"^.+\\.tsx?$": "ts-jest"
},
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"jsx",
"json",
"node"
],
"moduleNameMapper": {
"\\.(s?css|sass|styl(us)?|svg)$": "identity-obj-proxy"
},
"globals": {
"ts-jest": {
"isolatedModules": true
}
}
}
}
tsconfig.json
{
"compileOnSave": false,
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"noImplicitAny": false,
"strict": true,
"jsx": "react",
"jsxFactory": "React.createElement",
"target": "es5",
"typeRoots": [
"node_modules/@types"
],
"types": ["jest"],
"lib": [
"es2015",
"es2016",
"es2017",
"es2018",
"es2019",
"esnext",
"dom"
]
}
}
npm install parcel-bundler typescript @babel/preset-env --save-dev
npm install core-js@3 --save
app/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Hackers Champloo Uncanference 2019</title>
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
</head>
<body>
<div id="app"></div>
<script src="./index.ts"></script>
</body>
</html>
app/index.ts
import './app'
app/app.tsx
import React from 'react'
import ReactDOM from 'react-dom'
ReactDOM.render(
<div>hello world!</div>,
document.getElementById('app')
)
npm run serve
app/app.tsx
+import React, {useState} from 'react'
-import React from 'react'
import ReactDOM from 'react-dom'
+function App() {
+ const [count, setCount] = useState(0)
+ return (
+ <div>
+ <p>count: <span>{count}</span></p>
+ <button onClick={event => setCount(count + 1)}>count up!</button>
+ </div>
+ )
+}
ReactDOM.render(
+ <App />,
- <div>hello world!</div>,
document.getElementById('app')
)
app/Home.tsx
import React from 'react'
export function Home () {
return (
<h1>Home</h1>
)
}
app/Counter.tsx
import React, {useState} from 'react'
export function Counter() {
const [count, setCount] = useState(0)
return (
<div>
<h1>Counter</h1>
<p>count: <span>{count}</span></p>
<button onClick={event => setCount(count + 1)}>count up!</button>
</div>
)
}
app/app.tsx
+import React from 'react'
-import React, {useState} from 'react'
import ReactDOM from 'react-dom'
+import { BrowserRouter, Route, Link } from 'react-router-dom'
+import { Home } from './Home'
+import { Counter } from './Counter'
function App() {
- const [count, setCount] = useState(0)
- return (
- <div>
- <p>count: <span>{count}</span></p>
- <button onClick={event => setCount(count + 1)}>count up!</button>
- </div>
+ return (
+ <BrowserRouter>
+ <div>
+ <ul>
+ <li><Link to='/'>Home</Link></li>
+ <li><Link to='/counter'>Counter</Link></li>
+ </ul>
+ </div>
+ <div>
+ <Route exact path='/' component={Home} />
+ <Route path='/counter' component={Counter} />
+ </div>
+ </BrowserRouter>
)
}
ReactDOM.render(
<App />,
document.getElementById('app')
)