Woongjae Lee
Daangn - Frontend Core Team ex) NHN Dooray - Frontend Team Leader ex) ProtoPie - Studio Team
2woongjae@gmail.com
2woongjae@gmail.com
class HelloMessage extends React.Component {
render() {
return <div>Hello {this.props.name}</div>;
}
}
ReactDOM.render(<HelloMessage name="Jane" />, mountNode);
class HelloMessage extends React.Component {
render() {
return React.createElement(
"div",
null,
"Hello ",
this.props.name
);
}
}
ReactDOM.render(React.createElement(HelloMessage, { name: "Jane" }), mountNode);
{
"name": "start-project-babel",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"devDependencies": {
"babel-core": "^6.25.0",
"babel-loader": "^7.0.0",
"babel-plugin-transform-react-jsx": "^6.24.1",
"babel-preset-env": "^1.5.2",
"react": "^15.6.1",
"react-dom": "^15.6.1",
"webpack": "^2.6.1",
"webpack-dev-server": "^2.4.5"
}
}
{
"name": "start-project-nocra",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"devDependencies": {
"@types/react": "^15.0.29",
"@types/react-dom": "^15.5.0",
"react": "^15.6.1",
"react-dom": "^15.6.1",
"ts-loader": "^2.1.0",
"typescript": "^2.3.4",
"webpack": "^2.6.1",
"webpack-dev-server": "^2.4.5"
}
}
const path = require('path');
module.exports = {
// input 설정
entry: './src/index.tsx',
// output 설정
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js'
},
//
resolve: {
extensions: [".ts", ".tsx", ".js", ".jsx", ".json"]
},
// transformations 설정
module: {
rules: [
{
test: /\.(ts|tsx)$/,
loader: "ts-loader",
},
{
enforce: "pre",
test: /\.(ts|tsx)$/,
loader: "tslint-loader"
},
{
enforce: "pre",
test: /\.js$/,
loader: "source-map-loader"
}
]
},
// sourcemaps 설정 : Enable sourcemaps for debugging webpack's output.
devtool: 'source-map',
// server 설정
devServer: {
contentBase: path.join(__dirname, 'src'),
compress: true,
historyApiFallback: true
}
};
{
"compilerOptions": {
"outDir": "dist",
"sourceMap": true,
"noImplicitAny": true,
"module": "commonjs",
"moduleResolution": "node",
"target": "es5",
"lib": ["es6", "dom"],
"jsx": "react"
},
"include": [
"./src/**/*"
]
}
Marks:start-project-nocra mark$ yarn add tslint, tslint-loader, tslint-react -D
{
"extends": ["tslint-react"],
"rules": {
"no-console": [
true,
"log",
"error",
"debug",
"info",
"time",
"timeEnd",
"trace"
]
}
}
{
"name": "start-project-cra",
"version": "0.1.0",
"private": true,
"dependencies": {
"@types/jest": "^20.0.1",
"@types/node": "^8.0.1",
"@types/react": "^15.0.30",
"@types/react-dom": "^15.5.0",
"react": "^15.6.1",
"react-dom": "^15.6.1"
},
"devDependencies": {
"react-scripts-ts": "2.2.0"
},
"scripts": {
"start": "react-scripts-ts start",
"build": "react-scripts-ts build",
"test": "react-scripts-ts test --env=jsdom",
"eject": "react-scripts-ts eject"
}
}
{
"compilerOptions": {
"outDir": "build/dist", // 빌드 결과물 폴더
"module": "commonjs", // 빌드 결과의 모듈 방식은 commonjs
"target": "es5", // 빌드 결과물은 es5 방식으로
"lib": ["es6", "dom"], // 라이브러리는 es6 와 dom
"sourceMap": true, // .map.js 파일도 함께 생성
"allowJs": true, // JS 파일도 컴파일 대상
"jsx": "react", // jsx 구문 사용 가능
"moduleResolution": "node", // 모듈 해석 방식은 node 처럼
"rootDir": "src", // 컴파일할 대상들이 들어있는 폴더 (루트 폴더)
"forceConsistentCasingInFileNames": true, // https://github.com/TypeStrong/ts-loader/issues/89
"noImplicitReturns": true, // 제대로 리턴 다 안되면 에러
"noImplicitThis": true, // this 표현식에 암시적으로 any 로 추론되면
"noImplicitAny": true, // 암시적으로 선언되었는데 any 로 추론되면
"strictNullChecks": true, // null 이나 undefined 을 서브 타입으로 사용하지 못하게 함
"suppressImplicitAnyIndexErrors": true, // 인덱싱 시그니처가 없는 경우, 인덱스를 사용했을때 noImplicitAny 에 의해 에러가 뜨는 것을 방지
"noUnusedLocals": true // 사용 안하는 로컬 변수가 있으면 에러
},
"exclude": [
"node_modules",
"build",
"scripts",
"acceptance-tests",
"webpack",
"jest",
"src/setupTests.ts"
],
"types": [
"typePatches" // 자동으로 패치되기 때문에 이렇게 막아놓은 듯
]
}
{
"extends": ["tslint-react"],
"rules": {
"align": [
true,
"parameters",
"arguments",
"statements"
],
"ban": false,
"class-name": true,
"comment-format": [
true,
"check-space"
],
"curly": true,
"eofline": false,
"forin": true,
"indent": [ true, "spaces" ],
"interface-name": [true, "never-prefix"],
"jsdoc-format": true,
"jsx-no-lambda": false,
"jsx-no-multiline-js": false,
"label-position": true,
"max-line-length": [ true, 120 ],
"member-ordering": [
true,
"public-before-private",
"static-before-instance",
"variables-before-functions"
],
"no-any": true,
"no-arg": true,
"no-bitwise": true,
"no-console": [
true,
"log",
"error",
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-consecutive-blank-lines": true,
"no-construct": true,
"no-debugger": true,
"no-duplicate-variable": true,
"no-empty": true,
"no-eval": true,
"no-shadowed-variable": true,
"no-string-literal": true,
"no-switch-case-fall-through": true,
"no-trailing-whitespace": false,
"no-unused-expression": true,
"no-use-before-declare": true,
"one-line": [
true,
"check-catch",
"check-else",
"check-open-brace",
"check-whitespace"
],
"quotemark": [true, "single", "jsx-double"],
"radix": true,
"semicolon": [true, "always"],
"switch-default": true,
"trailing-comma": false,
"triple-equals": [ true, "allow-null-check" ],
"typedef": [
true,
"parameter",
"property-declaration"
],
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
}
],
"variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"],
"whitespace": [
true,
"check-branch",
"check-decl",
"check-module",
"check-operator",
"check-separator",
"check-type",
"check-typecast"
]
}
}
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import './index.css';
// react-dom 라이브러리를 이용해서 DOM 에 리액트 컴포넌트를 매칭
ReactDOM.render(
<App />,
document.getElementById('root') as HTMLElement
);
registerServiceWorker();
import * as React from 'react';
import './App.css';
const logo = require('./logo.svg');
class App extends React.Component<{}, null> {
render() {
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h2>Welcome to React</h2>
</div>
<p className="App-intro">
To get started, edit <code>src/App.tsx</code> and save to reload.
</p>
</div>
);
}
}
export default App;
class App extends React.Component<{}, null> {
render() {
return (
<h2>Hello World</h2>
);
}
}
class Component<P, S> {
constructor(props?: P, context?: any);
setState<K extends keyof S>(f: (prevState: S, props: P) => Pick<S, K>, callback?: () => any): void;
setState<K extends keyof S>(state: Pick<S, K>, callback?: () => any): void;
forceUpdate(callBack?: () => any): void;
render(): JSX.Element | null | false;
// React.Props<T> is now deprecated, which means that the `children`
// property is not available on `P` by default, even though you can
// always pass children as variadic arguments to `createElement`.
// In the future, if we can define its call signature conditionally
// on the existence of `children` in `P`, then we should remove this.
props: Readonly<{ children?: ReactNode }> & Readonly<P>;
state: Readonly<S>;
context: any;
refs: {
[key: string]: ReactInstance
};
}
class App extends React.Component<{ name: string }, null> {
render() {
return (
<h2>Hello {this.props.name}</h2>
);
}
}
ReactDOM.render(
<App name="Mark" />,
document.getElementById('root') as HTMLElement
);
class Component<P, S> {
constructor(props?: P, context?: any);
setState<K extends keyof S>(f: (prevState: S, props: P) => Pick<S, K>, callback?: () => any): void;
setState<K extends keyof S>(state: Pick<S, K>, callback?: () => any): void;
forceUpdate(callBack?: () => any): void;
render(): JSX.Element | null | false;
// React.Props<T> is now deprecated, which means that the `children`
// property is not available on `P` by default, even though you can
// always pass children as variadic arguments to `createElement`.
// In the future, if we can define its call signature conditionally
// on the existence of `children` in `P`, then we should remove this.
props: Readonly<{ children?: ReactNode }> & Readonly<P>;
state: Readonly<S>;
context: any;
refs: {
[key: string]: ReactInstance
};
}
class App extends React.Component<{ name: string; }, { age: number; }> {
render() {
return (
// <h2>{this.props.name}</h2>
<h2>{this.props.name} - {this.state.age}</h2>
);
}
}
class App extends React.Component<{ name: string; }, { age: number; }> {
public state = {
age: 35
};
render() {
return (
<h2>Hello {this.props.name} - {this.state.age}</h2>
);
}
}
class App extends React.Component<{ name: string; }, { age: number; }> {
constructor(props: { name: string; }) {
super(props);
this.state = {
age: 35
};
}
render() {
return (
<h2>Hello {this.props.name} - {this.state.age}</h2>
);
}
}
class Component<P, S> {
constructor(props?: P, context?: any);
setState<K extends keyof S>(f: (prevState: S, props: P) => Pick<S, K>, callback?: () => any): void;
setState<K extends keyof S>(state: Pick<S, K>, callback?: () => any): void;
forceUpdate(callBack?: () => any): void;
render(): JSX.Element | null | false;
// React.Props<T> is now deprecated, which means that the `children`
// property is not available on `P` by default, even though you can
// always pass children as variadic arguments to `createElement`.
// In the future, if we can define its call signature conditionally
// on the existence of `children` in `P`, then we should remove this.
props: Readonly<{ children?: ReactNode }> & Readonly<P>;
state: Readonly<S>;
context: any;
refs: {
[key: string]: ReactInstance
};
}
class App extends React.Component<{ name: string; }, { age: number; }> {
constructor(props: { name: string; }) {
super(props);
this.state = {
age: 35
};
setInterval(() => {
// this.state.age = this.state.age + 1;
this.setState({
age: this.state.age + 1
});
}, 1000);
}
render() {
return (
<h2>Hello {this.props.name} - {this.state.age}</h2>
);
}
}
class Component<P, S> {
constructor(props?: P, context?: any);
setState<K extends keyof S>(f: (prevState: S, props: P) => Pick<S, K>, callback?: () => any): void;
setState<K extends keyof S>(state: Pick<S, K>, callback?: () => any): void;
forceUpdate(callBack?: () => any): void;
render(): JSX.Element | null | false;
// React.Props<T> is now deprecated, which means that the `children`
// property is not available on `P` by default, even though you can
// always pass children as variadic arguments to `createElement`.
// In the future, if we can define its call signature conditionally
// on the existence of `children` in `P`, then we should remove this.
props: Readonly<{ children?: ReactNode }> & Readonly<P>;
state: Readonly<S>;
context: any;
refs: {
[key: string]: ReactInstance
};
}
export interface AppProps {
name: string;
}
interface AppState {
age: number;
}
class App extends React.Component<AppProps, AppState> {
constructor(props: AppProps) {
super(props);
this.state = {
age: 35
};
setInterval(() => {
this.setState({
age: this.state.age + 1
});
}, 1000);
}
render() {
return (
<h2>Hello {this.props.name} - {this.state.age}</h2>
);
}
}
const StatelessComponent = (props: AppProps) => {
return (
<h2>{props.name}</h2>
);
}
const StatelessComponent: React.SFC<AppProps> = (props) => {
return (
<h2>{props.name}</h2>
);
}
type SFC<P> = StatelessComponent<P>;
interface StatelessComponent<P> {
(props: P & { children?: ReactNode }, context?: any): ReactElement<any>;
propTypes?: ValidationMap<P>;
contextTypes?: ValidationMap<any>;
defaultProps?: Partial<P>;
displayName?: string;
}
render() {
return (
<div>
<h2>Hello {this.props.name} - {this.state.age}</h2>
<StatelessComponent name="Anna" />
<StatelessComponent name="Anna">여기는 칠드런입니다. 있을수도 있고 없을 수도 있고</StatelessComponent>
</div>
);
}
const StatelessComponent: React.SFC<AppProps> = (props) => {
return (
<h2>{props.name}, {props.children}</h2>
);
}
type SFC<P> = StatelessComponent<P>;
interface StatelessComponent<P> {
(props: P & { children?: ReactNode }, context?: any): ReactElement<any>;
propTypes?: ValidationMap<P>;
contextTypes?: ValidationMap<any>;
defaultProps?: Partial<P>;
displayName?: string;
}
import * as React from 'react';
import './App.css';
export interface AppProps {
name: string;
}
export interface AppState {
age: number;
}
class App extends React.Component<AppProps, AppState> {
private _interval: number;
constructor(props: AppProps) {
console.log('App constructor');
super(props);
this.state = {
age: 35
};
}
componentWillMount() {
console.log('App componentWillMount');
}
componentDidMount() {
console.log('App componentDidMount');
this._interval = window.setInterval(
() => {
this.setState({
age: this.state.age + 1
});
},
1000
);
}
componentWillUnmount() {
console.log('App componentWillUnmount');
clearInterval(this._interval);
}
render() {
console.log('App render');
return (
<div>
<h2>Hello {this.props.name} - {this.state.age}</h2>
</div>
);
}
}
export default App;
import * as React from 'react';
import './App.css';
export interface AppProps {
name: string;
}
export interface AppState {
age: number;
}
class App extends React.Component<AppProps, AppState> {
private _interval: number;
constructor(props: AppProps) {
console.log('App constructor');
super(props);
this.state = {
age: 35
};
}
componentWillMount() {
console.log('App componentWillMount');
}
componentDidMount() {
console.log('App componentDidMount');
this._interval = window.setInterval(
() => {
this.setState({
age: this.state.age + 1
});
},
1000
);
}
componentWillUnmount() {
console.log('App componentWillUnmount');
clearInterval(this._interval);
}
render() {
console.log('App render');
return (
<div>
<h2>Hello {this.props.name} - {this.state.age}</h2>
</div>
);
}
}
export default App;
constructor
componentWillMount
render
componentDidMount
componentWillReceiveProps(nextProps: AppProps) {
console.log(`App componentWillReceiveProps : ${JSON.stringify(nextProps)}`);
}
shouldComponentUpdate(nextProps: AppProps, nextState: AppState): boolean {
console.log(`App shouldComponentUpdate : ${JSON.stringify(nextProps)}, ${JSON.stringify(nextState)}`);
return true;
}
componentWillUpdate(nextProps: AppProps, nextState: AppState) {
console.log(`App componentWillUpdate : ${JSON.stringify(nextProps)}, ${JSON.stringify(nextState)}`);
}
componentDidUpdate(prevProps: AppProps, prevState: AppState) {
console.log(`App componentDidUpdate : ${JSON.stringify(prevProps)}, ${JSON.stringify(prevState)}`);
}
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate
constructor(props: AppProps) {
console.log('App constructor');
super(props);
this.state = {
age: 35
};
this._reset = this._reset.bind(this);
}
render() {
console.log('App render');
return (
<div>
<h2>Hello {this.props.name} - {this.state.age}</h2>
<button onClick={this._reset}>리셋</button>
</div>
);
}
private _reset(): void {
this.setState({
age: 35
});
}
import * as React from 'react';
import './App.css';
export interface AppProps {
name: string;
}
export interface AppState {
age: number;
company: string;
}
class App extends React.Component<AppProps, AppState> {
private _interval: number;
constructor(props: AppProps) {
console.log('App constructor');
super(props);
this.state = {
age: 35,
company: 'Studio XID'
};
this._reset = this._reset.bind(this);
this._change = this._change.bind(this);
}
componentWillMount() {
console.log('App componentWillMount');
}
componentDidMount() {
console.log('App componentDidMount');
this._interval = window.setInterval(
() => {
this.setState({
age: this.state.age + 1
});
},
1000
);
}
componentWillUnmount() {
console.log('App componentWillUnmount');
clearInterval(this._interval);
}
componentWillReceiveProps(nextProps: AppProps) {
console.log(`App componentWillReceiveProps : ${JSON.stringify(nextProps)}`);
}
shouldComponentUpdate(nextProps: AppProps, nextState: AppState): boolean {
console.log(`App shouldComponentUpdate : ${JSON.stringify(nextProps)}, ${JSON.stringify(nextState)}`);
return true;
}
componentWillUpdate(nextProps: AppProps, nextState: AppState) {
console.log(`App componentWillUpdate : ${JSON.stringify(nextProps)}, ${JSON.stringify(nextState)}`);
}
componentDidUpdate(prevProps: AppProps, prevState: AppState) {
console.log(`App componentDidUpdate : ${JSON.stringify(prevProps)}, ${JSON.stringify(prevState)}`);
}
render() {
console.log('App render');
return (
<div>
<h2>Hello {this.props.name} - {this.state.age}</h2>
<button onClick={this._reset}>리셋</button>
<input type="text" onChange={this._change} value={this.state.company} />
</div>
);
}
private _reset(): void {
this.setState({
age: 35
});
}
private _change(e: React.ChangeEvent<HTMLInputElement>): void {
this.setState({
company: e.target.value
});
}
}
export default App;
// 사용시에 name props 를 쓰지 않으면,
ReactDOM.render(
<App />,
document.getElementById('root') as HTMLElement
);
// 이렇게 name 을 물음표를 이용해 옵셔널하게 처리
export interface AppProps {
name?: string;
}
// 클래스 안에 static 메서드를 이용해서 디폴트 값을 작성한다.
public static defaultProps = {
name: 'Default'
};
// type definition 에 따르면 Props 의 부분집합이다.
defaultProps?: Partial<P>;
export interface AppProps {
name?: string;
}
const StatelessComponent: React.SFC<AppProps> = (props) => {
return (
<h2>{props.name}</h2>
);
}
StatelessComponent.defaultProps = {
name: 'Default'
};
export interface AppProps {
name?: string;
}
const StatelessComponent: React.SFC<AppProps> = ({name = 'Default'}) => {
return (
<h2>{props.name}</h2>
);
}
import * as React from 'react';
import './App.css';
export interface AppProps {
}
export interface AppState {
toGrandChild: string;
}
class App extends React.Component<AppProps, AppState> {
constructor(props: AppProps) {
console.log('App constructor');
super(props);
this.state = {
toGrandChild: '아직 안바뀜'
};
this._clickToGrandChild = this._clickToGrandChild.bind(this);
}
componentWillMount() {
console.log('App componentWillMount');
}
componentDidMount() {
console.log('App componentDidMount');
}
componentWillUnmount() {
console.log('App componentWillUnmount');
}
componentWillReceiveProps(nextProps: AppProps) {
console.log(`App componentWillReceiveProps : ${JSON.stringify(nextProps)}`);
}
shouldComponentUpdate(nextProps: AppProps, nextState: AppState): boolean {
console.log(`App shouldComponentUpdate : ${JSON.stringify(nextProps)}, ${JSON.stringify(nextState)}`);
return true;
}
componentWillUpdate(nextProps: AppProps, nextState: AppState) {
console.log(`App componentWillUpdate : ${JSON.stringify(nextProps)}, ${JSON.stringify(nextState)}`);
}
componentDidUpdate(prevProps: AppProps, prevState: AppState) {
console.log(`App componentDidUpdate : ${JSON.stringify(prevProps)}, ${JSON.stringify(prevState)}`);
}
render() {
console.log('App render');
return (
<div>
<Parent {...this.state} />
<button onClick={this._clickToGrandChild}>GrandChild 의 값을 바꾸기</button>
</div>
);
}
private _clickToGrandChild(): void {
this.setState({
toGrandChild: '그랜드 차일드의 값을 변경'
});
}
}
interface ParentProp {
toGrandChild: string;
}
const Parent: React.SFC<ParentProp> = (props) => {
return (
<div>
<p>여긴 Parent</p>
<Me {...props} />
</div>
);
};
interface MeProp {
toGrandChild: string;
}
const Me: React.SFC<MeProp> = (props) => {
return (
<div>
<p>여긴 Me</p>
<Child {...props} />
</div>
);
};
interface ChildProp {
toGrandChild: string;
}
const Child: React.SFC<ChildProp> = (props) => {
return (
<div>
<p>여긴 Child</p>
<GrandChild {...props} />
</div>
);
};
interface GrandChildProp {
toGrandChild: string;
}
const GrandChild: React.SFC<GrandChildProp> = (props) => {
return (
<div>
<p>여긴 GrandChild</p>
<h3>{props.toGrandChild}</h3>
</div>
);
};
export default App;
import * as React from 'react';
import './App.css';
export interface AppProps {
}
export interface AppState {
fromGrandChild: string;
}
class App extends React.Component<AppProps, AppState> {
constructor(props: AppProps) {
console.log('App constructor');
super(props);
this.state = {
fromGrandChild: '아직 안바뀜'
};
this._clickFromGrandChild = this._clickFromGrandChild.bind(this);
}
componentWillMount() {
console.log('App componentWillMount');
}
componentDidMount() {
console.log('App componentDidMount');
}
componentWillUnmount() {
console.log('App componentWillUnmount');
}
componentWillReceiveProps(nextProps: AppProps) {
console.log(`App componentWillReceiveProps : ${JSON.stringify(nextProps)}`);
}
shouldComponentUpdate(nextProps: AppProps, nextState: AppState): boolean {
console.log(`App shouldComponentUpdate : ${JSON.stringify(nextProps)}, ${JSON.stringify(nextState)}`);
return true;
}
componentWillUpdate(nextProps: AppProps, nextState: AppState) {
console.log(`App componentWillUpdate : ${JSON.stringify(nextProps)}, ${JSON.stringify(nextState)}`);
}
componentDidUpdate(prevProps: AppProps, prevState: AppState) {
console.log(`App componentDidUpdate : ${JSON.stringify(prevProps)}, ${JSON.stringify(prevState)}`);
}
render() {
console.log('App render');
return (
<div>
<Parent clickFromGrandChild={this._clickFromGrandChild} />
<p>{this.state.fromGrandChild}</p>
</div>
);
}
private _clickFromGrandChild(): void {
this.setState({
fromGrandChild: '그랜드 차일드로 부터 값이 변경되었음.'
});
}
}
interface ParentProp {
clickFromGrandChild(): void;
}
const Parent: React.SFC<ParentProp> = (props) => {
return (
<div>
<p>여긴 Parent</p>
<Me {...props} />
</div>
);
};
interface MeProp {
clickFromGrandChild(): void;
}
const Me: React.SFC<MeProp> = (props) => {
return (
<div>
<p>여긴 Me</p>
<Child {...props} />
</div>
);
};
interface ChildProp {
clickFromGrandChild(): void;
}
const Child: React.SFC<ChildProp> = (props) => {
return (
<div>
<p>여긴 Child</p>
<GrandChild {...props} />
</div>
);
};
interface GrandChildProp {
clickFromGrandChild(): void;
}
const GrandChild: React.SFC<GrandChildProp> = (props) => {
return (
<div>
<p>여긴 GrandChild</p>
<button onClick={props.clickFromGrandChild}>GrandChild 버튼</button>
</div>
);
};
export default App;
function SplitPane(props) {
return (
<div className="SplitPane">
<div className="SplitPane-left">
{props.left}
</div>
<div className="SplitPane-right">
{props.right}
</div>
</div>
);
}
function App() {
return (
<SplitPane
left={
<Contacts />
}
right={
<Chat />
} />
);
}
interface CustomTextInputProps {
inputRef(element: HTMLInputElement): void;
}
function CustomTextInput(props: CustomTextInputProps) {
return (
<div>
<input ref={props.inputRef} />
</div>
);
}
function Parent(props: ParentProps) {
return (
<div>
My input: <CustomTextInput inputRef={props.inputRef} />
</div>
);
}
interface ParentProps {
inputRef(element: HTMLInputElement): void;
}
class App extends React.Component<AppProps, AppState> {
inputElement: HTMLInputElement | null;
constructor(props: AppProps) {
console.log('App constructor');
super(props);
}
componentWillMount() {
console.log('App componentWillMount');
}
componentDidMount() {
console.log('App componentDidMount');
}
componentWillUnmount() {
console.log('App componentWillUnmount');
}
componentWillReceiveProps(nextProps: AppProps) {
console.log(`App componentWillReceiveProps : ${JSON.stringify(nextProps)}`);
}
shouldComponentUpdate(nextProps: AppProps, nextState: AppState): boolean {
console.log(`App shouldComponentUpdate : ${JSON.stringify(nextProps)}, ${JSON.stringify(nextState)}`);
return true;
}
componentWillUpdate(nextProps: AppProps, nextState: AppState) {
console.log(`App componentWillUpdate : ${JSON.stringify(nextProps)}, ${JSON.stringify(nextState)}`);
}
componentDidUpdate(prevProps: AppProps, prevState: AppState) {
console.log(`App componentDidUpdate : ${JSON.stringify(prevProps)}, ${JSON.stringify(prevState)}`);
}
render() {
console.log('App render');
return (
<div>
<Parent inputRef={element => this.inputElement = element} />
</div>
);
}
}
export default App;
componentWillReceiveProps(nextProps: AppProps) {
console.log(`App componentWillReceiveProps : ${JSON.stringify(nextProps)}`);
}
shouldComponentUpdate(nextProps: AppProps, nextState: AppState): boolean {
console.log(`App shouldComponentUpdate : ${JSON.stringify(nextProps)}, ${JSON.stringify(nextState)}`);
return true;
}
componentWillUpdate(nextProps: AppProps, nextState: AppState) {
console.log(`App componentWillUpdate : ${JSON.stringify(nextProps)}, ${JSON.stringify(nextState)}`);
}
componentDidUpdate(prevProps: AppProps, prevState: AppState) {
console.log(`App componentDidUpdate : ${JSON.stringify(prevProps)}, ${JSON.stringify(prevState)}`);
}
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate
import * as React from 'react';
import './App.css';
export interface AppProps {
}
export interface AppState {
todo: string[];
}
class App extends React.PureComponent<AppProps, AppState> {
constructor(props: AppProps) {
console.log('App constructor');
super(props);
this.state = {
todo: ['First']
};
this._addSecond = this._addSecond.bind(this);
}
componentWillMount() {
console.log('App componentWillMount');
}
componentDidMount() {
console.log('App componentDidMount');
}
componentWillUnmount() {
console.log('App componentWillUnmount');
}
componentWillReceiveProps(nextProps: AppProps) {
console.log(`App componentWillReceiveProps : ${JSON.stringify(nextProps)}`);
}
/*
shouldComponentUpdate(nextProps: AppProps, nextState: AppState): boolean {
console.log(`App shouldComponentUpdate : ${JSON.stringify(nextProps)}, ${JSON.stringify(nextState)}`);
return true;
}
*/
componentWillUpdate(nextProps: AppProps, nextState: AppState) {
console.log(`App componentWillUpdate : ${JSON.stringify(nextProps)}, ${JSON.stringify(nextState)}`);
}
componentDidUpdate(prevProps: AppProps, prevState: AppState) {
console.log(`App componentDidUpdate : ${JSON.stringify(prevProps)}, ${JSON.stringify(prevState)}`);
}
render() {
console.log('App render');
return (
<div>
<p>{this.state.todo.join(', ')}</p>
<button onClick={this._addSecond}>Second 추가</button>
</div>
);
}
private _addSecond(): void {
const todo: string[] = this.state.todo;
todo.push('Second');
this.setState({
todo: todo
});
}
}
export default App;
By Woongjae Lee
타입스크립트 한국 유저 그룹 리액트 스터디 201706
Daangn - Frontend Core Team ex) NHN Dooray - Frontend Team Leader ex) ProtoPie - Studio Team