ãã®èšäºã®ç®çã¯ãææ°ã®Webã¢ããªã±ãŒã·ã§ã³ãéçºããå¿
èŠãªããŒã«ãšã©ã€ãã©ãªãé 次远å ããã³ã«ã¹ã¿ãã€ãºããããã®ç°å¢ãèªè
ãšäžç·ã«æžãããšã§ãã å€æ°ã®ã¹ã¿ãŒã¿ãŒããã/å®åãªããžããªãšã®é¡æšã«ãã£ãŠã§ãããç§ãã¡ã®ãã®ã§ãã
ãŸããèè
ã¯èªåã®èããç¥èãå®è·µçãªçµéšãæ§ç¯ããããã«ãã®èšäºãæžããéçºã®æ°ããåŽé¢ãç 究ããè¯ãã¢ãããŒã·ã§ã³ãåãåããŸãã
èè
ã¯çŸåšã®èšäºã®ä¿®æ£ãšä¿®æ£ã«å
šåã§åãçµãã§ãããæçµçãªè³æãææ°ã®äŸ¿å©ãªåèæžã«å€ããããšèããŠããŸãã

ãã®èšäºã§ã¯ã詳现ãªTypeScriptæ§æãšReactã®æäœã®åºæ¬ã«ã€ããŠã¯èæ
®ããŠããŸãããèªè
ãäžèšã®ãã¯ãããžãŒã䜿çšããçµéšããªãå Žåã¯ãç 究ãåããããšããå§ãããŸãã
èšäºã®ç¬¬2éšãžã®ãªã³ã¯äœ¿çšãããŠãããã¯ãããžãŒã«ã€ããŠå°ãïŒ
TypeScriptã§ãããžã§ã¯ããäœæããããšã¯ãç¹ã«æåã«èšèªã«æ
£ãããšãã«å€ãã®å°é£ã䌎ããŸãã èè
ã®èŠè§£ã§ã¯ãã¹ããã³ã°ã¿ã€ãã³ã°ã®å©ç¹ã¯åªåãã䟡å€ããããŸãã
èšèªèªäœã®æ©èœã«å ããŠãTypeScriptã³ã³ãã€ã©ãŒã¯æšæºã®ãã¹ãŠã®ããŒãžã§ã³ã®JavaScriptã³ãŒããçæãããããžã§ã¯ãã§Babelã®äœ¿çšãæŸæ£ã§ããããã«ããŸãïŒäœæè
ã¯ãã®çŽ æŽãããããŒã«ã«å¯ŸããŠäœããããŸããããTSãšBabelã®åæ䜿çšã¯æåã«å°ãæ··ä¹±ããããããŸãïŒã
Reactã¯ã巚倧ãªã³ãã¥ããã£ãšã€ã³ãã©ã¹ãã©ã¯ãã£ãåãããWebã€ã³ã¿ãŒãã§ã€ã¹ãäœæããããã®å®çžŸã®ããã©ã€ãã©ãªã§ãã
æè¿ãå€ãã®æ¹åãšæ¹èšãããããã¥ã¡ã³ããå«ãã©ã€ãã©ãªã®
æ°ããããŒãžã§ã³ããªãªãŒã¹ãããŸããã
ããã³ããšã³ãéçºè
ã®èŠªåã§ãã
Webpackã䜿çšããŠãããžã§ã¯ãããã«ãããŸãã ãã®ããŒã«ã®åºæ¬èšå®ã¯éåžžã«ç°¡åã«ç¿åŸããŠäœ¿çšã§ããŸãã çå£ã«ã
ããŒã«ãšã©ã€ãã©ãªã®äœ¿çšæžã¿ããŒãžã§ã³NodeJs v6ã*ã*
Npm v5 *ã*
TypeScript v2ã*ã*
Webpack v3ã*ã*
React v16 *ã*
ããå§ããŸãããïŒ
ãããžã§ã¯ããªããžããªã«ã¯ãåã¹ãããã®åå¥ã®ãã©ã³ãã«ã³ãŒããå«ãŸããŠããŸãã
ã¹ããã1-ãããžã§ã¯ãã«TypeScriptãè¿œå ããŸãã
çµæã®ã³ãŒãã衚瀺ããã«ã¯ïŒ
git checkout step-1
äŸåé¢ä¿ã®ã€ã³ã¹ããŒã«ïŒ
npm i webpack typescript awesome-typescript-loader --save-dev
awesome-typescript-loader -webpackçšã®TypeScript
ããŒã㌠ãäž»èŠãªã©ã€ãã«ã§ãã
ts-loaderãããé«éãšèŠãªãããŠããŸãã
ãããžã§ã¯ãã®ãœãŒã¹çšã«ã
src
ãã©ã«ããŒãäœæããŸãã
ã¢ã»ã³ããªçµæã
dist
éä¿¡ããŸãã
TypeScriptã³ã³ãã€ã©ã®åºæ¬èšå®-ãããžã§ã¯ãã«ãŒããã£ã¬ã¯ããªã®
tsconfig.json
ãã¡ã€ã«
tsconfig.json { "compilerOptions": { "target": "es5",
ã³ã¬ã¯ã¿ãŒã®åºæ¬èšå®ã¯ããããžã§ã¯ãã«ãŒããã£ã¬ã¯ããªã®
webpack.config.js
ãã¡ã€ã«ã§ãã
webpack.config.js const path = require('path'); const webpack = require('webpack'); const paths = { src: path.resolve(__dirname, 'src'), dist: path.resolve(__dirname, 'dist') }; module.exports = { context: paths.src,
src
å
ã§
src
TypeScriptæ§æã䜿çšããã³ãŒãã§
index.ts
ãã¡ã€ã«ãäœæããŸãã次ã«äŸã瀺ããŸãã
index.ts interface Props { world: string; } function hello(props: Props) { alert(`Hello, ${props.world}`); } hello({ world: 'TypeScript!' });
ã³ãŒããã³ã³ãã€ã«ããŠãã«ãããã³ãã³ãïŒ
webpack
ãããžã§ã¯ãã®1åéãã®ãã«ã
webpackã¢ãžã¥ãŒã«å
ã®æåŸã®
dist/app.bundle.js
ã«ã¯ãéžæããæšæºã®ããŒãžã§ã³ã®ããããããèªã¿ãããJavaScriptã³ãŒãã衚瀺ãããŸãã
äœæããç°å¢ã¯ãã©ã€ãã©ãªã䜿çšããŠç°¡åã«æ¡åŒµã§ãããããã¿ã€ãã³ã°ïŒFavorite Technology + TypeScriptïŒã«äœ¿çšããã®ã«äŸ¿å©ã§ãã
ç¶ããŸãããïŒ
ã¹ããã2-Tiny Reactã¢ããªã±ãŒã·ã§ã³ãäœæãã
çµæã®ã³ãŒãã衚瀺ããã«ã¯ïŒ
git checkout step-2
äŸåé¢ä¿ã®ã€ã³ã¹ããŒã«ïŒ
npm i webpack react react-dom --save
npm i webpack @types/react @types/react-dom html-webpack-plugin clean-webpack-plugin --save-dev
html-webpack-plugin-æ¥ç¶ãããã¢ã»ã³ããªçµæãå«ãhtmlãã¡ã€ã«ãçæããããã®ãã©ã°ã€ã³ã
clean-webpack-plugin-ã¢ã»ã³ããªã®çµæã§ãã£ã¬ã¯ããªãã¯ãªãŒã³ã¢ããããŸãã
@ types / reactããã³
@ types / react-domã¯
ã察å¿ããJSã©ã€ãã©ãªã®
宣èšãå«ãããã±ãŒãžã§ããããšã¯ã¹ããŒãããããã¹ãŠã®ã¢ãžã¥ãŒã«ã®ã¿ã€ãã«é¢ããTSã³ã³ãã€ã©ãŒæ
å ±ãæäŸããŸãã
人æ°ã®ããJSã©ã€ãã©ãªã®ã»ãšãã©ã«ã¯å®£èšããããæã«ã¯ãããžã§ã¯ãã®ãœãŒã¹ãã¡ã€ã«ã«ãæã«ã¯çŽ æŽããã
DefinitelyTypedãªããžããªã«ãããã³ãã¥ããã£ã®ãããã§ç©æ¥µçã«éçºãããŠããŸããæ¢åã®å®£èšã«ãšã©ãŒããªããã°ããããã®åé¡ã®ä¿®æ£ã«ç°¡åã«è²¢ç®ã§ããŸãã
src
å
ã§ãã«ãŒãåå¿ã³ã³ããŒãã³ããããŠã³ãããããã®èŠçŽ ãå«ã
index.html
ãã¡ã€ã«ãäœæããŸãã
index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>React and Typescript</title> </head> <body> <div id="root"></div> </body> </html>
Webpackèšå®ã®æŽæ°ïŒ
webpack.config.js const path = require('path'); const webpack = require('webpack'); const CleanWebpackPlugin = require('clean-webpack-plugin'); const paths = { src: path.resolve(__dirname, 'src'), dist: path.resolve(__dirname, 'dist') }; const config = { context: paths.src, entry: { app: './index' }, output: { path: paths.dist, filename: '[name].bundle.js' }, resolve: { extensions: ['.ts', '.tsx', '.js', '.jsx']
TypeScriptã³ã³ãã€ã©ãŒèšå®ãæŽæ°ããŸãã
tsconfig.json { "compilerOptions": { "target": "es5", "module": "esnext", "jsx": "react"
ã³ã³ããŒãã³ãã«ç§»ããŸãããã
æ¡åŒµåã
index.ts
ãã
index.ts
ã«å€æŽããå¿
èŠããããŸãã ã³ã³ããŒãã³ãã®ã³ãŒããèšè¿°ããããŒãžã«è¡šç€ºããŸãã
index.tsx // react TS import React from 'react' - TS import * as React from 'react'; import * as ReactDOM from 'react-dom'; // props state interface IAppProps { title: string; } // const App = (props: IAppProps) => <h1>{props.title}</h1>; ReactDOM.render( <App title="Hello, React!" />, document.getElementById('root') );
ã³ãã³ããè¿œå ããŠãã³ãŒããã³ã³ãã€ã«ããã³ãã«ãããŸãã
webpack-dev-server
ã¢ããªã±ãŒã·ã§ã³ã§ãµãŒããŒãäžã
webpack-dev-server
http://localhost:8080/
ã§å©çšã§ããŸãã
ãŸãããœãŒã¹ãã¡ã€ã«ãå€æŽããããšãwebpackã¯èªåçã«ãããžã§ã¯ããåæ§ç¯ããŸãã
ãã®æ®µéã§ãã¢ã»ã³ããªã®ãµã€ãºã«é¢ããŠçåãçããå ŽåããããŸããäœæè
ã¯ã次ã®ã¹ãããã§ãã¢ã»ã³ããªã®çç£ãšéçºã®åºåã«ç¹å¥ãªæ³šæãæããŸãã æåã®æ®µéã§ã¯ãããã»ã¹ãå®å
šã«ç解ããããã«ãæäœéå¿
èŠãªèšå®ãšã©ã€ãã©ãªã«éç¹ã眮ãããŠããŸãã
ã¹ããã3-Reactããã³TypeScriptã¬ã·ã
çµæã®ã³ãŒãã衚瀺ããã«ã¯ïŒ
git checkout step-3
ãã®ã¹ãããã®äŸåé¢ä¿ã¯å€ãããŸããã
ãã®æ®µéã§ã®äžè¬å
ïŒãžã§ããªãã¯ïŒãžã§ããªãã¯ïŒïŒãç解ããããšããå§ãããŸãã
ãã®èšäºããæšæºã®Reactãã¿ãŒã³ã®è©³çŽ°ãåŠã¶ããšãã§ããŸãã
1ïŒ
ããããã£ãšç¶æ
ãæã€æšæºã³ã³ããŒãã³ãå¶åŸ¡ãããå
¥åãã£ãŒã«ããåºåãã
simple.tsx
ã³ã³ããŒãã³ããäœæããŸãã
simple.tsx import * as React from 'react'; interface Props extends React.HTMLProps<HTMLInputElement> { customProperty: string; }
2ïŒ
é«æ¬¡ã³ã³ããŒãã³ãå
¬åŒã®Reactããã¥ã¡ã³ãã§ã®é«æ¬¡ã³ã³ããŒãã³ãã®èª¬æ-
ãããã¯ãªãã¯TypeScriptã§ã®é«æ¬¡ã³ã³ããŒãã³ãã®èšè¿°ã®è©³çŽ°ãªèšäºïŒãã®èšäºã®äŸã¯ãèè
ã«ãã£ãŠéšåçã«åçšãããŠã
ãŸã ïŒ-
ãããã¯ãªãã¯èŠããã«ãé«æ¬¡ã³ã³ããŒãã³ãïŒä»¥äžãããã¯ãšåŒã³ãŸãïŒã¯ãã³ã³ããŒãã³ããåŒæ°ãšããŠïŒããã³ãªãã·ã§ã³ã§ïŒãªãã·ã§ã³ãšããŠãå€ãã³ã³ããŒãã³ãã
render
ã¡ãœããã§è¡šç€ºããæ°ããã³ã³ããŒãã³ããè¿ãããã®ããããã£ãšç¶æ
ãæž¡ãé¢æ°ã§ãã
眲åã¯æ¬¡ã®ããã«ãªããŸãã
(Component) => WrapComponent => Component
TypeScriptã¯ã³ã³ããŒãã³ãã«æž¡ãããããã£ãå³å¯ã«ç£èŠããããããããã®ããããã£ã®ã€ã³ã¿ãŒãã§ã€ã¹ã決å®ããå¿
èŠããããŸãã
OriginProps-ã³ã³ããŒãã³ãã®åºæã®ããããã£ãhocã¯ãããã«ã€ããŠäœãç¥ãããã³ã³ããŒãã³ãã«æž¡ãã ãã§ãã
ExternalProps-äžæã®äžæçãªããããã£ã
InjectedProps -hocããã³ã³ããŒãã³ãã«æž¡ãããããã£ã¯ãExternalPropsãšStateã«åºã¥ããŠèšç®ãããŸãã
ç¶æ
-äžæçãªç¶æ
ã®ã€ã³ã¿ãŒãã§ã€ã¹ã hocç¶æ
å
šäœãã³ã³ããŒãã³ãã«æž¡ããããStateã¯InjectedPropsãšç°ãªãããããã£ãæã€ããšã¯ã§ããŸããïŒãŸãã¯ãæ¡åŒµæŒç®åã䜿çšããã«äœ¿çšå¯èœãªããããã£ãæž¡ãå¿
èŠããããŸãïŒã
ã³ãŒãã«ç§»ããç°¡åãªãã¿ã³ã¯ãªãã¯ã«ãŠã³ã¿ãŒãèšè¿°ããŸãããã
hoc
ãã©ã«ããŒãäœæããŸãããã®äžã«ã³ã³ããŒãã³ã
displayCount.tsx
ããã³hoc
withCount.tsx
äœæããŸã
ã³ã³ããŒãã³ãã³ãŒãdisplayCount.tsx import * as React from 'react'; import { InjectedProps } from './withCount';
ã³ã³ããŒãã³ãã³ãŒãwithCount.tsx import * as React from 'react';
次ã«ãé«æ¬¡ã³ã³ããŒãã³ãã®äœ¿çšã«ã€ããŠèª¬æããŸãã
const Counter = withCount(DisplayCount); const App = () => <Counter title="High Order Component" increment={1} /> ;
æŠèŠããªãŒïŒ

WithCountïŒDisplayCountïŒã®ããããã£ãšç¶æ
ïŒ

DisplayCountã®ããããã£ãšã¹ããŒã¿ã¹ïŒ

ããã§ãè¿œå ã®
increment
ããããã£ã衚瀺ãããŸããå¿
èŠã«å¿ããŠãlodashã®exclude
ã¡ãœãããªã©ã䜿çšããŠåé€ã§ããŸãã
3ïŒ
é
延ã³ã³ããŒãã³ãã®ããŒãïŒã³ã³ããŒãã³ãããªã³ããã³ãã§ããŒãããã«ã¯ãã¢ãžã¥ãŒã«ã®åçã€ã³ããŒãã®æ§æã䜿çšããŸãã
TypeScriptã§ã¯ããã®æ§æã¯
ããŒãžã§ã³2.4ã§ç»å ŽããŸããã
åçã€ã³ããŒãã«ééããWebpackã¯ãã€ã³ããŒãæ¡ä»¶ã«è©²åœããã¢ãžã¥ãŒã«çšã«
åå¥ã®ãã³ãã«ã
äœæããŸãã
ã€ã³ããŒãããæãç°¡åãªåŒã¯æ¬¡ã®ãšããã§ãã
import('module.ts').then((module) => {
次ã«ãã€ã³ããŒããè¿ãé¢æ°ãåãåããçµæã®ã³ã³ããŒãã³ãã衚瀺ããã³ã³ããŒãã³ããäœæããŸãã
lazyComponent.tsx
ããã³
lazyLoad.tsx
ã³ã³ããŒãã³ãã®
lazy
ãã©ã«ããŒãäœæããŸã
LazyComponentã¯ã·ã³ãã«ãªæ©èœã³ã³ããŒãã³ãã§ããå®éã®ã¢ããªã±ãŒã·ã§ã³ã§ã¯ãåå¥ã®ããŒãžãŸãã¯ã¹ã¿ã³ãã¢ãã³ã®ãŠã£ãžã§ããã«ããããšãã§ããŸãã
lazyComponent.tsx import * as React from 'react'; const LazyComponent = () => <h3>I'm so lazy!</h3>; export default LazyComponent;
LazyLoadã¯ãåçã³ã³ããŒãã³ãã®ããŒããšåºåã®ããã®æ±çšã³ã³ããŒãã³ãã§ãã
ããããã£ãåçã³ã³ããŒãã³ãã«ã¹ããŒããå¿
èŠãããå ŽåãLazyLoadãé«æ¬¡ã³ã³ããŒãã³ãã«æžãæããããšãã§ããŸãã
lazyLoad.tsx import * as React from 'react'; interface LazyLoadProps { load: () => Promise<{ default: React.ComponentType }>; }
ããã§ãããã³ãã«ã«ååãä»ããããšãã§ããããã«ãwebpackã®èšå®ãæŽæ°ããŸãã
webpack.config.js const path = require('path'); const webpack = require('webpack'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const CleanWebpackPlugin = require('clean-webpack-plugin'); const paths = { src: path.resolve(__dirname, 'src'), dist: path.resolve(__dirname, 'dist') }; const config = { context: paths.src, entry: { app: './index' }, output: { path: paths.dist, filename: '[name].bundle.js', chunkFilename: '[name].bundle.js'
ãããŠãtsconfig.jsonèšå®ãæŽæ°ããŸã-ã³ã³ãã€ã«æã«TypeScriptã䜿çšããã©ã€ãã©ãªãæåã§æå®ããŸãã å
·äœçã«ã¯ães2015.promiseããå¿
èŠã§ããã䟿å®äžãESæšæºã®å®å
šãªãªã¹ãããããŠãã¡ããDOMãè¿œå ããŸãã
tsconfig.json { "compilerOptions": { "lib": [ "es5", "es6", "es7", "dom" ], "target": "es5", "module": "esnext", "jsx": "react" } }
ã³ã³ããŒãã³ãã®äœ¿çšïŒ
4ïŒ
å°éå
·ã®ã¬ã³ããªã³ã°å
¬åŒã®Reactããã¥ã¡ã³ãã§ã®renderããããã£ãæã€ã³ã³ããŒãã³ãã®èª¬æ-
ãããã®ãããªã³ã³ããŒãã³ãã䜿ããããããããã«ãéåžžãããã€ãã®ã¬ã³ããªã³ã°æ¹æ³ãæäŸãããŠããŸãã
2ã€ã®äž»ãªãã®ãæ€èšããŠãã ããïŒ
renderããããã£ãš
childrenããããã£ã
renderProps
ãã©ã«ããŒãäœæããŸãããã®äžã«
displaySize.tsx
ã³ã³ããŒãã³ããš
windowQueries.tsx
ã³ã³ããŒãã³ã
ã³ã³ããŒãã³ãã³ãŒãdisplaySize.tsx import * as React from 'react'; import { IRenderProps } from './windowQueries';
windowQueries.tsxã³ã³ããŒãã³ãã³ãŒã import * as React from 'react';
次ã«ãã³ã³ããŒãã³ãã®äœ¿çšã«ã€ããŠèª¬æããŸãã
<WindowQueries> {({ width, height }) => <DisplaySize title="render children" width={width} height={height} />} </WindowQueries> <WindowQueries render={ ({ width, height }) => <DisplaySize title="render property" width={width} height={height} /> } />
5ïŒ
ãã¥ã¢ã³ã¹ïŒåã«ã¢ã¯ã»ã¹ããããã®childrenããããã£ã®èª¬æïŒãªãã·ã§ã³ïŒïŒ
interface Props { children: React.ReactNode; }
JSXèŠçŽ ã䜿çšããããããã£ã®èª¬æã¯ãããŒã¯ã¢ããã³ã³ããŒãã³ãã«äœ¿çšã§ããŸãã
interface Props { header: JSX.Element, body: JSX.Element } <Component header={<h1></h1>} body={<div></div>} />
ãããã«æå°éå¿
èŠãªèšå®ã§ReactãšTypeScriptã®éçºç°å¢ãäœæããããã€ãã®ç°¡åãªã³ã³ããŒãã³ããäœæããŸããã
TypeScriptã䜿çšãããšã
PropTypesã®äœ¿çšãæŸæ£ããéçºããã³ã³ã³ãã€ã«äžã«ã³ã³ããŒãã³ãã®ããããã£ã確èªã§ããŸãïŒPropTypesã¯ãã¢ããªã±ãŒã·ã§ã³ã®å®è¡äžã«ã®ã¿ãšã©ãŒãè¿ããŸãïŒã
èªåè£å®ãšããŠã®åŒ·ãåä»ãã®ãã®ãããªå©ç¹ã¯JSXã«ãŸã§åã³ãReactã©ã€ãã©ãªå®£èšãã¡ã€ã«ã§ã¯ãçµã¿èŸŒã¿JSXèŠçŽ ã®ãã¹ãŠã®å¯èœãªããããã£ããã°ãã確èªã§ããŸãã
è€éãªãããžã§ã¯ãã§ã¯ãTypeScriptã䜿çšããããšã§å®å
šã«æ£åœåãããŸããããã¯ãReduxã䜿çšããïŒã¹ãã¢ã®ã€ã³ã¿ãŒãã§ã€ã¹ã®ãããã§ãïŒãå€éšAPIãæäœãããªã©ã®ç¬éã«èŠãããŸãã
èšäº2ã§ã¯ã次ã®ããšãèæ
®ããŠããŸãã
1ïŒReduxãæ¥ç¶ãã
2ïŒæšæºReactãReduxãããã³TypeScriptã¬ã·ã
3ïŒAPIã䜿çšãã
4ïŒçç£éçºãããžã§ã¯ãã®çµã¿ç«ãŠ
ãã®åŸã®èšäºã§ã¯ãèè
ã¯æ¬¡ã®ããšã説æããäºå®ã§ããããã°ã¬ãã·ãWebã¢ããªã±ãŒã·ã§ã³ïŒPWAïŒã®äœæããµãŒããŒã¬ã³ããªã³ã°ãJestã§ã®ãã¹ãããããŠæçµçã«ã¢ããªã±ãŒã·ã§ã³ã®æé©å
èè
ã¯ãèšäºã®ãã¶ã€ã³ã®å€±æã«ã€ããŠè¬çœªãããã®èšäºã®èªèãšèªã¿ããããæ¹åããããã®ææ¡ãå床æåºããããæ±ããŸãã
ãæž
èŽããããšãããããŸããïŒ
æŽæ°10.22.2017ïŒé
延ããŒãã³ã³ããŒãã³ãã®ã¬ã·ããè¿œå
ã¢ããããŒã02.17.2018ïŒã¬ã³ããªã³ã°ããããã£ãå«ãã³ã³ããŒãã³ãã¬ã·ããè¿œå ããäŸåé¢ä¿ãæŽæ°ïŒReactNodeã¿ã€ãã®ãšã©ãŒãä¿®æ£ïŒ