Definitelytyped: React.d.ts ์ฝ๊ธฐ ์ „์šฉ<t>์ƒํƒœ ๋ฐ ์†Œํ’ˆ</t>

์— ๋งŒ๋“  2017๋…„ 01์›” 25์ผ  ยท  91์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: DefinitelyTyped/DefinitelyTyped

์•ˆ๋…•ํ•˜์„ธ์š” @ericanderson

์‹ค์ œ๋กœ ์‚ฌ์šฉํ•  ๋•Œ ์ด ๋ณ€๊ฒฝ ์‚ฌํ•ญ ์— ๋งŽ์€ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฌธ์ œ 1: ์ •์˜๋กœ ์ด๋™

props ๋˜๋Š” state์˜ ์†์„ฑ์—์„œ ์ •์˜๋กœ ์ด๋™์„ ๋ˆ„๋ฅด๋ฉด Typescript๊ฐ€ ์ด๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

interface MyComponentProps {
    name: string;
}

export abstract class MyComponent extends React.Component<MyComponentProps , void> {
    myMethood() {
       this.props.name; //<-- Go To definition in name
   }
}

image

๋ฉค๋ฒ„๊ฐ€ ํ•ฉ์„ฑ์ ์œผ๋กœ ์ƒ์„ฑ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ดํ•ด๊ฐ€ ๋˜์ง€๋งŒ ์–ด์จŒ๋“  ์งœ์ฆ๋‚ฉ๋‹ˆ๋‹ค.

๋ฌธ์ œ 2: ๊ตฌ์„ฑ ์š”์†Œ์˜ ๊ณ„์ธต ๊ตฌ์กฐ(์ œ์•ฝ์ด ์žˆ๋Š” ์ผ๋ฐ˜ P)

๋” ์ค‘์š”ํ•œ ๊ฒƒ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ถ”์ƒ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค.

interface MyBaseProps {
    onChange?: (val: any) => void;
}

export abstract class MyBase<P extends MyBaseProps> extends React.Component<P, void> {
    myMethood() {
        this.props.onChange!(2); //The type is S["onChange"] instead of (val: any) => void and so is not invocable. 
   }
}

TS๋Š” onChange ์†์„ฑ์ด ์žˆ์Œ์„ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ์ง€๋งŒ ๋•Œ๋•Œ๋กœ ๊ทธ์˜ ์œ ํ˜•์„ ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

image

if ๊ฐ€ ๊ณตํ†ต ์†Œํ’ˆ๊ณผ ๊ธฐ๋Šฅ์„ ๊ณต์œ ํ•˜๋Š” ๊ตฌ์„ฑ ์š”์†Œ์˜ ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์€ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ ์ž…๋‹ˆ๋‹ค. TS ์ปดํŒŒ์ผ๋Ÿฌ์˜ ๋ฌธ์ œ์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ ์ˆ˜์ •๋  ๋•Œ๊นŒ์ง€์ž…๋‹ˆ๋‹ค.

๋ฌธ์ œ 3: ์ฝ๊ธฐ ์ „์šฉ์ด ์•„๋‹™๋‹ˆ๋‹ค.

์ด ๋ณ€๊ฒฝ์ด React์˜ ๊ธฐ๋Šฅ์  ์˜๋„๋ฅผ ์ž˜ ํฌ์ฐฉํ•œ๋‹ค๋Š” ์ ์—๋Š” ๋™์˜ํ•˜์ง€๋งŒ ์ƒ์„ฑ์ž์—์„œ์™€ ๊ฐ™์ด ๋ช…๋ น์ ์œผ๋กœ ์ƒํƒœ๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๊ณ  ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ  forceUpdate๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๋ชจ๋“  ๊ฒƒ์ด ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™ํ•˜๋Š” ์œ ํšจํ•œ ์ƒํ™ฉ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

C# this.state.name = "John"; this.forceUpdate(); //Ok as long as you don't setState afterwards, but calling setState also is annoying with the callback.

์ถ”์ฒœ์ธ๊ฐ€์š”? ์•„๋‹ˆ์š”.
๊ธˆ์ง€๋˜์–ด ์žˆ์Šต๋‹ˆ๊นŒ? ๋˜ํ•œ ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด forceUpdate๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋ฌผ๋ก  ์ƒํƒœ๋ฅผ S (๋˜๋Š” any )๋กœ ๋ณ€ํ™˜ํ•˜๊ณ  ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์ผ๋ฐ˜์ ์ธ ํŒจํ„ด์ธ ๊ฒฝ์šฐ ๋ฒˆ๊ฑฐ๋กญ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๋ก  : ๊ฐ€์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

TS์˜ ์ƒˆ๋กœ์šด ๋ฐ˜์ง๊ฑฐ๋ฆฌ๋Š” ๊ธฐ๋Šฅ์ด ์ด ๊ฒฝ์šฐ ์†”๋ฃจ์…˜๋ณด๋‹ค ๋” ๋งŽ์€ ๋ฌธ์ œ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์•ˆํƒ€๊น์ง€๋งŒ ์†”์งํžˆ ์—ฌ๊ธฐ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋ฐ˜๋ฉด setState ์˜ ๋ณ€ํ™”๋Š” ๋Œ€๋‹จํ•ฉ๋‹ˆ๋‹ค ๐Ÿ‘ , Pick<S,K> ์— ๋Œ€ํ•ด ๋ชฐ๋ž์Šต๋‹ˆ๋‹ค.

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

๋ฌธ์ œ 3์€ ๋…ผ์Ÿ์˜ ์—ฌ์ง€๊ฐ€ ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

React์—์„œ ์œ„์˜ ์˜ˆ๋ฅผ _๊ธฐ์ˆ ์ ์œผ๋กœ_ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์€ ์˜ณ์ง€๋งŒ, ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด React๊ฐ€ ์‚ฌ์šฉ๋˜๋„๋ก ์˜๋„๋œ ๋ฐฉ์‹์ด ์•„๋‹ˆ๋ผ๊ณ  ํ™•์‹คํžˆ ์ฃผ์žฅํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ 3๊ฐ€์ง€ ๋ณ„๊ฐœ์˜ ๊ฒฝ์šฐ๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ผ๋ฐ˜ ์ดˆ๊ธฐํ™”

interface State {
  bar: number;
}

interface Props {
  baz: number;
}

class Foo extends React.Component<Props, State> {
  public state: State = {
    bar: 5,
  };
}

props ๊ธฐ๋ฐ˜ ์ดˆ๊ธฐํ™”

interface State {
  bar: number;
}

interface Props {
  baz: number;
}

class Foo extends React.Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = {
      bar: props.baz,
    };

    // or
    this.setState({
      bar: props.baz,
    });
  }
}

forceUpdate ๋กœ ๋ฌด์ž‘์œ„ ํ• ๋‹น

์‚ฌ๋žŒ๋“ค์„ "์˜ฌ๋ฐ”๋ฅธ" ๋ฐฉํ–ฅ์œผ๋กœ ๋ฐ€์–ด๋ถ™์ด๋Š” ๊ฒƒ์ด ๋” ๋‚ซ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด public state ๋ฅผ ๋‹ค์‹œ ์„ ์–ธํ•˜์—ฌ ์ด ๋ฌธ์ œ๋ฅผ ์‰ฝ๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

interface State {
  bar: number;
}

class Foo extends React.Component<{}, State> {
  public state: State;
  public myMethod() {
    this.state.bar = 5;
  }
}

๋ชจ๋“  91 ๋Œ“๊ธ€

Visual Studio๋Š” ์–ด๋–ค ๋ฒ„์ „์˜ typescript๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

@vsaio for sa

๋ฌธ์ œ 1์˜ ๊ฒฝ์šฐ TS 2.1.5 ๋ฐ ์ตœ์‹  VSCode๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด ๋ฐฉ๋ฒ•์ด ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” windows/VS๊ฐ€ ์—†์–ด์„œ ๊ฑฐ๊ธฐ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์—†์ง€๋งŒ ํ”Œ๋Ÿฌ๊ทธ์ธ์— ๋Œ€ํ•œ ์—…๋ฐ์ดํŠธ๊ฐ€ ์žˆ๊ฑฐ๋‚˜ TS 2.1.5์— ์žˆ์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ฌธ์ œ 2์™€ ๋™์ผ

VS 2015(TS 2.1.5.0 ํฌํ•จ)

๋ฌธ์ œ 3์€ ๋…ผ์Ÿ์˜ ์—ฌ์ง€๊ฐ€ ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

React์—์„œ ์œ„์˜ ์˜ˆ๋ฅผ _๊ธฐ์ˆ ์ ์œผ๋กœ_ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์€ ์˜ณ์ง€๋งŒ, ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด React๊ฐ€ ์‚ฌ์šฉ๋˜๋„๋ก ์˜๋„๋œ ๋ฐฉ์‹์ด ์•„๋‹ˆ๋ผ๊ณ  ํ™•์‹คํžˆ ์ฃผ์žฅํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ 3๊ฐ€์ง€ ๋ณ„๊ฐœ์˜ ๊ฒฝ์šฐ๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ผ๋ฐ˜ ์ดˆ๊ธฐํ™”

interface State {
  bar: number;
}

interface Props {
  baz: number;
}

class Foo extends React.Component<Props, State> {
  public state: State = {
    bar: 5,
  };
}

props ๊ธฐ๋ฐ˜ ์ดˆ๊ธฐํ™”

interface State {
  bar: number;
}

interface Props {
  baz: number;
}

class Foo extends React.Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = {
      bar: props.baz,
    };

    // or
    this.setState({
      bar: props.baz,
    });
  }
}

forceUpdate ๋กœ ๋ฌด์ž‘์œ„ ํ• ๋‹น

์‚ฌ๋žŒ๋“ค์„ "์˜ฌ๋ฐ”๋ฅธ" ๋ฐฉํ–ฅ์œผ๋กœ ๋ฐ€์–ด๋ถ™์ด๋Š” ๊ฒƒ์ด ๋” ๋‚ซ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด public state ๋ฅผ ๋‹ค์‹œ ์„ ์–ธํ•˜์—ฌ ์ด ๋ฌธ์ œ๋ฅผ ์‰ฝ๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

interface State {
  bar: number;
}

class Foo extends React.Component<{}, State> {
  public state: State;
  public myMethod() {
    this.state.bar = 5;
  }
}

๋‚ด ๋ฌธ์ œ๋Š” ์ œ๋„ค๋ฆญ ๋ถ„์‚ฐ์— ์žˆ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ์ผ๋ฐ˜์ ์œผ๋กœ ์ž…๋ ฅ๋˜๋Š” ํด๋ž˜์Šค ๋‚ด์—์„œ ์ž…๋ ฅํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์•„๋ž˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ณณ์˜ ์•„์ฃผ ์ตœ์†Œํ•œ์˜ ์ƒ˜ํ”Œ์ž…๋‹ˆ๋‹ค.

class TBaseState {
  public value: string;
}

function globalFunc<T extends Readonly<TBaseState>>(item: T) {
}

class MyComponent<TProps, TState extends TBaseState> extends React.Component<TProps, TState> {
  broken() {
    // typing of this.state is Readonly<TState>
    // this is not assignable to Readonly<TBase>
    globalFunc(this.state);

    // this is a horrible hack to fix the generics variance issue
    globalFunc(this.state as TState as Readonly<TBaseState>);
  }
}

class MyState extends TBaseState {
}

let component: MyComponent<any, MyState>;

// here the typing of component.state is Readonly<MyState>
// this is assignable to Readonly<TBase>
globalFunc(component.state);

๋‚˜๋Š” TS 2.1.5.0์—์žˆ๋‹ค

image

๊ทธ๋Ÿฌ๋‚˜ VS์—์„œ VS ์ฝ”๋“œ๋ณด๋‹ค ์ตœ์•…์˜ TS ๊ฒฝํ—˜์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค...

๋ฌธ์ œ 1์˜ ๊ฒฝ์šฐ ์ •์˜๋กœ ์ด๋™ TS๋Š” VS ์ฝ”๋“œ์—์„œ๋„ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

interface MyComponentProps {
    name: string;
}

export abstract class MyComponent extends React.Component<MyComponentProps , void> {
    fullName: string;
    myMethood() {
       this.props.name; //<-- doesnt work
       this.fullName; //<-- works
   }
}

๋ฌธ์ œ 2์˜ ๊ฒฝ์šฐ VS Code๊ฐ€ ๋” ์ž˜ ์ž‘๋™ํ•œ๋‹ค๋Š” ๊ฒƒ์€ ์‚ฌ์‹ค์ž…๋‹ˆ๋‹ค.

image

VS๊ฐ€ ํ˜ผ๋ž€์Šค๋Ÿฌ์›Œ ๋ณด์ด๋Š” ๋™์•ˆ:

image

VSCode ๋ฐ ๋ฌธ์ œ 1์˜ ๊ฒฝ์šฐ ๋” ๋˜‘๋˜‘ํ•œ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ "์ตœ์‹  Typescript ๋ฐ Javascript ๋ฌธ๋ฒ•"์šฉ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ž‘๋™ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

@patsissons ํฅ๋ฏธ๋กœ์šด ์˜ˆ์ง€๋งŒ ์ •์˜ ํŒŒ์ผ์˜ ๋ฒ„๊ทธ๋ณด๋‹ค typescript์˜ ๋ฒ„๊ทธ๋ฅผ ๋” ์ž˜ ๋Œ€ํ‘œํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, setState ๋Š” S ๋ฅผ ์ทจํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์šฐ๋ฆฌ๊ฐ€ setState({foo:5} as any as State) ์™€ ๊ฐ™์€ ์ด์ƒํ•œ ํŠธ๋ฆญ์„ ์ˆ˜ํ–‰ํ•˜๊ฑฐ๋‚˜ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ๋ถ€๋ถ„์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ–ˆ์Šต๋‹ˆ๋‹ค. ์ปดํŒŒ์ผ๋Ÿฌ์˜ ํ‘œํ˜„๋ ฅ ๋ถ€์กฑ์œผ๋กœ ์ธํ•ด ์ž…๋ ฅ์ด "์ž˜๋ชป"๋˜๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ด๊ฒƒ์ด ์ด ๊ทน๋‹จ์ ์ธ ๊ฒฝ์šฐ๋ฅผ ํ‘œ์‹œํ•˜๊ธฐ ์œ„ํ•ด README๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•œ ์ ์ ˆํ•œ ์ฃผ์žฅ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

TS์— ๋ฌธ์ œ๋ฅผ ์ œ์ถœํ•˜์…จ์Šต๋‹ˆ๊นŒ?

๋”ฐ๋ผ์„œ ์ด ๋ณ€๊ฒฝ ์‚ฌํ•ญ์€ ์š”์ฆ˜ ๋ชจ๋“  VS๋ฅผ ์ค‘๋‹จํ•˜๊ณ  ํ”Œ๋Ÿฌ๊ทธ์ธ์ด ์žˆ๋Š” ๊ฒฝ์šฐ๋ฅผ ์ œ์™ธํ•˜๊ณ  ๋ชจ๋“  VS ์ฝ”๋“œ์—์„œ ์ •์˜๋กœ ์ด๋™์„ ๋น„ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค...

๋˜ํ•œ ์™„์ „์„ฑ ์ฃผ์žฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ์˜๋„๋œ API๊ฐ€ ์ˆ˜์‹ญ์–ต ๊ฐœ ์žˆ์œผ๋ฉฐ ์š”์ฆ˜์—๋Š” ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‹จ์ง€ React.d.ts์—๋งŒ ์žˆ์Šต๋‹ˆ๋‹ค.

 interface ComponentLifecycle<P, S> {
        componentWillMount?(): void;
        componentDidMount?(): void;
        componentWillReceiveProps?(nextProps: Readonly<P>, nextContext: any): void;
        shouldComponentUpdate?(nextProps: Readonly<P>, nextState: Readonly<S>, nextContext: Readonly<any>): boolean;
        componentWillUpdate?(nextProps: Readonly<P>, nextState: Readonly<S>, nextContext: Readonly<any>): void;
        componentDidUpdate?(prevProps: Readonly<P>, prevState: Readonly<S>, prevContext: Readonly<any>): void;
        componentWillUnmount?(): void;
    }

์˜ˆ๋ฅผ ๋“ค์–ด ์ด๋ฒคํŠธ ๊ฐœ์ฒด์™€ ๊ฐ™์ด ์ˆ˜์ •๋˜์ง€ ์•Š๋Š” ๊ธด ๊ผฌ๋ฆฌ๊ฐ€ ์•„๋‹Œ '๊ณ ์ •' ๋˜๋Š” 'Inmmutable.js'์— readonly๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์ œ์ถœํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์ €๋Š” ์˜ค๋Š˜ ์ƒˆ๋กœ์šด Readonly<T> ์œ ํ˜•์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์ฝ”๋“œ๋ฅผ ๊ฐœ์กฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ œ๋Œ€๋กœ ์ž…๋ ฅ๋œ ์†”๋ฃจ์…˜์ด ์—†๋Š” ๊ฒฝ์šฐ์˜€์Šต๋‹ˆ๋‹ค. ๊ณ„์†ํ•ด์„œ ๋ฌธ์ œ๋ฅผ ์ œ๊ธฐํ•˜์„ธ์š”. ์ €๋Š” ์˜ค๋Š˜ ํ•˜๋ฃจ ์ค‘ ๋Œ€๋ถ€๋ถ„์˜ ์‹œ๊ฐ„์„ ์ฝ”๋“œ ํŒจ์น˜๋กœ ๋ฐ”์  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์•„ ์˜ˆ, ์ œ๊ฐ€ ๋†“์นœ ๋ถ€๋ถ„์ด ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. @olmobrutall ์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ํ‘œ์‹œํ•˜๊ธฐ ์œ„ํ•ด ๋„์ž…ํ•œ ์ƒํƒœ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์œ ์ง€ํ•œ๋‹ค๋ฉด ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋ฅผ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•œ๋‹ค๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋จผ์ € ํ•ด์•ผ ํ•  ์˜ณ์€ ์ผ์— ๋Œ€ํ•œ ํ•ฉ์˜๊ฐ€ ํ•„์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

VS ๋ธŒ๋ ˆ์ดํฌ์— ๊ด€ํ•ด์„œ๋Š” ๋ฌด์—‡์ด ์˜ณ์€์ง€ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ผ๋ถ€ ๋„๊ตฌ๊ฐ€ ์ตœ์‹  ์ƒํƒœ๋กœ ์œ ์ง€๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์œ ํ˜•์„ ๋ณด๋ฅ˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

@patsisson ๋ชจ๋“  ์ฝ”๋“œ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ ์ „์— ์ด๊ฒƒ์ด ์–ด๋–ป๊ฒŒ ์ง„ํ–‰๋˜๋Š”์ง€ ๋ณด๊ณ  ์‹ถ๋‹ค๋ฉด ์ง€๊ธˆ ๋‹น์žฅ์€ ๋ฐ˜์‘์— ๋Œ€ํ•œ ์ž์‹ ๋งŒ์˜ ํƒ€์ดํ•‘์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. https://ericlanderson.com/using-custom-typescript-definitions-with-ts-2-x-3121db84015d#.ftlkojwnb

์šฐ๋ฆฌ์˜ ๊ฒฝํ—˜์— ๋”ฐ๋ฅด๋ฉด VS๋Š” ํ•ญ์ƒ ์•ฝ๊ฐ„ ๋’ค์ณ์ ธ ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ ๊ฐ€๊ฒŒ๋Š” ํ™œ์„ฑ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ๊ฐœ๋ฐœ์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด vscode๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ, VS๋Š” ๋‹จ์ˆœํžˆ ์ฝ”๋“œ ํŒŒ์ผ์„ ํŒจ์น˜ํ•˜๊ฑฐ๋‚˜ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์•„๋‹Œ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๋Š” ๋ฐ ๋” ๋งŽ์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

@ericanderson ์ง€๊ธˆ ์€ ํ•ดํ‚น ์ด ๊ทธ๋ ‡๊ฒŒ ๋‚˜์˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Readonly<Base> T $ ๋ฅผ ์–ป์œผ๋ ค๋ฉด Readonly<T> ๋ฅผ ์–ป์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” 'react.d.ts'์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋‹จ์ผ ๋ฉค๋ฒ„ ์„ ์–ธ์€ ๋งŽ์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. VS๊ฐ€ ์ค€๋น„๋  ๋•Œ๊นŒ์ง€ ๋ณด๋ฅ˜ํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ ์ „ ์„ธ๊ณ„ ์œ ํ˜•์˜ 50%๊ฐ€ API์—์„œ ๊ฐ€์ ธ์˜จ ๊ฐœ์ฒด์™€ ๊ฐ™์ด ์ฝ๊ธฐ ์ „์šฉ์ด๋ฏ€๋กœ ์ฃผ์„์„ ๋‹ฌ ํ•„์š”๊ฐ€ ์—†๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

Get-only ์†์„ฑ์„ ๊ฐ–๋„๋ก ๋ช…์‹œ์ ์œผ๋กœ ๋ณ€ํ™˜๋œ ๊ฐœ์ฒด์—๋Š” Readonly๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋™๊ฒฐ์ฒ˜๋Ÿผ.

@olmobrutall Readonly ๋Š” ์ƒˆ๋กœ์šด ๊ฒƒ์ด๋ฏ€๋กœ ์ •ํ™•ํ•œ ๋ชจ๋ฒ” ์‚ฌ๋ก€๊ฐ€ ์‹ค์ œ๋กœ ์ •์˜๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ €๋Š” ๊ฐœ์ธ์ ์œผ๋กœ ๋ชจ๋“  ๊ฒƒ์ด Readonly<> ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ๋‚˜ํƒ€๋‚ด๋Š” ๋ฐ ๋„์›€์ด ๋œ๋‹ค๊ณ  ์„ ์–ธํ•˜๋Š” ๊ฒƒ์„ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค. ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ React๋Š” setState state ๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ์„ ๊ธฐ๋Œ€ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์ด ๋ณ€๊ฒฝ์œผ๋กœ ์ธํ•ด ์‚ฌ๊ณ ๋กœ ์ธํ•ด ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ณด๋‹ค TypeScript๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ฃผ์š” ์ด์  ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค.

Object.freeze ์— ๋Œ€ํ•ด ๋ธŒ๋ผ์šฐ์ € ๊ฐ„์— ์„ฑ๋Šฅ์ด ๋” ์ผ๊ด€์ ์ด์—ˆ๋‹ค๋ฉด React ์‚ฌ๋žŒ๋“ค์ด setState ์ดํ›„์— ์‹ค์ œ๋กœ ๋ฉˆ์ถ”๊ธฐ ์‹œ์ž‘ํ•  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

forceUpdate์˜ ๋ชฉ์ ์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

๋‚˜๋Š” ๋„๊ตฌ ์—…๋ฐ์ดํŠธ์™€ ๊ด€๋ จํ•˜์—ฌ ํ™•์‹คํžˆ ์œ ํ˜•์ด ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•ด์•ผ ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์˜ ์ƒ๊ฐ๊ณผ ๋ฐ˜์‘์— ๋Œ€ํ•œ ์ฝ๊ธฐ ์ „์šฉ์— ๋Œ€ํ•œ ์ฒ ํ•™(๋ฐ ํŠน์ • ๊ฐœ์ฒด๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์˜๋„๋ฅผ ๊ฐ€์ง„ ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ)์— ๋Œ€ํ•œ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์˜ ์ƒ๊ฐ์ด ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค.

cc/ @johnnyreilly @vsaio @pspeter3 ๋ฐ˜์‘์— ๋Œ€ํ•œ ์ƒ๊ฐ๊ณผ ์ผ๋ฐ˜์ ์ธ ๋‹ค๋ฅธ ์ƒ๊ฐ
cc/ @andy-ms @mhegazy ๋Š” ํˆด๋ง ์—…๋ฐ์ดํŠธ์™€ Readonly ์˜ ์—ด์„ฑ์ ์ธ ์‚ฌ์šฉ์„ ์œ„ํ•ด ํ™•์‹คํžˆ Typed๊ฐ€ ์–ด๋–ป๊ฒŒ ์ฒ ํ•™์ ์œผ๋กœ ์ง„ํ–‰๋˜์–ด์•ผ ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ์ƒ๊ฐ์ž…๋‹ˆ๋‹ค.

@olmobrutall ์šฐ๋ฆฌ๋Š” forceUpdate ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒํƒœ ์ธก์˜ ๊ด€์ฐฐ ๊ฐ€๋Šฅํ•œ ์ด๋ฒคํŠธ์—์„œ ๊ตฌ๋™๋˜๋Š” ๋ฐ˜์‘ ์ธก์˜ ๋ Œ๋”๋ฅผ ๋Œ€๊ธฐ์—ด์— ๋„ฃ์Šต๋‹ˆ๋‹ค.

์—…๋ฐ์ดํŠธ :
์˜คํ•ด๊ฐ€ ์—†๋„๋ก ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์กฐ๊ธˆ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์ƒํƒœ ๊ฐœ์ฒด๋Š” ์˜ค๋ž˜ ์ง€์†๋˜๋Š” ๋ถˆ๋ณ€ ๊ฐœ์ฒด์ž…๋‹ˆ๋‹ค(๋”ฐ๋ผ์„œ Readonly<T> ๋Š” ์‹ค์ œ๋กœ ์šฐ๋ฆฌ์—๊ฒŒ ๋งค์šฐ ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค). ์ด๋Ÿฌํ•œ ์ƒํƒœ ๊ฐœ์ฒด์—๋Š” stateChanged ๋ผ๋Š” ์•Œ๋ฆผ ๊ด€์ฐฐ ๊ฐ€๋Šฅ ํ•ญ๋ชฉ์œผ๋กœ ์œ ์ž…๋˜๋Š” ์—ฌ๋Ÿฌ rxjs ๊ด€์ฐฐ ๊ฐ€๋Šฅ ์ŠคํŠธ๋ฆผ์ด ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. React ๊ตฌ์„ฑ ์š”์†Œ๋Š” ์ด๋ฒคํŠธ์— ๋Œ€ํ•ด ์ด ์˜ต์ €๋ฒ„๋ธ”์„ ๊ด€์ฐฐํ•˜๊ณ  ํ•ด๋‹น ์ด๋ฒคํŠธ๋ฅผ forceUpdate ์— ๋Œ€ํ•œ ํ˜ธ์ถœ๋กœ ์œ ์ž…ํ•ฉ๋‹ˆ๋‹ค(๋””๋ฐ”์šด์‹ฑ ํ›„). ์‚ฌ์‹ค์ƒ ์šฐ๋ฆฌ์˜ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ๋Š” ์ƒํƒœ ๋‚ด์— ์žˆ์ง€๋งŒ ์ƒํƒœ ์ž์ฒด์™€ ์ƒํƒœ์— ์กด์žฌํ•˜๋Š” ๋ฉค๋ฒ„๋Š” ๋ชจ๋‘ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ํ™•์‹คํžˆ React์˜ ํ‘œ์ค€ ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ์•„๋‹ˆ์ง€๋งŒ ํ๋ฆ„์ด ๋งค์šฐ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์žฌ๋ Œ๋”๋ง์ด ํ•„์š”ํ•  ๋•Œ ๊ตฌ์„ฑ ์š”์†Œ์— ์•Œ๋ฆฌ๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ๊ณ  ์žˆ๋Š” ์Šค๋งˆํŠธ ์ƒํƒœ ๊ฐœ์ฒด๋งŒ ์žˆ์œผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

@ericanderson ์ฃผ์š” ๋ฌธ์ œ๋Š” ์ด๋Ÿฌํ•œ ์œ ํ˜• ์ •์˜๊ฐ€ SemVer ๋ฌธ์ œ๋กœ ๊ณ ํ†ต๋ฐ›๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์œ ํ˜• ์ •์˜ ๋ฒ„์ „์€ ํ•ด๋‹น ๋ชจ๋“ˆ ๋ฒ„์ „์— ํฌ๊ฒŒ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์œ ํ˜• ์ •์˜ ๋ณ€๊ฒฝ์„ ์ผ์œผํ‚ค๋Š” ๋ถ€ ๋ฒ„์ „ ๋ฒ”ํ”„๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” @types ๋ฒ„์ „์„ package.json ์— ๊ณ ์ •ํ•ด์•ผ ํ•จ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ํŒŒ์ผ.

@olmobrutall ๋ฐ˜์‘ ๋ฌธ์„œ์—์„œ:

์ผ๋ฐ˜์ ์œผ๋กœ forceUpdate()์˜ ๋ชจ๋“  ์‚ฌ์šฉ์„ ํ”ผํ•˜๊ณ  render()์˜ this.props ๋ฐ this.state๋งŒ ์ฝ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ฐ˜์‘ ๊ฐ€์ด๋“œ๋Š” ์‚ฌ์‹ค ์ƒํƒœ๋ฅผ ์ง์ ‘ ์—…๋ฐ์ดํŠธํ•˜์ง€ ๋ง๋ผ๊ณ  ์•Œ๋ ค์ค๋‹ˆ๋‹ค: https://facebook.github.io/react/docs/state-and-lifecycle.html#do -not-modify-state-directly

forceUpdate ๋Š” ๋‚ด๊ฐ€ ์ฝ์€ ๋Œ€๋กœ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ props ๋˜๋Š” state์˜ _not_ ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•  ๋•Œ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๊ฐ•์ œ๋กœ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@patsisson ๋‚ด๊ฐ€ ํ‹€๋ฆด ์ˆ˜๋„ ์žˆ์ง€๋งŒ SemVer๊ฐ€ API ๋ฐ ์˜๋ฏธ๋ก ์  ์˜๋„์™€ ์—ญํ˜ธํ™˜๋˜๋„๋ก ์„ค๊ณ„๋˜์—ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์˜๋„ํ•˜์ง€ ์•Š์€ ๋ฐฉ์‹์œผ๋กœ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•ด์„œ(๋ฌธ์„œ์— ๋”ฐ๋ผ) ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์˜๋„ํ•˜์ง€ ์•Š์€ ์‚ฌ์šฉ์„ ๊ณ„์† ์ง€์›ํ•ด์•ผ ํ•œ๋‹ค๋Š” ์˜๋ฏธ๋Š” ์•„๋‹™๋‹ˆ๋‹ค. ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ž‘์„ฑ์ž๋Š” SemVer ๋‚ด์—์„œ ์ •ํ™•ํ•˜์ง€ ์•Š์ง€๋งŒ ์ผ๋ถ€ ์‚ฌ๋žŒ๋“ค์ด ์‚ฌ์šฉํ•˜๊ฒŒ ๋œ ์˜๋ฏธ ์ฒด๊ณ„๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฆ‰, Readonly<> ์—์„œ state ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์€ ๋„ˆ๋ฌด ํฐ ๋ณ€๊ฒฝ์ด์ง€๋งŒ ์ž ์‹œ ๋™์•ˆ ์˜ฌ๋ฐ”๋ฅธ ๋ณ€๊ฒฝ์ด๋ผ๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค. ์–ธ์ œ ํ™•์‹คํžˆ Typed๋กœ ์ถœ์‹œ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๊นŒ? state ๋ฅผ Readonly<> ๋กœ ํ‘œ์‹œํ•˜๋Š” ์—…๋ฐ์ดํŠธ๋ฅผ ๋ฐ›์œผ๋ฉด ์ฝ”๋“œ๋ฅผ ํ•ญ์ƒ ๋ณ€๊ฒฝํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ์—ฌ์ „ํžˆ Readonly<> ๊ฐ€ state ์— ์ ์šฉ๋˜์–ด semver, tooling ๋˜๋Š” ๋‹ค๋ฅธ ๊ฒƒ์— ๋Œ€ํ•ด ํ† ๋ก ํ•˜๊ธฐ ์–ด๋ ต๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์˜ณ์€์ง€ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‚ด ์ง๊ฐ์€ ์˜ณ์•˜๋‹ค. ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๊ฒ€ํ† ํ•œ ์‚ฌ๋žŒ๋“ค์€ ๊ทธ๊ฒƒ์„ ๋ฌธ์ œ๋กœ ์ œ๊ธฐํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. React ํŒ€์˜ ์˜๋„์™€ ์ผ์น˜ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ํ™•์‹คํžˆ Typed์— ๋Œ€ํ•œ ๋ฐ˜์‘์— ๋Œ€ํ•ด ๋ฆฌ๋ทฐ์–ด๋“ค์—๊ฒŒ ๋งก๊ธธ ์ˆ˜ ์žˆ์–ด ๊ธฐ์ฉ๋‹ˆ๋‹ค(์œ„์—์„œ ๋ชจ๋‘ ์ฐธ์กฐํ–ˆ์Šต๋‹ˆ๋‹ค).

๋”ฐ๋ผ์„œ Observable์€ ๊ฐ•์ œ ์—…๋ฐ์ดํŠธ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๊นŒ? ๋”ฐ๋ผ์„œ ์ƒํƒœ๋ฅผ ๋ช…๋ น์ ์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์€ ์–ด๋Š ์ •๋„ ํ—ˆ์šฉ๋ฉ๋‹ˆ๋‹ค.

Readonly๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์œ„์น˜๊ฐ€ 100% ์ •์˜๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•˜์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋„๊ตฌ๊ฐ€ ์ค€๋น„๋˜๊ธฐ ์ „์— ๋…ผ๋ž€์˜ ์—ฌ์ง€๊ฐ€ ๋งŽ๊ณ  ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” ์ž์‚ฐ์œผ๋กœ ์‹œ์ž‘ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

์ €๋Š” ๋ชจ๋‘ ๊ฐ•๋ ฅํ•œ ํ˜•์‹์„ ์‚ฌ์šฉํ•˜๊ณ  strictNullChecks๊ฐ€ ์žˆ๋Š” 6๊ฐœ์˜ ํ”„๋กœ์ ํŠธ๋ฅผ ๋ชจ๋‘ ๊ด€๋ฆฌํ•˜์ง€๋งŒ ์—ฌ๊ธฐ์—์„œ ์–ป๋Š” ์ด์ ์€ ํ˜„์žฌ ์ƒ์„ฑํ•˜๋Š” ๋ฌธ์ œ๋ณด๋‹ค ํ›จ์”ฌ ์ ์Šต๋‹ˆ๋‹ค.

@ericanderson ๋‚˜๋Š” SemVer2๊ฐ€ ^15.0.0 ์™€ ๊ฐ™์€ ๋…ธ๋“œ ๋ฒ„์ „ ์„ ์–ธ์„ ํ—ˆ์šฉํ•˜๋„๋ก ์„ค๊ณ„๋˜์—ˆ์œผ๋ฉฐ ๋ชจ๋“ˆ์— ๋Œ€ํ•œ ๋ชจ๋“  ๋งˆ์ด๋„ˆ ๋˜๋Š” ํŒจ์น˜ ์—…๊ทธ๋ ˆ์ด๋“œ(์˜ˆ: 15.0.1 ๋˜๋Š” 15.1.0 )๊ฐ€ ํˆฌ๋ช…ํ•˜๊ฑฐ๋‚˜ ์ ์–ด๋„ ์™ธ๋ถ€ ๊ด€์ ์—์„œ ์ด์ „ ๋ฒ„์ „๊ณผ ํ˜ธํ™˜๋ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ์ฃผ์š” ์—…๊ทธ๋ ˆ์ด๋“œ( 16.0.0 )๋Š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋ฒ„์ „ ์„ ์–ธ์„ ์กฐ์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋ณธ์งˆ์ ์œผ๋กœ ์ฃผ์š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ํƒ€์ดํ•‘ ์‹œ์Šคํ…œ์œผ๋กœ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์„ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํ˜„์žฌ ์œ ํ˜• ์ •์˜ ๋ฒ„์ „์€ ํ•ด๋‹น ๋ชจ๋“ˆ ๋ฒ„์ „(๊ด€๋ก€์— ๋”ฐ๋ผ)์—์„œ ๋ฒ—์–ด๋‚  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ์ด๋Ÿฌํ•œ ๋ถˆ์—ฐ์†์„ฑ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์งง์€ ๋ฒ„์ „์€ ์œ ํ˜• ์ •์˜๊ฐ€ ๋ชจ๋“ˆ ์ž์ฒด๋ฅผ ์ „ํ˜€ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ ๋„ ๋„์ž…๋œ ์ฃผ์š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ฃผ์š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ์—๋Š” ์ฃผ์š” ๋ฒ„์ „ ๋ฒ”ํ”„๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ PR์„ ์ œ๊ฑฐํ•˜๋Š” forceUpdate๋ฅผ ๋งŒ๋“ค์ง€๋Š” ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ฃ ?

๊ทธ๋Ÿฐ ๋‹ค์Œ forceUpdate๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์ƒํƒœ๋ฅผ ๋ฐ˜๋“œ์‹œ ๋ณ€๊ฒฝํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด๋ก ์ƒ์œผ๋กœ๋Š” ๊นŠ์€ ๋ถˆ๋ณ€ ์ƒํƒœ ๊ทธ๋ž˜ํ”„๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜์ง€๋งŒ ๋งค์šฐ ์ž์ฃผ ์ƒํƒœ๋ฅผ ๋ช…๋ น์ ์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์€ ๊ดœ์ฐฎ๊ณ  ๋ชจ๋“  ๊ฐœ๋ฐœ์ž๊ฐ€ ์˜๊ตฌ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ์•„์ด๋””์–ด๋ฅผ ๋ฐ›์•„๋“ค์ด๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.

๋‹คํ–‰ํžˆ React๋Š” ์Šค์ผ€์ดํ”„ ๊ฒฝ๋กœ๋ฅผ ํ—ˆ์šฉํ•˜๊ณ  ์ƒํƒœ๋ฅผ ์ง์ ‘ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. TS ๊ฐœ๋ฐœ์ž๊ฐ€ ํ•ด๋‹น ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ธˆ์ง€ํ• ๊นŒ์š”? ๋„ˆ๋ฌด ๊ฐ€๋ถ€์žฅ์ ์ธ๊ฑฐ ์•„๋‹™๋‹ˆ๊นŒ?

์˜ˆ๋ฅผ ๋“ค์–ด Vue.js๋Š” ๋ช…๋ น์  ๋ณ€๊ฒฝ์„ ์ด‰์ง„ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์ด React์— ์˜ํ–ฅ์„ ์ค€๋‹ค ํ•ด๋„ ๋†€๋ผ์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋˜ํ•œ ๋‚˜๋Š” ์–ผ๋งˆ ์ „์— ๋ชจ๋“  Redux ํ–‰์‚ฌ ์—†์ด React ์‚ฌ์šฉ์„ ๊ถŒ์žฅํ•˜๋Š” React ์ž‘์„ฑ์ž์˜ ๋ธ”๋กœ๊ทธ ๊ฒŒ์‹œ๋ฌผ์„ ์ฝ๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค(๊ธฐ์–ตํ•  ์ˆ˜ ์žˆ์Œ).

๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ๋‚ด ์ž…์žฅ์€ ๊ฐ€๋Šฅํ•œ ํ•œ ๋นจ๋ฆฌ ์œ ํ˜• ์ •์˜๋ฅผ ๊ฒŒ์‹œํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‚ด ์œ ์ผํ•œ ๊ด€์‹ฌ์‚ฌ๋Š” ์ž๋™ํ™”์ž…๋‹ˆ๋‹ค. ์œ ํ˜• ์ •์˜ ๋ฒ„์ „ ๊ด€๋ฆฌ์˜ ํ˜„์žฌ ์ƒํƒœ๊ฐ€ ์ฃผ์–ด์ง€๋ฉด ์†Œ์Šค ๋ณ€๊ฒฝ ์—†์ด ์—ฐ์† ๋นŒ๋“œ๊ฐ€ ์ค‘๋‹จ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์œ ํ˜•์˜ ๋น„๊ฒฐ์ •์  CI ์‹คํŒจ๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ํ‘ธ์‹œํ•œ ๋‹ค์Œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ๋นŒ๋“œ ์ค‘๋‹จ๊ณผ ๊ด€๋ จ์ด ์—†์Œ์„ ์•Œ๊ธฐ ๋•Œ๋ฌธ์— ์•„๋ฌด๋„ ๋นŒ๋“œ ์ค‘๋‹จ์„ ๋ณด๊ณ  ์‹ถ์–ดํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ž๊ณ  ๋‚˜์„œ ๊ฐœ์ธ์ ์ธ ์˜๊ฒฌ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ์ข‹์€ ๋ฐฉ๋ฒ•์€ ์›์‚ฌ ๋˜๋Š” npm ์ž ๊ธˆ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋ฏ€๋กœ ๋กœ์ปฌ์—์„œ ๋จผ์ € ์—…๊ทธ๋ ˆ์ด๋“œํ•˜์ง€ ์•Š๋Š” ํ•œ ๋†€๋ผ์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  • ์ƒํƒœ๋ฅผ ์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ React๊ฐ€ ์‚ฌ์šฉ๋˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ๋ฌธ์„œ์™€ ์˜ˆ์ œ๊ฐ€ ์ด๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • setState๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ ค๋Š” ์›Œํฌํ”Œ๋กœ๋Š” ์ฝ”๋“œ ๊ธฐ๋ฐ˜ ๋ฐ ๊ณ ์œ  ๊ถŒํ•œ ๋‚ด์— ์žˆ์Šต๋‹ˆ๋‹ค. React๊ฐ€ forceUpdate๋ฅผ ์ œ๊ณตํ•œ๋‹ค๋Š” ๊ฒƒ์€ ๋งž์ง€๋งŒ ์˜๋„ํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ๋ฒ—์–ด๋‚  ๋•Œ ๋ Œ๋”๋ง์„ ์ผ์œผํ‚ค๊ธฐ ์œ„ํ•œ ์šฉ๋„์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์˜๋„ํ•œ ๋Œ€๋กœ ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์ง€ ์•Š๋‹ค๋ฉด ๊ดœ์ฐฎ์ง€๋งŒ ๊ทธ ์‹œ์ ์—์„œ๋Š” ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜ ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ์ผ๋ฐ˜ ๊ฐœ์ธ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์˜ˆ, ์ด ํ”„๋กœ์ ํŠธ๋Š” ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ์˜์กดํ•˜๊ณ  ์žˆ์ง€๋งŒ ์ง€๊ธˆ๊นŒ์ง€ ์ด๊ฒƒ์ด ๋„๋ฆฌ ํผ์ง„ ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋ผ๊ณ  ์ƒ๊ฐํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ์œ ์ผํ•œ ๋‘ ๊ฐ€์ง€ ๋ถˆ๋งŒ ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ ์ „์—ญ ํ•จ์ˆ˜์— ๋Œ€ํ•ด ์ œ๊ธฐ๋œ ๋ฌธ์ œ๋Š” ์ œ๋„ค๋ฆญ์„ ๋‹ค๋ฅด๊ฒŒ ์‚ฌ์šฉํ•˜๋„๋ก ๋‹ค์‹œ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(์—ฐ๊ฒฐ๋œ TypeScript ๋ฌธ์ œ ์ฐธ์กฐ).

์œ„์˜ ์ƒ๊ฐ๊ณผ ๋น„ํ‘œ์ค€ React ์•ฑ์— ๋Œ€ํ•œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ๊ฐ์•ˆํ•  ๋•Œ Readonly๊ฐ€ ์˜ณ๊ณ  ์™„์ „์„ฑ์„ ์œ„ํ•ด ํ•„์š”ํ•œ ์œ ์ผํ•œ ๋ณ€๊ฒฝ์€ ์ผ์น˜ํ•˜๋„๋ก ์ˆ˜๋ช… ์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์™„์ „ํžˆ ์˜๋ฏธ๊ฐ€ ์žˆ๋‹ค๋Š” ์ ์— ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚จ ์ œ ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ๊ฑฐ์˜ ๋ฐœ์ƒํ•˜์ง€ ์•Š์•„์•ผ ํ•˜๋Š” ๋งค์šฐ ๋…ํŠนํ•œ ์ฝ”๋„ˆ ์‚ฌ๋ก€์˜€์Šต๋‹ˆ๋‹ค. ๋‚ด ์ฝ”๋“œ ๊ธฐ๋ฐ˜์„ ์ฝ๊ธฐ ์ „์šฉ props ๋ฐ state์— ์ ์šฉํ•จ์œผ๋กœ์จ ๊ฐ์ง€ํ•  ์ˆ˜ ์—†๋Š” ํƒ€์ดํ•‘ ๋ฌธ์ œ๋ฅผ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๊ฒŒ์‹œํ•œ ๊ฒƒ์ด ์˜ฌ๋ฐ”๋ฅธ ์„ ํƒ์ด์—ˆ๋‹ค๋Š” ์ ์—๋Š” ์˜์‹ฌ์˜ ์—ฌ์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

Patsisson, VS, VS Code ๋˜๋Š” ๋‹ค๋ฅธ ํŽธ์ง‘๊ธฐ๋ฅผ ์‚ฌ์šฉ ์ค‘์ด์‹ ๊ฐ€์š”?

์ œ ์š”์ ์€ React๊ฐ€ ๊ธฐ๋Šฅ์  ์ ‘๊ทผ ๋ฐฉ์‹์„ ์žฅ๋ คํ•˜๋Š” ๋ฐ˜๋ฉด ๋ช…๋ น์ ์œผ๋กœ(์ƒํƒœ) ์„ธ๊ณ„๋ฅผ ๋ณ€๊ฒฝํ•œ ๋‹ค์Œ ๋ Œ๋”๋ง(forceUpdate)ํ•˜๋Š” ๋น„๋””์˜ค ๊ฒŒ์ž„๊ณผ ๊ฐ™์€ ์›Œํฌํ”Œ๋กœ๋ฅผ ํ—ˆ์šฉํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ์ ‘๊ทผ ๋ฐฉ์‹์€ ์ด์ œ TS์—์„œ ๊ธˆ์ง€๋ฉ๋‹ˆ๋‹ค. ์ผ์ข…์˜ func-damentalism :)

๊ทธ๋Ÿฌ๋ฉด ํ˜„์žฌ ์ƒํƒœ๊ณ„๋ฅผ ์ž‘๋™ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ๋Œ€์•ˆ์„ ์ƒ๊ฐํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ฌธ์ œ 2๋Š” strictNullChecks ์—์„œ๋งŒ ์˜ค๋ฅ˜๋ฅผ ๋˜์ง‘๋‹ˆ๋‹ค.

[TS] Cannot invoke an expression whose type lacks a call signature. Type '((val: any) => void) | undefined' has no compatible call signatures.

+1 strictNullChecks๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

@์—๋ฆฌ์นธ๋”์Šจ ?

์œ„์—์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ์ด๊ฒƒ์€ ํˆด๋ง๊ณผ ๊ด€๋ จ์ด ์žˆ์œผ๋ฉฐ ์ด๋Š” DT์˜ ๋ฒ”์œ„๋ฅผ ๋ถ„๋ช…ํžˆ ๋ฒ—์–ด๋‚ฉ๋‹ˆ๋‹ค. VSCode๋ฅผ ์‚ฌ์šฉ ์ค‘์ด๊ณ  ๊ณง ์ถœ์‹œ๋  TS ํŒŒ์„œ์˜ ๋ฏธ๋ฆฌ ๋ณด๊ธฐ๋ฅผ ์„ค์น˜ํ•˜๋Š” ๊ฒฝ์šฐ ์œ„์˜ ๋‚ด์šฉ์„ ์ž‘์„ฑํ•  ๋•Œ strictNullChecks์—์„œ ์ด ๋ฌธ์ œ๋ฅผ ๋ณด์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ฐฝ๋ฌธ์ด ์—†์œผ๋ฏ€๋กœ VS์™€ ์ ์ ˆํ•˜๊ฒŒ ๋งํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์ด Pick ํŒจ์น˜๋Š” VSCode์—์„œ ์ œ์•ˆ์„ ์ค‘๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค. this.setState({ | }) (Ctrl + Space) ํ•˜๋ฉด State๊ฐ€ ๋ช…ํ™•ํ•˜๊ฒŒ ์ •์˜๋˜์–ด ์žˆ๊ณ  Partial<State> ๋ฅผ ์‚ฌ์šฉํ•ด๋„ ์•„๋ฌด ๊ฒƒ๋„ ํ‘œ์‹œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. setState ๋Š” ๋ฉค๋ฒ„์˜ ์ƒํƒœ๋ฅผ ์„ ํƒ์ ์œผ๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

IMHO ์˜ฌ๋ฐ”๋ฅธ ์ฝ”๋“œ๋Š” setState(state: Partial<S>, callback?: () => any): void; ์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์›๋ž˜ pull request ๋ธŒ๋žœ์น˜์—์„œ ๋…ผ์˜ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ์šฐ๋ฆฌ๋Š” Partial๋กœ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ƒํƒœ ๊ฐ์ฒด๊ฐ€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฝ์šฐ:

์ธํ„ฐํŽ˜์ด์Šค ์ƒํƒœ {
foo: ๋ฌธ์ž์—ด;
}

๊ทธ๋Ÿฐ ๋‹ค์Œ ๋ถ€๋ถ„์ ์œผ๋กœ ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

setState({foo: ์ •์˜๋˜์ง€ ์•Š์Œ});

๋ถ„๋ช…ํžˆ ์ž˜๋ชป๋œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์‹œ ์ฝ๊ธฐ ์ „์šฉ์— ๋Œ€ํ•ด

React๋Š” Redux์™€ setState๋งŒ์ด ์•„๋‹™๋‹ˆ๋‹ค. React๋Š” ๋˜ํ•œ mobx ๋ฐ ๊ธฐํƒ€ ๊ด€์ฐฐ ๊ฐ€๋Šฅํ•œ ํŒจํ„ด์ด๋ฉฐ ์ƒํƒœ ์†์„ฑ ํ• ๋‹น์ด ์ฃผ์š” ๊ธฐ๋Šฅ ์ž…๋‹ˆ๋‹ค. ๋…ผ์˜๋œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์€ typescript๋กœ mobx ์‚ฌ์šฉ์„ ์™„์ „ํžˆ ์ข…๋ฃŒํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด ์›๋ž˜ ๋ฐ˜์‘ ์ฝ”๋“œ์— ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋™์ž‘์„ .d.ts ํŒŒ์ผ์— ์ถ”๊ฐ€ํ•˜๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? .d.ts๋Š” ์›๋ณธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋ฐ˜์˜ํ•˜๋Š” ๊ฒƒ์ด์ง€๋งŒ ์ž‘์„ฑ์ž์˜ ๊ด€์ ์— ๋”ฐ๋ผ ์˜ฌ๋ฐ”๋ฅธ ์ฝ”๋”ฉ ์Šคํƒ€์ผ์„ ๊ฐ€๋ฅด์น˜๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค!

@lezious , ๋‚˜๋Š” ๋‹น์‹ ์˜ ์ž…์žฅ์„ ์ดํ•ดํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ์ฝ”๋“œ ์ƒ˜ํ”Œ์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ๊ทธ๋ฆฌ๊ณ  ์ƒ˜ํ”Œ๊ณผ ๊ด€๋ จํ•˜์—ฌ ํƒ€์ดํ•‘์— ๋Œ€ํ•ด ์ž˜๋ชป๋œ ์ ์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ๊ฐ์‚ฌ ํ•ด์š”!

๊ดœ์ฐฎ์•„์š”:

์ด๊ฒƒ์€ ๋‚ด ์ƒํƒœ ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค

class UserInfoBlockState  
{
    <strong i="7">@observable</strong>                  <- this is mobx way to declare state
    public updating: boolean;
    <strong i="8">@observable</strong> 
    public deleted: boolean;
}

๊ทธ๋ฆฌ๊ณ  ์ด๊ฒƒ์€ ๋‚ด ๊ตฌ์„ฑ ์š”์†Œ์ž…๋‹ˆ๋‹ค

<strong i="12">@observer</strong>       <-- this is mobx way to make component react to state change
export class UserPanel extends React.Component<IUserInfoBlockProps, UserInfoBlockState>
{
   ......
     private updateUser()
    {
        this.state.updating = true;
        UsersAPI.update(this.props.user)
       .then(() =>
            {
                this.state.updating = false;      <--- this is the mobx way to work with the state
            }
        ).catch(() =>
            {
                this.showErrror("Server error");
                this.state.updating = false;
            });
    }
   ....

}

๊ทธ๋ฆฌ๊ณ  ์ด์ œ ์šฐ๋ฆฌ(react+mobx๋กœ ์ž‘์„ฑ๋œ ๊ฑฐ๋Œ€ํ•œ ํ”„๋กœ์ ํŠธ๊ฐ€ ์žˆ๋Š” ์šฐ๋ฆฌ ํšŒ์‚ฌ)๋Š” ์ƒˆ ๋ฆด๋ฆฌ์Šค ์„œํด์ด ์‹œ์ž‘๋  ๋•Œ DT ๋ฐ React๋ฅผ ์—…๋ฐ์ดํŠธํ–ˆ์œผ๋ฉฐ ... 3000๊ฐœ ์ด์ƒ์˜ ์ปดํŒŒ์ผ ์˜ค๋ฅ˜ "์†์„ฑ์ด ์ฝ๊ธฐ ์ „์šฉ์ž…๋‹ˆ๋‹ค". ์™€. ๋‹น์‹ ์ด ๋‚˜์—๊ฒŒ ์ œ์•ˆํ•œ ๊ฒƒ - ์ „์ฒด ํ”„๋กœ์ ํŠธ๋ฅผ redux๋กœ ๋‹ค์‹œ ์ž‘์„ฑํ•˜๊ฑฐ๋‚˜ react.d.ts๋ฅผ ์—…๋ฐ์ดํŠธํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ํ•ญ์ƒ ๋ถ„๊ธฐ๋œ ๋ฒ„์ „์„ ์œ ์ง€ํ•˜๊ณ  ์ง€์›ํ•ฉ๋‹ˆ๊นŒ?

@mweststrate , ์ด๊ฒƒ์„ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค.

@Iezious ๊ท€ํ•˜์˜ ์ž…์žฅ์— ๊ฐ์‚ฌ๋“œ๋ฆฌ๋ฉฐ ์ง„์ •ํ•˜์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‹น์‹ ๊ณผ ํ•จ๊ป˜ ์ผํ•˜๋ ค๊ณ  ํ•ด์š”. ์ด๊ฒƒ์€ Redux์™€ ์•„๋ฌด ๊ด€๋ จ์ด ์—†์ง€๋งŒ ์ˆœ์ˆ˜ํ•œ React์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” DT๊ฐ€ ์ด์ „์— ์ž‘๋™ํ–ˆ๋˜ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ์ฐจ๋‹จํ•˜๋Š” ๊ฒƒ์„ ์›ํ•˜์ง€ ์•Š์ง€๋งŒ, ๋ฐ˜์‘๊ณผ ํ•จ๊ป˜ mobx์˜ ์‚ฌ์šฉ์„ ์„ค๋ช…ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ๋ฐ˜์‘ ๋ฌธ์„œ์™€ ์ผ์น˜ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ).

React๋Š” ๋ฌธ์„œ์—์„œ state๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์‚ฌ์šฉํ•˜๋Š” 3๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค๊ณ  ๋ถ„๋ช…ํžˆ ๋ช…์‹œํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, ์ฒซ ๋ฒˆ์งธ๋Š” "์ƒํƒœ๋ฅผ ์ง์ ‘ ์ˆ˜์ •ํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค"์ž…๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ํ˜„์žฌ ์ฝ”๋“œ ๊ธฐ๋ฐ˜์ด ์ž‘๋™ํ•˜๋Š” ๋ฐฉ์‹์ด ํ–ฅํ›„ ๋ฒ„์ „์˜ react์—์„œ ๊นจ์งˆ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค๊ณ  ๋ฏฟ๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค. https://github.com/mobxjs/mobx-react ๋ฅผ ์‚ดํŽด๋ณด๋ฉด ์ƒํƒœ๋ฅผ ์ด๋Ÿฐ ์‹์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ์ œ์•ˆ์„ ๋ณผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์‚ฌ์‹ค, ๊ทธ๋“ค์€ ๋‹น์‹ ์ด ์†์„ฑ์„ ์‚ฌ์šฉํ•˜๊ธฐ๋ฅผ ์›ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

https://mobx.js.org/getting-started.html ์„ ๊ฒ€ํ† ํ•˜๊ณ  "mobx ๋ฐ˜์‘ ์ƒํƒœ"์— ๋Œ€ํ•ด ์ธํ„ฐ๋„ท ๊ฒ€์ƒ‰์„ ํ•ด๋ณด๋ฉด, mobx๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์„ ์ œ์•ˆํ•˜๋Š” ๋ฌธ์„œ๋ฅผ ์ฐพ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.

DT๋Š” ๊ธฐ๊ปํ•ด์•ผ ๊ธฐ๋ณธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์ •์‹ ์„ ์ „๋‹ฌํ•˜๊ณ  ์ตœ์•…์˜ ๊ฒฝ์šฐ ์‹ค์ œ ๊ตฌํ˜„์„ ์ „๋‹ฌํ•ด์•ผ ํ•˜๋ฉฐ, ๋ฐ˜์‘์„ ๊ตฌ๋งคํ•˜๊ณ  ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ํ™•์žฅํ•˜๋Š” ๊ฒƒ์€ ๋ฌต์‹œ์  โ€‹โ€‹๊ณ„์•ฝ์„ ์กด์ค‘ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค๋Š” ๊ฒƒ์ด ๋ถ„๋ช…ํ•ฉ๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ๋‹น์‹ ์—๊ฒŒ ๋ฌด์—‡์„ ์ œ์•ˆํ•˜๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์ƒ๊ฐํ•  ์ˆ˜์žˆ๋Š” ๋ช‡ ๊ฐ€์ง€ ์˜ต์…˜์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. state ๋ณ€์ˆ˜ ์ธ์ˆ˜๋ฅผ ์ฃผ์žฅํ•˜๋Š” ๊ฒฝ์šฐ "์ €๋ ดํ•œ" ์˜ต์…˜์€ React.Component ๋ฅผ ๊ฒ€์ƒ‰ํ•˜์—ฌ MyComponent ๋กœ ๋ฐ”๊พธ๊ณ  $ MyComponent ๋ฅผ ํ•˜์œ„ ํด๋ž˜์Šค๋กœ ์ •์˜ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฝ๊ธฐ ์ „์šฉ ์ œ์•ฝ ์—†์ด React.Component ์ค‘.
  2. mobx์— ๋Œ€ํ•œ ๋ฌธ์„œ์— ๊ฒŒ์‹œ๋œ ๊ด€์šฉ์  ์˜ˆ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์€ this.state ์‚ฌ์šฉ์„ ์ค‘๋‹จํ•˜๊ณ  ์‹ค์ œ React.Component ์— ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์•ฝ๊ฐ„ ๊ณ ํ†ต์Šค๋Ÿฌ์šธ ์ˆ˜ ์žˆ์ง€๋งŒ ์ ์–ด๋„ ํ”„๋กœ์ ํŠธ์˜ ์ƒˆ๋กœ์šด ์‚ฌ๋žŒ๋“ค์€ ์˜จ๋ผ์ธ์— ์„ค๋ช…๋œ ๋Œ€๋กœ ์ฝ”๋“œ ๊ธฐ๋ฐ˜์˜ ํŒจํ„ด์„ ๋ณผ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  3. ํ˜„์žฌ ํ•˜๊ณ  ์žˆ๋Š” ๋ฐฉ์‹๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ๊ณ„์† ์ˆ˜ํ–‰ํ•˜๋ ค๋ฉด ๊ฐ ๊ตฌ์„ฑ ์š”์†Œ์—์„œ state ๋ฅผ ๋‹ค์‹œ ์„ ์–ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  4. this.state ๋ฅผ ๊ฒ€์ƒ‰ํ•˜์—ฌ this.somethingElse ๋กœ ๋ฐ”๊พธ๊ณ  ์ˆ˜๋™์œผ๋กœ ์„ ์–ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  5. DT์—์„œ ๋ฐ˜์‘ํ•˜๊ธฐ ์œ„ํ•ด ์—…๋ฐ์ดํŠธ๋ฅผ ์ค‘๋‹จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(ํ–ฅํ›„ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์‚ฌ์šฉ ์‚ฌ๋ก€์— ์–ด๋–ค ์˜ํ–ฅ์„ ๋ฏธ์น  ์ˆ˜ ์žˆ๋Š”์ง€์— ๋”ฐ๋ผ ์ผ๋ฐ˜์ ์œผ๋กœ ํ–ฅํ›„ ๋ฐ˜์‘์—์„œ ๊ฐ€๋Šฅ).

๊ทธ๊ฒƒ์ด ๋‚ด ํ”„๋กœ์ ํŠธ๋ผ๋ฉด ์•„๋งˆ๋„ 2๋ฒˆ์„ ํ–ˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋น„๋ก mobx์— ๋Œ€ํ•ด ํ™•์‹คํžˆ ์•Œ์ง€๋Š” ๋ชปํ•˜์ง€๋งŒ์š”.

์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค(๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ๋™์˜ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ด๋ผ๋Š” ์˜๋ฏธ๋Š” ์•„๋‹˜). ๋‚˜๋Š” ๊ทธ ๋ถ€๋ถ„์„ ๋˜๋Œ๋ฆด ์ด์œ ๋ฅผ ์ฐพ์œผ๋ ค๊ณ  ๋…ธ๋ ฅํ–ˆ์ง€๋งŒ ์ง€๊ธˆ์€ ํƒ‘์Šนํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

Mobx ํŒจํ„ด๊ณผ ๋งค์šฐ ์œ ์‚ฌํ•œ React ์ƒํƒœ ๋ณ€๊ฒฝ ๋ฐ ๋ Œ๋”๋ง์„ ๊ตฌ๋™ํ•˜๊ธฐ ์œ„ํ•œ RxJ ๊ด€์ฐฐ ๊ฐ€๋Šฅ ํ•ญ๋ชฉ์˜ ์‚ฌ์šฉ์ž ์ง€์ • ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์ธ ์šฐ๋ฆฌ์˜ ์ „๋žต์„ ๋‹ค์‹œ ์–ธ๊ธ‰ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๋ทฐ(React) ๋ ˆ์ด์–ด์—์„œ ์ž…๋ ฅ์„ ๋ฐ›๊ธฐ ์œ„ํ•ด ์•ก์…˜์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ž‘์—…์€ ์ž…๋ ฅ์„ ์†Œ๋น„ํ•˜๊ณ  ๊ด€์ฐฐ ๊ฐ€๋Šฅ ํ•ญ๋ชฉ์„ ์ƒ์„ฑํ•œ ๋‹ค์Œ ๋‹ค๋ฅธ ์ƒํƒœ ๊ด€์ฐฐ ๊ฐ€๋Šฅ ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€๋กœ ๊ตฌ๋™ํ•˜๋Š” ํ•จ์ˆ˜์™€ ๋™์˜์–ด์ž…๋‹ˆ๋‹ค. ์ด ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ด€์ฐฐ ๊ฐ€๋Šฅํ•œ ๊ฐ’๋งŒ ์ฟผ๋ฆฌํ•˜๊ณ  ์ƒํƒœ ์ž‘์—…์„ ์‹คํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— React ๋ ˆ์ด์–ด ๊ด€์ ์—์„œ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋‚ด๋ถ€ ์ƒํƒœ์—๋Š” ์ฝ๊ธฐ ์ „์šฉ ์ œ์•ฝ ์กฐ๊ฑด์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋‚ด๋ถ€์ ์œผ๋กœ ์ƒํƒœ๋Š” ์ž‘์—…์˜ ๊ฒฐ๊ณผ๋กœ ์ž์ฒด์ ์œผ๋กœ "๋ณ€๊ฒฝ"๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ง„์ •ํ•  ์ˆ˜ ์—†์–ด์š”. ๋‚˜๋Š” ํ”„๋กœ๋•์…˜์— ์žˆ๋Š” ํ”„๋กœ์ ํŠธ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๊ณ  ์—„์ฒญ๋‚œ ์–‘์˜ ํŒ€ ์‹œ๊ฐ„์„ ๋ณด๋‚ด์•ผ ํ•˜๊ณ , ์ด๊ฒƒ์€ ์ด ๋ณ€๊ฒฝ ์ดํ›„์— ๋ˆ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๊ทธ ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ์ด ๋ณ€ํ™”๋Š” ๋ฐ˜์‘์˜ ํ˜„์‹ค์„ ๋ฐ˜์˜ํ•ฉ๋‹ˆ๊นŒ? ์•„๋‹ˆ์š”. ๋ฐ˜์‘์— ์—†๋Š” ์ œํ•œ ์‚ฌํ•ญ๊ณผ ๋™์ž‘์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์˜ณ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์–ด๋–ป๊ฒŒ๋“  ์ถ”๊ฐ€๋˜๋Š” ์ œํ•œ ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค.

DT ํ”„๋กœ์ ํŠธ์˜ ๋ชฉํ‘œ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? JS ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๊ฐ€๋Šฅํ•œ ํ•œ ์ •ํ™•ํ•˜๊ฒŒ ์„ค๋ช…ํ•˜๊ฑฐ๋‚˜ ์ด๋Ÿฌํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์˜ฌ๋ฐ”๋ฅธ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์šฐ๋ฆฌ์˜ ๋น„์ „์„ ์„ค๋ช…ํ•˜๋ ค๋ฉด? "Definitely Typed"๋ผ๋Š” ์ด๋ฆ„์— ๋”ฐ๋ฅด๋ฉด ์ฒซ ๋ฒˆ์งธ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด ์ œํ•œ์ด ์›๋ž˜ JS ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด DT์—๋„ ์กด์žฌํ•ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค(MUST NOT). ์ด๊ฒƒ์ด ์ œ ์š”์ ์ž…๋‹ˆ๋‹ค. ์ด ์‹œ์ ์—์„œ ๋‚ด๊ฐ€ ์ž˜๋ชปํ•œ ๋ถ€๋ถ„์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

๋‚˜๋Š” ๋‹น์‹ ์ด ์ขŒ์ ˆ๊ฐ์„ ๋Š๋‚€๋‹ค๋Š” ๊ฒƒ์„ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์€ ๋ฌธ์„œ๋ฅผ ์ฝ์„ ๋•Œ ๋ฐ˜์‘์ด ์‚ฌ์šฉ๋˜๋„๋ก ์˜๋„๋œ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ๊ท€ํ•˜์˜ ํŒ€์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋‚จ์šฉํ•˜๊ณ  ๋ฌต์‹œ์  ๊ณ„์•ฝ์„ ์œ„๋ฐ˜ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— DT๋ฅผ ๋œ ๊ตฌ์ฒด์ ์œผ๋กœ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์„ ๊ฑฐ์˜ ์•Œ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์ƒํƒœ๊ฐ€ ์ง์ ‘ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•ด์•ผ ํ•จ์„ ์ œ์•ˆํ•˜๋Š” ๋ฐ˜์‘ ํŒ€์ด ๋‚ด๋†“์€ 1์˜จ์Šค์˜ ๋ฌธ์„œ๋ฅผ ๋ณด์—ฌ์ฃผ์‹œ๋ฉด ์ฆ‰์‹œ ์ฝ”๋“œ๋ฅผ ๋‹ค์‹œ ๋ณ€๊ฒฝํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

https://facebook.github.io/react/docs/react-component.html#state

๋‚˜์ค‘์— setState()๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๋ณ€๊ฒฝ์„ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ this.state๋ฅผ ์ง์ ‘ ๋ณ€๊ฒฝํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค. this.state๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

๋ฐ˜์‘์ด this.state ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผํ•˜๋Š” ๊ฒƒ์ด ๋งค์šฐ ๋ถ„๋ช…ํ•ด ๋ณด์ž…๋‹ˆ๋‹ค. React๋Š” this.state ์˜ _properties_๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(์ด๋Š” redux ๊ฐ€์ •). ๋‹ค์Œ ์ž‘์—…์„ ์ž์œ ๋กญ๊ฒŒ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

this.state.user.name = "foo";

๊ด€์šฉ์  ๋ฐ˜์‘์œผ๋กœ.

๋‚ด๊ฐ€ ์„ ํ˜ธํ•˜๋Š” ๊ฒƒ์€ API๋ฅผ ์ •ํ™•ํ•˜๊ฒŒ ์ž…๋ ฅํ•˜๊ณ (์ด ๊ฒฝ์šฐ Readonly ์˜๋ฏธ) ๋ฐ˜์‘ ํŒ€์ด ๋ช…์‹œํ•œ ๋ชจ๋“  ๋ถˆ๋ณ€๋Ÿ‰์„ ํ‘œํ˜„ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@ericanderson ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ์ด์ œ์„œ์•ผ ์•Œ์•„์ฐจ๋ ธ์Šต๋‹ˆ๋‹ค. FWIW ๋‚˜๋Š” ๋ณ€ํ™”๊ฐ€ ํ•ฉ๋ฆฌ์ ์ด๊ณ  ๋„๊ตฌ๊ฐ€ ๋”ฐ๋ผ ์žก์„ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์— ์˜ํ•ด ๊ฐœ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” setState ์˜ค๋ฒ„๋กœ๋“œ๋ฅผ ๋” ์ด์ƒ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ๋“ค์—ˆ์Šต๋‹ˆ๊นŒ? ๋ฏธ๋ž˜๋Š” ๋ชจ๋“  ๊ณ„์ •์˜ setState ์ถ•์†Œ ์Šคํƒ€์ผ์ž…๋‹ˆ๋‹ค.

@amoreland ๋™์˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‹น: https://facebook.github.io/react/docs/state-and-lifecycle.html#do -not-modify-state-directly

์ƒํƒœ๋ฅผ ์ง์ ‘ ์ˆ˜์ •ํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค.

์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ์€ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋‹ค์‹œ ๋ Œ๋”๋งํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

// Wrong
this.state.comment = 'Hello';

๋Œ€์‹  setState()๋ฅผ ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค.

// Correct
this.setState({comment: 'Hello'});

this.state๋ฅผ ํ• ๋‹นํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์ผํ•œ ์žฅ์†Œ๋Š” ์ƒ์„ฑ์ž์ž…๋‹ˆ๋‹ค.

@johnnyreilly ๋‚˜๋Š” ์—†์—ˆ๋‹ค. ๊ทธ ํฅ๋ฏธ ๋กญ๊ตฐ์š”. ์›์ฒœ?

์ตœ๊ทผ์˜ ๋ฆฌ์•กํŠธ ์ปจํผ๋Ÿฐ์Šค์—์„œ ๋…ผ์˜๋œ ๋‚ด์šฉ ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. YouTube์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Lin Clark์˜ ์—ฐ์„ค์ด์—ˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. 1์ผ ์ฐจ์˜ ์ฒซ ๋ฒˆ์งธ ๋Œ€ํ™” ์ค‘ ํ•˜๋‚˜ - v16์— ๋Œ€์‘ํ•  ์˜ˆ์ •๋œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋‹ค๋ฃน๋‹ˆ๋‹ค. ์„ฌ์œ  ๋“ฑ

https://www.reddit.com/r/reactjs/comments/5zqgsb/react_fiber_functional_setstate/ @gaeron์ด ์—ฌ๊ธฐ์—์„œ ์–ธ๊ธ‰

@gaearon ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค.

mobx๊ฐ€ ์ƒํƒœ ๋ณ€๊ฒฝ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์ด์œ ๋Š” ์˜ต์ €๋ฒ„๋ธ”์ด ์ƒํƒœ๋ฅผ ์™„์ „ํžˆ _๊ต์ฒด_ํ•˜๋Š” ๋Œ€์‹  React ์—…๋ฐ์ดํŠธ๋ฅผ ๊ตฌ๋™ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ƒํƒœ๋Š” ๋ Œ๋”๋ง์„ ๊ตฌ๋™ํ•˜๋Š” ์—”์ง„์ด ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ this.state.updating = true; ์™€ ๊ฐ™์€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋ฉด ์‹ค์ œ๋กœ ์ƒํƒœ ๊ต์ฒด์™€ ๋™์ผํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด์ง€๋งŒ ์ƒํƒœ๋Š” ์ด์ „ ์ฝ˜ํ…์ธ ์—์„œ ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ์Œ์„ ๊ตฌ์„ฑ ์š”์†Œ์— ํ†ต์ง€ํ•˜์—ฌ ์ƒˆ ๋ Œ๋”๋ง์„ ํŠธ๋ฆฌ๊ฑฐํ•  ๋งŒํผ ์ถฉ๋ถ„ํžˆ ๋˜‘๋˜‘ํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ด๊ฒƒ์ด _conventional_ React ์‚ฌ์šฉ๋ฒ•์ด ์•„๋‹ˆ๋ผ ํ›จ์”ฌ ๋” ํฌ๊ด„์ ์ด๊ณ  ๋” ๋†’์€ ์ˆ˜์ค€์˜ React ์‚ฌ์šฉ๋ฒ•์ด๋ผ๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ „ํ†ต์ ์ธ React ์‚ฌ์šฉ๋ฒ•์ด ์†Œ์ˆ˜์˜ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์žˆ๋Š” ์†Œ๊ทœ๋ชจ ํ”„๋กœ์ ํŠธ์—๋งŒ ์œ ์šฉํ•˜๋‹ค๊ณ  ์ฃผ์žฅํ•ฉ๋‹ˆ๋‹ค. ๊ฐ๊ฐ ์ˆ˜์‹ญ ๊ฐœ์˜ ๋ฐ˜์‘์„ฑ ๋Œ์—ฐ๋ณ€์ด ๋“œ๋ผ์ด๋ฒ„๊ฐ€ ์žˆ๋Š” 100๊ฐœ์˜ ๊ตฌ์„ฑ ์š”์†Œ๋กœ ๋๋‚˜๋ฉด ๊ธฐ์กด์˜ React ์ƒํƒœ ๋ณ€๊ฒฝ(์ฆ‰, setState)์„ ๋” ์ด์ƒ ์•ˆ์ •์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์œผ๋ฉฐ _smart_ state(mobx๊ฐ€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•˜๋Š” ์ž‘์—…)์™€ ๊ด€๋ จ๋œ ์•„ํ‚คํ…์ฒ˜ ๋ณ€๊ฒฝ์„ ์ˆ˜์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ).

์ฆ‰, ํƒ€์ดํ•‘ ๋ณ€๊ฒฝ์ด React ์‹œ์Šคํ…œ์˜ ๊ณ ๊ธ‰ ์‚ฌ์šฉ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๊ฐ€ ํ™”๋‚œ ์ด์œ ๋ฅผ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค. ๊ด€์ฐฐ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ ํ• ๋‹น์€ ๊ธฐ์ˆ ์ ์œผ๋กœ _mutating_ ์ƒํƒœ๊ฐ€ ์•„๋‹ˆ๋ผ RHS ๊ฐ’์— ๋Œ€ํ•œ ๊ด€์ฐฐ ๊ฐ€๋Šฅํ•œ ์ด๋ฒคํŠธ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. mobx๊ฐ€ ์ด๋Ÿฌํ•œ ๊ด€์ฐฐ ๊ฐ€๋Šฅํ•œ ์ด๋ฒคํŠธ๋ฅผ ๋ฐœํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์„ ํƒํ•œ ๊ตฌ๋ฌธ์ด React ๋ถˆ๋ณ€ ์ƒํƒœ์˜ ๋ช…์‹œ์  ์˜๋„์™€ ์ถฉ๋Œํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

@Iezious ์ด๋Ÿฌํ•œ ์œ ํ˜•์˜ ๋ฌธ์ œ์— ๋Œ€ํ•œ ๋น ๋ฅธ ์ˆ˜์ •์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ React ์œ ํ˜•์„ ๋ณด๊ฐ•ํ•˜๊ณ  React.Component ์œ ํ˜• ์ •์˜์— ๋Œ€ํ•œ ํ™•์žฅ์„ ์‚ฌ์šฉํ•˜๋„๋ก ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋ฆฌํŒฉํ„ฐ๋งํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import * as React from 'react';
declare module 'react' {
  class MutableStateComponent<P, S> extends React.Component<P, S> {
    state: S;
  }
}
(React as any).MutableStateComponent = React.Component;

์ด์ œ state ๋ฉค๋ฒ„๊ฐ€ ๋” ์ด์ƒ readonly ๋กœ ํ‘œ์‹œ๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์„ ์ œ์™ธํ•˜๊ณ  ์ผ๋ฐ˜ ๊ตฌ์„ฑ ์š”์†Œ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

export class MyComponent extends React.MutableStateComponent<MyProps, MyState> {
  // this.state.name is writable
}

@patsissons ๋„ค, ๋ฐ”๋กœ ๊ทธ ์ด์œ ์ž…๋‹ˆ๋‹ค.

์ €๋Š” ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  setState๋ฅผ ํ˜ธ์ถœํ•˜๋Š” mobx ์˜ต์ €๋ฒ„๋ธ”์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ œ ๊ฑฐ๋Œ€ํ•œ ํ”„๋กœ์ ํŠธ ์ฝ”๋“œ๊ฐ€ ํ›จ์”ฌ ๋” ๋ช…ํ™•ํ•˜๊ณ  ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์›Œ ๋ณด์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๋ ‡๊ฒŒ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋‚ด ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ npm ์„œ๋ฒ„์—์„œ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ด ์Šคํฌ๋ฆฝํŠธ๋Š” ํ•ญ์ƒ ์šฐ๋ฆฌ ํšŒ์‚ฌ์— ๋Œ€ํ•ด ์ด ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋˜๋Œ๋ฆด ๊ฒƒ์ž…๋‹ˆ๋‹ค. "this.state.state.updated"์™€ ๊ฐ™์€ ํ•ดํ‚น๊ณผ ๋‹ค๋ฅธ ๋งŽ์€ ํ•ดํ‚น์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ €๋Š” ์ด ๋ณ€๊ฒฝ์ด ์‹ค์ œ๋กœ ๋ฐ˜์‘ ๋ฐฉ์‹์„ ๋”ฐ๋ฅด๋Š” mobx์™€ ๊ฐ™์€ ๊ด€์ฐฐ ๊ฐ€๋Šฅํ•œ ํŒจํ„ด ์‚ฌ์šฉ์— ์˜ํ–ฅ์„ ๋ฏธ์นœ๋‹ค๊ณ  ๋งํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ง€๊ธˆ์€ ์ด ๋ณ€๊ฒฝ์„ ์ปดํŒŒ์ผํ•  ์ˆ˜ ์—†๊ณ  ์ž‘๋™ํ•˜๋ ค๋ฉด ๋ช‡ ๊ฐ€์ง€ ํ•ดํ‚น ๋ฐ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ €๋Š” ์ด ๋ณ€ํ™”๊ฐ€ ์˜ณ์ง€ ์•Š๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์•„๋งˆ๋„ ๋‚ด๊ฐ€ ์ œ์•ˆํ•œ MutableStateComponent ๋Œ€์‹  Observable React ํŒจํ„ด์— ๋” ์ž˜ ๋งž๋Š” ObservableComponent ๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค.

Readonly ๋ฅผ ์‚ญ์ œํ•˜๋ฉด ์ผ๋ฐ˜ ๋ฐ˜์‘(๋ฐ/๋˜๋Š” mobx๋ฅผ ์ œ์™ธํ•œ ๋‹ค๋ฅธ ์ƒํƒœ ๊ด€๋ฆฌ ์‹œ์Šคํ…œ)๊ณผ ํ•จ๊ป˜ ๋ฐ˜์‘ ์œ ํ˜•์„ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์ด ์˜ค๋ฅ˜์— ๋…ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ฑฐ๋Œ€ํ•œ ํ”„๋กœ์ ํŠธ์—์„œ mobx๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉฐ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์˜คํƒ€๋ฅผ ๋งŒ๋“ค๊ณ  ์‹ค์ˆ˜๋กœ this.state.foo = bar ์„ ์‚ฌ์šฉํ•  ๋•Œ ์ปดํŒŒ์ผ๋Ÿฌ ์˜ค๋ฅ˜์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

ํ‘œ์ค€ ๋ฐ˜์‘๊ณผ ๋น„ํ‘œ์ค€ ๋ฐ˜์‘ ์‚ฌ์šฉ ์‚ฌ์ด์— ํ”ผํ•  ์ˆ˜ ์—†๋Š” ์ ˆ์ถฉ์ ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ํ‘œ์ค€ ๋ฐ˜์‘ ์œ ํ˜•์€ ์ „์ž์— ์˜์กดํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ mobx๋ฅผ ๊ด€์šฉ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋ฉด ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

Readonly๋ฅผ ์‚ญ์ œํ•˜๋ฉด ์ผ๋ฐ˜ ๋ฐ˜์‘(๋ฐ/๋˜๋Š” mobx๋ฅผ ์ œ์™ธํ•œ ์—ฌ๋Ÿฌ ์ƒํƒœ ๊ด€๋ฆฌ ์‹œ์Šคํ…œ)๊ณผ ํ•จ๊ป˜ ๋ฐ˜์‘ ์œ ํ˜•์„ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์ด ์˜ค๋ฅ˜์— ๋…ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ฑฐ๋Œ€ํ•œ ํ”„๋กœ์ ํŠธ์—์„œ mobx๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉฐ ๋ˆ„๊ตฐ๊ฐ€ ์˜คํƒ€๋ฅผ ๋งŒ๋“ค๊ณ  ์‹ค์ˆ˜๋กœ this.state.foo = bar๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์ปดํŒŒ์ผ๋Ÿฌ ์˜ค๋ฅ˜์— ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์‹œ ํ•œ ๋ฒˆ - ๋‹น์‹ ์€ ์ฝ”๋“œ ์ž‘์„ฑ์„ ๊ฐ€๋ฅด์น˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค

์ด ํ”„๋กœ์ ํŠธ๋Š” ์ฝ”๋“œ ์ž‘์„ฑ์„ ๊ฐ€๋ฅด์น˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ JS ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๊ธฐ์กด ๊ธฐ๋Šฅ์„ ์„ค๋ช…ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋…ผ์˜๋œ ์ œํ•œ ์‚ฌํ•ญ์€ ์›๋ณธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์—†์œผ๋ฏ€๋กœ ์‚ญ์ œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๊ฒŒ ๋‹ค์•ผ.

@patsissons

์ด๋Ÿฌํ•œ ์œ ํ˜•์˜ ๋ฌธ์ œ์— ๋Œ€ํ•œ ๋น ๋ฅธ ์ˆ˜์ •์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ React ์œ ํ˜•์„ ๋ณด๊ฐ•ํ•˜๊ณ  React.Component ์œ ํ˜• defs์— ๋Œ€ํ•œ ํ™•์žฅ์„ ์‚ฌ์šฉํ•˜๋„๋ก ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋ฆฌํŒฉํ„ฐ๋งํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ณ์ง€ ์•Š๋‹ค. ๋‚ด๊ฐ€ ์žˆ๋Š” ๊ธฐ์—…์˜ ์„ธ๊ณ„์—๋Š” "๋น ๋ฅธ ์ˆ˜์ •"์ด ์—†์Šต๋‹ˆ๋‹ค. SDK์—์„œ ๋ฌด์–ธ๊ฐ€๊ฐ€ ๋ณ€๊ฒฝ๋˜๊ฑฐ๋‚˜ ์ด์ „ ๋ฒ„์ „๊ณผ ํ˜ธํ™˜ ๋˜์–ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ, ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ๋ช‡ ๋…„์ด ๊ฑธ๋ฆฝ๋‹ˆ๋‹ค. 2๋ฐฑ๋งŒ ๋ผ์ธ ์ด์ƒ์˜ ์ฝ”๋“œ ํ”„๋กœ์ ํŠธ์—๋Š” ๋น ๋ฅธ ์ˆ˜์ •์ด ์—†์Šต๋‹ˆ๋‹ค. ๋ช‡ ์ฃผ๊ฐ„์˜ ๋ณ€๊ฒฝ, ํ…Œ์ŠคํŠธ, A/B ์ œํ’ˆ ํ…Œ์ŠคํŠธ, ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์„ ์œ„ํ•œ ๋กค์•„์›ƒ์ž…๋‹ˆ๋‹ค. ์‹ค์ œ ๋ˆ์ด ๋“ญ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์‹ค์ œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์กด์žฌํ•˜์ง€ ์•Š๋Š” ์ด์ „ ๋ฒ„์ „๊ณผ ํ˜ธํ™˜๋˜์ง€ ์•Š๋Š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ถ”๊ฐ€ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด ๋ชจ๋“  ์—„์ฒญ๋‚œ ๋…ธ๋ ฅ์„ ๊ธฐ์šธ์˜€์Šต๋‹ˆ๊นŒ?

์™œ forceUpdate๊ฐ€ ๋ฐ˜์‘์— ์—ฌ์ „ํžˆ ์กด์žฌํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๊นŒ? ๊ทธ๋“ค์€ ์˜ฌ๋ฐ”๋ฅธ ์Šคํƒ€์ผ์— ๋Œ€ํ•ด conf์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๊ณ  ์žˆ์ง€๋งŒ ๋‹ค๋ฅธ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค. ์™œ์š”? ๋Œ€๊ธฐ์—…์ด๊ณ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ด์ „ ๋ฒ„์ „๊ณผ ํ˜ธํ™˜๋˜์–ด์•ผ ํ•จ์„ ์•Œ๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

@ericanderson ์ด ์ผ์Šต๋‹ˆ๋‹ค

this.state.state.value = 1 

๊ทธ์˜ ๊ด€์ ์—์„œ๋„ ์ •๋‹นํ•˜์ง€ ์•Š๋‹ค. ๋‹ค์Œ์— ๊ทธ๋Š” TS์—์„œ ๋„๊ตฌ๋ฅผ ์–ป๊ณ  ์ด ์ฝ”๋“œ๋ฅผ ๋ฐฉ์ง€ํ•˜๋Š” ์ œํ•œ์„ ์ถ”๊ฐ€ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋˜๋Š” ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์ตœ์ข… ํด๋ž˜์Šค๋กœ ๋งŒ๋“ค๊ฑฐ๋‚˜ "์˜ฌ๋ฐ”๋ฅธ ์Šคํƒ€์ผ์ด๊ณ  ์‚ฌ๋žŒ๋“ค์ด ์‹ค์ˆ˜ํ•˜์ง€ ์•Š๋„๋ก"ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค๋ฅธ ๊ฒƒ์œผ๋กœ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

์‚ฌ๋žŒ๋“ค์˜ ์‹ค์ˆ˜ ๋ฐฉ์ง€ - FB์˜ ์ž‘์—…์ž…๋‹ˆ๋‹ค. ์›ํ•˜๋Š” ๊ฒฝ์šฐ ํ”„๋ก์‹œ๋ฅผ ์‰ฝ๊ฒŒ ์ถ”๊ฐ€ํ•˜๊ณ  ์ƒํƒœ ๋Œ์—ฐ๋ณ€์ด๋ฅผ ํ—ˆ์šฉํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. DT์˜ ๋ชฉ์ ์€ ์„ค๋ช…์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ๋ฟ์ž…๋‹ˆ๋‹ค.

@์ด์ง€์–ด์Šค

์š”์ ์€ React ํŒ€์ด JavaScript๋กœ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋„๋ก ๋งŒ๋“ค ์ˆ˜๋Š” ์—†์ง€๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค๋ฉด ๊ทธ๋ ‡๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด์— TypeScript๋Š” ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋„๋ก ๋งŒ๋“ค ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ด๋Ÿฌํ•œ ๋ณ€๊ฒฝ์ด ์œ ํ˜• ์ •์˜์— ์ ์šฉ๋œ ์ด์œ ์ž…๋‹ˆ๋‹ค. ์ƒํƒœ ๊ตฌ์„ฑ์›์— ๋Œ€ํ•œ ์ง์ ‘ ์ˆ˜์ •์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด React ํŒ€์˜ ์ ˆ๋Œ€์ ์ธ ์˜๋„์˜€์ง€๋งŒ( ์ƒํƒœ๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•œ ๊ณต์‹ ๋ฌธ์„œ์—์„œ ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด), ํ•ด๋‹น ์ œ์•ฝ ์กฐ๊ฑด์„ ๋ถ€๊ณผํ•  ์–ธ์–ด ๊ตฌ์„ฑ์ด ์—†์—ˆ์Šต๋‹ˆ๋‹ค. ์ด ์ œ์•ฝ ์กฐ๊ฑด์€ ์•Œ๋ ค์ง€์ง€ ์•Š์•˜์œผ๋ฉฐ ์ฒ˜์Œ๋ถ€ํ„ฐ ์ž˜ ๋ฌธ์„œํ™”๋˜์—ˆ์Šต๋‹ˆ๋‹ค. React์˜ _conventional_ ์‚ฌ์šฉ ๋ฒ”์œ„ ๋ฐ–์—์„œ ์ž‘์—…ํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์˜ ๊ฒฝ์šฐ ์ตœ์†Œํ•œ React ๊ณต์‹ ์‚ฌ์šฉ ๊ถŒ์žฅ ์‚ฌํ•ญ์„ ์ค€์ˆ˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ ํŒ€์—๊ฒŒ ์ด๋Š” ์ƒํƒœ๋ฅผ ์ง์ ‘ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ์ƒํƒœ ๋ณ€๊ฒฝ์„ ์ถ”์ง„ํ•  ์ˆ˜ ์žˆ๋Š” ์†”๋ฃจ์…˜์„ ์„ค๊ณ„ํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ํŠนํžˆ ์ด์™€ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ํ•˜๊ธฐ ์œ„ํ•ด ์ˆ˜ํ–‰๋˜์—ˆ์Šต๋‹ˆ๋‹ค(์ด ๋ณ€๊ฒฝ์ด ์šฐ๋ฆฌ์—๊ฒŒ ์•ฝ๊ฐ„์˜ ์˜ํ–ฅ์„ ์ฃผ๊ธด ํ–ˆ์ง€๋งŒ ๊ธฐ๋ณธ ์„ค๊ณ„๊ฐ€ ์•„๋‹Œ ๊ธฐ๋Šฅ ์„œ๋ช…์„ ํ†ตํ•ด์„œ๋งŒ).

๊ท€ํ•˜์˜ ์ƒํ™ฉ์—์„œ ๋ฆฌํŒฉํ† ๋ง์ด ๋ถˆ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ ๋ณ€๊ฒฝ์ด ์ด๋ฃจ์–ด์ง€๊ธฐ ์ „์— @types/react ๋ฅผ 15.0.1 ์— ๊ณ ์ •ํ•˜๊ฑฐ๋‚˜ @types/react ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ๋Œ€์‹  ์ž์‹ ์˜ ๋ณ€ํ˜•์„ ์œ ์ง€ํ•˜์‹ญ์‹œ์˜ค. defs ๋ฅผ ์ž…๋ ฅํ•˜๊ณ  Component state ํƒ€์ดํ•‘์„ ๋ณ€๊ฒฝํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋˜๋Œ๋ฆฌ๋„๋ก ๋ˆ„๊ตฐ๊ฐ€๋ฅผ ์„ค๋“ํ•˜๋Š” ๋ฐ ์„ฑ๊ณตํ•˜์ง€ ๋ชปํ•  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

forceUpdate ๋Š” ๋‚ด๋ถ€ ๊ตฌ์กฐ์  ์ƒํƒœ๊ฐ€ ์ˆ˜์ •๋  ๋•Œ(๋˜๋Š” render() ๊ฐ€ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ ์™ธ๋ถ€์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ) ๋ Œ๋”๋ง์„ ๊ตฌ๋™ํ•˜๊ธฐ ์œ„ํ•œ ๊ถŒ์žฅ ์ฝ”๋“œ ๊ฒฝ๋กœ๋กœ ๋ฌธ์„œํ™”๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. forceUpdate ์˜ ์‚ฌ์šฉ๋ฒ•์€ ์šฐ๋ฆฌ ํŒ€์ด React์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ์šฉ ํŒจํ„ด๊ณผ ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜๋„๋ก ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

React ํŒ€์€ JS๋กœ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋„๋ก ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‰ฝ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด์ „ ๋ฒ„์ „๊ณผ ํ˜ธํ™˜๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‹ค์‹œ ํ•œ ๋ฒˆ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

this.state.state.value = 1 

ํ•ฉ๋ฒ• ์—ฌ๋ถ€?

๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค๋งŒ ์ œ ์ƒ๊ฐ์€ ์ด๋ฏธ ๋ช…ํ™•ํ•ฉ๋‹ˆ๋‹ค...

๋‚˜๋Š” ๊ฐ€๋ณ€์„ฑ/๋ถˆ๋ณ€์„ฑ์— ๋Œ€ํ•œ ๋Œ€ํ™”๊ฐ€ _์•„์ง_ ๊ด€๋ จ์ด ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ถ„๋ช…ํžˆ ์ด ๋ณ€๊ฒฝ๊ณผ ๊ฒฐํ•ฉ๋œ TS ์ปดํŒŒ์ผ๋Ÿฌ์˜ ๋ฒ„๊ทธ( Readonly ๊ด€๋ จ)๋กœ ์ธํ•ด ์ผ๋ฐ˜ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์™„์ „ํžˆ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ฒŒ ๋˜์–ด ๋งŽ์€ ๊ธฐ์กด ์ฝ”๋“œ๊ฐ€ ์†์ƒ๋ฉ๋‹ˆ๋‹ค. ํ™•์‹คํžˆ ๊ทธ๊ฒƒ์€ ๋ณดํŽธ์ ์œผ๋กœ ํ—ˆ์šฉ๋˜๋Š” ์œ ํšจํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€์ด๋ฉฐ ์ง€๊ธˆ์€ ์ด๊ฒƒ์„ ๋กค๋ฐฑํ•  ์ถฉ๋ถ„ํ•œ ์ด์œ ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค???

interface test1 {
    num: number;
}

function add<T extends test1>(initial: T, add: number) {
    var copy: Readonly<T> = initial;

    //ERROR HERE: [ts] Operator '+' cannot be applied to types 'T["num"]' and 'number'.
    return copy.num + add;
}

์ด์— ๋Œ€ํ•ด Typescript ํŒ€์— ๋ฏธํ•ด๊ฒฐ ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š”์ง€ ์•„๋Š” ์‚ฌ๋žŒ์ด ์žˆ์Šต๋‹ˆ๊นŒ? ํŠธ๋ž˜์ปค์—์„œ ๊ด€๋ จ ๋ฌธ์ œ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

@caesay Microsoft/TypeScript#15501 ์ฐธ์กฐ

์ƒ์„ฑ์ž์—์„œ ์ƒํƒœ๋ฅผ ์ดˆ๊ธฐํ™”ํ•ด์•ผ ํ•˜์ง€๋งŒ tslint๋Š” "์ƒํƒœ๊ฐ€ ์ฝ๊ธฐ ์ „์šฉ์ž…๋‹ˆ๋‹ค"๋ผ๊ณ  ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค....

constructor(props) {
  super(props);
  this.state = {
     value: props.defaultValue,
  };
}

์–ด๋–ป๊ฒŒ ๊ณ ์น  ์ˆ˜ ์žˆ๋‚˜์š”...........

setState ์‚ฌ์šฉ

setState๊ฐ€ ์ƒ์„ฑ์ž์—์„œ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค

๋˜๋Š” componentWillMount w/setState๋ฅผ ๊ณ ๋ คํ•˜์‹ญ์‹œ์˜ค.

๊ฐ์‚ฌ ํ•ด์š”

์•ˆ๋…•ํ•˜์„ธ์š”,

์ „์ฒด ์Šค๋ ˆ๋“œ๋ฅผ ์ฝ์—ˆ์ง€๋งŒ @alanwei0 ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ฒ˜๋ฆฌํ•  ๊ณ„ํš์ด ์žˆ๋Š”์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

state ๋ฅผ ReadOnly ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ํ•ฉ๋ฆฌ์ ์ด๋ผ๋Š” ๋ฐ ์ „์ ์œผ๋กœ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ์ƒ์„ฑ์ž์—์„œ ์ดˆ๊ธฐ ์ƒํƒœ๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์€ componentDidMount render ๊ฐ€ ํ˜ธ์ถœ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ƒ๋‹นํžˆ ๋ณต์žกํ•ฉ๋‹ˆ๋‹ค.

์ƒ์„ฑ์ž์—์„œ this.state = { ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” @pawelpabich ๋Š” ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ƒ์„ฑ์ž์—์„œ readonly ๋ณ€์ˆ˜์— ํ• ๋‹นํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ Readonly<T> ๋Š” ํ• ๋‹น์„ ๋ฐฉ์ง€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(์ ˆ๋Œ€!).

interface TInterface {
    test: string;
}

class TClass {
    readonly blah: Readonly<TInterface>;
    constructor() {
        this.blah = { test: "constructor" };
    }

    fn = () => {
        this.blah = { test: "fn" };
    }
}

์—ฌ๊ธฐ์„œ ์œ ์ผํ•œ ์˜ค๋ฅ˜๋Š” fn ๋‚ด๋ถ€์— ์žˆ์Šต๋‹ˆ๋‹ค. Readonly<T> ๋•Œ๋ฌธ์ด ์•„๋‹ˆ๋ผ readonly ํ‚ค์›Œ๋“œ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์‚ฌ์‹ค, ์ตœ์‹  ๋ฒ„์ „์˜ ํƒ€์ดํ•‘์€ readonly ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์ง€๋„ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ state ๋‚ด๋ถ€์˜ ์†์„ฑ์„ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ์‹ค์ œ๋กœ state๋ฅผ ์•„๋ฌด๋ฐ๋‚˜ ํ• ๋‹นํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ์šฐ๋ฆฌ๊ฐ€ ์ด์•ผ๊ธฐํ•œ ๋ฌธ์ œ๋Š” ์ƒ์†๋œ ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ์ƒํƒœ ์†์„ฑ์˜ ์œ ํ˜•์ด ์†์‹ค๋˜๋Š” ์œ ํ˜• ์Šคํฌ๋ฆฝํŠธ ์ปดํŒŒ์ผ๋Ÿฌ์˜ ๋ฒ„๊ทธ์˜€์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ดํ›„๋กœ ์ˆ˜์ •๋˜์—ˆ์œผ๋ฉฐ, ๊ทธ๋ ‡๋‹ค๋ฉด ์ด ๋ฌธ์ œ๋ฅผ ์ข…๋ฃŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@caesay ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค, ์ €๋Š” ์šฐ๋ฆฌ๊ฐ€ ์—ฌ๊ธฐ์„œ ๋งํ•˜๋Š” ๊ฒฝ์šฐ๋ผ๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚ด ๋ฌธ์ œ๋Š” ๊ธฐ๋ณธ ํด๋ž˜์Šค์—์„œ ์ƒํƒœ๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ €๋Š” TS 2.4.1์„ ์‚ฌ์šฉ ์ค‘์ž…๋‹ˆ๋‹ค. ํ˜น์‹œ id๊ฐ€ ๋ฌธ์ œ์ธ์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ์‹œ๋‚˜์š”?

ํ•ญ์ƒ setState(componentWillMount์—์„œ)๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@pawelpabich ๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ ์ด๊ฒƒ์€ ๋ฌธ์ œ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค :) ์˜๋„์ ์œผ๋กœ ๊ธฐ๋ณธ ํด๋ž˜์Šค์—์„œ ์ƒํƒœ๋ฅผ ํ• ๋‹นํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์–ด๋–ป๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ˆ? ํŒŒ์ƒ ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ์‚ฌ์šฉ ์ค‘์ธ prop ๊ณ„์•ฝ์„ ๋ชจ๋ฆ…๋‹ˆ๋‹ค.

interface BaseCompState {
    baseState1?: string;
}

class BaseComp<TState extends BaseCompState> extends React.Component<any, TState> {
    constructor(props) {
        super(props);
        this.state = {
            baseState1: "fromBase",
        };
    }
}

interface TopCompState extends BaseCompState {
    topState1?: string;
}

class TopComp extends BaseComp<TopCompState> {
    constructor(props) {
        super(props);
        this.state = {
            baseState1: "fromTop",
            topState1: "fromTop",
        };
    }
}

์ด๊ฒƒ์€ ํŒŒ์ƒ ๊ตฌ์„ฑ ์š”์†Œ์˜ ๊ฐ„๋‹จํ•œ ์˜ˆ์ž…๋‹ˆ๋‹ค(props๋Š” ์ƒ๋žต๋˜์—ˆ์ง€๋งŒ ๋™์ผํ•œ ์•„์ด๋””์–ด). ๊ธฐ๋ณธ ํด๋ž˜์Šค์˜ this.state = ๋Š” TState ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ๋ชจ๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ๋ถ„๋ช…ํžˆ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ฒŒ๋‹ค๊ฐ€, ๊ทธ๊ฒƒ์ด _did_ ์ž‘๋™ํ•œ๋‹ค๋ฉด, ๊ทธ๊ฒƒ์€ ๋‹จ์ง€ ๋ถ€๋ชจ๊ฐ€ ์„ค์ •ํ•œ ์ƒํƒœ๋ฅผ ๋ฎ์–ด์“ฐ๊ฒŒ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ตœ์ข… ์ƒํƒœ๋Š” { baseState1: "fronBase" } ์ž…๋‹ˆ๋‹ค. topState ์†์„ฑ์€ ์–ด๋–ป๊ฒŒ ๋˜์—ˆ๋‚˜์š”?

๊ธฐ๋ณธ ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ์ƒํƒœ๋ฅผ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ ˆ๋Œ€์ ์œผ๋กœ ํ™•์‹ ํ•˜๋Š” ๊ฒฝ์šฐ ํŒŒ์ƒ ๊ตฌ์„ฑ ์š”์†Œ์˜ ์ƒํƒœ๋ฅผ ๊ธฐ๋ณธ ๊ตฌ์„ฑ ์š”์†Œ ์ƒ์„ฑ์ž๋กœ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(ํ• ๋‹นํ•  ์ˆ˜ ์žˆ๋„๋ก TState ๋กœ). ๋‹ค์Œ๊ณผ ๊ฐ™์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ:

interface BaseCompState {
    baseState1?: string;
}

class BaseComp<TState extends BaseCompState> extends React.Component<any, TState> {
    constructor(props, state: TState) {
        super(props);
        this.state = Object.assign({
            baseState1: "fromTop",
        }, state);
    }
}

interface TopCompState extends BaseCompState {
    topState1?: string;
}

class TopComp extends BaseComp<TopCompState> {
    constructor(props) {
        super(props, {
            topState1: "fromTop",
        });
    }
}

๋˜๋Š” ๋” ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ธฐ๋ณธ ๊ตฌ์„ฑ ์š”์†Œ ๋‚ด์—์„œ this.setState( ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(์˜ˆ, ์ƒ์„ฑ์ž์—์„œ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!)

์—ฌ๊ธฐ์—๋Š” ๋ฌธ์ œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

@caesay ์ œ์•ฝ ์กฐ๊ฑด์ด ์—†์œผ๋ฉด ํ• ๋‹น์ด ์˜๋ฏธ๊ฐ€ ์—†๋‹ค๋Š” ๋ฐ ์ „์ ์œผ๋กœ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ปดํŒŒ์ผ๋Ÿฌ์— ์ฝ”๋“œ๊ฐ€ ์˜ฌ๋ฐ”๋ฅธ์ง€ ํ™•์ธํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ๋ชจ๋“  ์ •๋ณด๊ฐ€ ์žˆ์ง€๋งŒ ๋‹ค์Œ ์ฝ”๋“œ๋Š” ์—ฌ์ „ํžˆ ์ปดํŒŒ์ผ ์˜ค๋ฅ˜๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

import * as React from "react";

/* tslint:disable:max-classes-per-file*/

interface BaseProps {
    baseProp: string;
}

interface BaseState {
    baseState: string;
}

class Base<TProps extends BaseProps, TState extends BaseState> extends React.Component<TProps, TState> {
    constructor(props) {
        super(props);

        this.state = {
            baseState: props.baseProp
        };
    }

    render() {
        return <div>{this.state.baseState}</div>;
    }
}

interface DerivedProps extends BaseProps {
    derivedProp: string;
}

interface DerivedState extends BaseState {
    derivedState: string;
}

export class Derived extends Base<DerivedProps, DerivedState> {
    constructor(props) {
        super(props);

        this.state = {
            derivedState: props.derivedProp
        };
    }

    render() {
        return <div>{this.state.derivedState}</div>;
    }
}

์˜ค๋ฅ˜

webpack: Compiled successfully.
ERROR at Test.tsx(17,9):
TS2322: Type '{ baseState: any; }' is not assignable to type 'Readonly<TState>'.

ERROR at Test.tsx(39,9):
TS2322: Type '{ derivedState: any; }' is not assignable to type 'Readonly<DerivedState>'.
  Property 'baseState' is missing in type '{ derivedState: any; }'.

Version: typescript 2.4.1

์ฒซ ๋ฒˆ์งธ. ์ƒ์„ฑ์ž์˜ base์— ์žˆ๋Š” ์†Œํ’ˆ์ด ์ž…๋ ฅ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ props.baseProp ๋Š” ํ• ๋‹นํ•  ์ˆ˜ ์—†๋Š” any ์ž…๋‹ˆ๋‹ค!

๋‘˜์งธ, Derived ์˜ ์†Œํ’ˆ์—๋Š” ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ๊ณ  baseState ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋ฌผ๋ก  Readonly์— ๊ด€๊ณ„์—†์ด ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

TProps extends BaseProps ์ฆ‰ TProps ์—๋Š” BaseProps ์™€ ๋™์ผํ•œ ๊ตฌ์„ฑ์›์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ์ •์˜๋˜์ง€ ์•Š์Šต๋‹ˆ๊นŒ? ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๊ทธ๊ฒƒ์„ ์œ ์ถ”ํ•  ์ˆ˜ ์—†์„ ์ˆ˜๋„ ์žˆ์ง€๋งŒ ์ •์˜๋˜์ง€ ์•Š์•˜๋‹ค๊ณ  ๋งํ•˜๋Š” ๊ฒƒ์€ ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™๋‹ค๋Š” ๊ฒƒ์„ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค. Derived ์—๋„ ๊ฐ™์€ ์ƒ๊ฐ์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ƒ์„ฑ์ž์˜ @caesay setState ๋Š” ์ด ๋ฉ”์„œ๋“œ๊ฐ€ ๋น„๋™๊ธฐ์‹์ด๊ณ  ์ดˆ๊ธฐ ์ƒํƒœ ์„ค์ • ์—†์ด render ์— ๋„๋‹ฌํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ์†”๋ฃจ์…˜์ด ์•„๋‹™๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ๋ณผ ์ˆ˜์žˆ๋Š” ์œ ์ผํ•œ ์‹ ๋ขฐํ•  ์ˆ˜์žˆ๋Š” ์†”๋ฃจ์…˜์€ ํŒŒ์ƒ ํด๋ž˜์Šค์—์„œ ์ „์ฒด ์ƒํƒœ๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ช…๋ฐฑํ•œ ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  1. ์ด๊ฒƒ์€ ๋ชจ๋“  ํŒŒ์ƒ ํด๋ž˜์Šค์—์„œ ๋ณต์ œ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  2. ํŒŒ์ƒ ํด๋ž˜์Šค๋Š” ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š๋Š” ์ƒํƒœ์— ๋Œ€ํ•ด ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์œ„์—์„œ ๋ณด์—ฌ๋“œ๋ฆฐ ์˜ˆ์ œ๋Š” C#์—์„œ ์ž‘๋™ํ•˜๋ฏ€๋กœ TypeScript์—์„œ ์ž‘๋™ํ•˜๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

  1. ~setState๋Š” ์ƒ์„ฑ์ž์—์„œ ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค~
  2. ํŒŒ์ƒ ํด๋ž˜์Šค์˜ ๊ฒฝ์šฐ ๋‚ด๊ฐ€ ๋ณผ ์ˆ˜์žˆ๋Š” ๊ฐ€์žฅ ์ข‹์€ ๊ฒฝ์šฐ๋Š” componentWillMount setState ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ท€ํ•˜์˜ ๊ธฐ์ง€๋Š” ํ•ด๋‹น ํ•˜์œ„ ์ƒํƒœ์— ์žˆ์–ด์•ผ ํ•˜๋Š” ํ•ญ๋ชฉ์„ ์•Œ์ง€ ๋ชปํ•˜๋ฏ€๋กœ this.state ๋ฅผ ์•ˆ์ „ํ•œ ๊ตฌ์„ฑ์œผ๋กœ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํ•˜์œ„ ํด๋ž˜์Šค๋Š” ๋ถ€๋ชจ์˜ componentWillMount ๋ฅผ ํ˜ธ์ถœํ•œ ๋‹ค์Œ ํ•„์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ์ƒํƒœ๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  3. ๋งŽ์€ ์–ธ์–ด์—๋Š” typescript์— ์žˆ์œผ๋ฉด ์ข‹์„ ์–ธ์–ด ๊ธฐ๋Šฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ผ๋ถ€๋Š” ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์€ ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์–ด๋Š ์ชฝ์ด๋“  ๊ทธ๊ฒƒ์€ ํฌํ•จ์— ๋Œ€ํ•œ ๋…ผ์Ÿ์ด ์•„๋‹™๋‹ˆ๋‹ค.
  4. ๋ณด๊ณ  ์žˆ๋Š” ์˜ค๋ฅ˜๋Š” ์˜๋ฏธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋“ค์€ ํƒ€์ดํ•‘์ด๋‚˜ ํƒ€์ดํ•‘์—์„œ ๋ฒ„๊ทธ๋ฅผ ์ œ์•ˆํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ฐ๊ฐ์˜ ๊ฒฝ์šฐ์— ๋ง ๊ทธ๋Œ€๋กœ ์˜ˆ์ƒ ์œ ํ˜•๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฐœ์ฒด์— this.state ๋ฅผ ํ• ๋‹นํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

ํŽธ์ง‘๋จ, ์ƒ์„ฑ์ž์˜ setState์— ๋Œ€ํ•ด ์ž˜๋ชป๋˜์—ˆ์Œ์„ ๋ฐ˜์˜ํ•˜๊ณ  ๊ฐ€๋…์„ฑ์„ ์œ„ํ•ด ๋ฐฑํ‹ฑ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

@ericanderson ์ €๋Š” ์šฐ๋ฆฌ๊ฐ€ ์—ฌ๊ธฐ์„œ ์–ด๋–ค ์ง„์ „๋„ ์ด๋ฃจ์ง€ ๋ชปํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ์‹œ๋ฅผ ๋ณด์—ฌ ๋“œ๋ ธ๋Š”๋ฐ ์ง‘์ค‘ํ•ด ์ฃผ์‹œ๋ฉด ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ํ† ๋ก ์ด ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

Re setState ์ƒ์„ฑ์ž์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์•ˆ์ „ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค . ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์ง€๋งŒ ๋ Œ๋”๋ง์ด ๋ฐœ์ƒํ•˜๊ธฐ ์ „์— ์ƒํƒœ๋ฅผ ์„ค์ •ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ ๋•Œ๋ฌธ์— ๊นจ์ง€๋Š” ์ฝ”๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ React ๋ฌธ์„œ๋Š” ๊ฑฐ๊ธฐ์—์„œ ์‚ฌ์šฉ๋˜์–ด์„œ๋Š” ์•ˆ ๋œ๋‹ค๋Š” ๊ฒƒ์ด ๋งค์šฐ ๋ถ„๋ช…ํ•ฉ๋‹ˆ๋‹ค.

@pawelpabich ์•„๋‹ˆ์š”, ์ด๊ฒƒ์€ ์ด ์ฃผ์žฅ์„ ํ•  ๊ณณ์ด ์•„๋‹™๋‹ˆ๋‹ค. ๋‹น์‹ ์€ ์–ธ์–ด์— ๋Œ€ํ•œ ์ดํ•ด๊ฐ€ ๊ทผ๋ณธ์ ์œผ๋กœ ์ž˜๋ชป๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ท€ํ•˜๊ฐ€ ์ œ๊ณตํ•œ ์˜ˆ์—์„œ ๊ท€ํ•˜๋Š” ์ฃผ์— ๋Œ€ํ•œ ๊ท€ํ•˜์˜ ํ• ๋‹น ์ค‘ ์–ด๋Š ์ชฝ์ด๋“  "์ฃผ" ๊ณ„์•ฝ์„ ์ถฉ์กฑํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ํ•  ๋•Œ

this.state = { baseState: props.baseProp };
// now the state is exactly { baseState: props.baseProp }

์ƒํƒœ๋Š” ์ •ํ™•ํžˆ { baseState: props.baseProp } ์ด๊ณ  ์ด๊ฒƒ์€ TProps extends BaseProps ์˜ ์š”๊ตฌ ์‚ฌํ•ญ์„ ์ถฉ์กฑํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(TProps๊ฐ€ ๋ฌด์—‡์ธ์ง€ ๋ชจ๋ฅด๊ธฐ ๋•Œ๋ฌธ์—! ์†์„ฑ์ด ์žˆ์„ ์ˆ˜ ์žˆ์Œ).

๊ทธ ํ›„, ๋‹น์‹ ์€ _ SEPARATE _ ํ• ๋‹น์„ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

this.state = { derivedState: props.derivedProp };
// now the state is exactly {  derivedState: props.derivedProp }

์ƒํƒœ๋Š” ์ด์ œ ์ •ํ™•ํžˆ { derivedState: props.derivedProp } ์ด๊ณ (๊ธฐ๋ณธ ์ƒํƒœ ํ• ๋‹น์„ ๋ฎ์–ด์ผ์Šต๋‹ˆ๋‹ค!!) ์ด๊ฒƒ์€ DerivedState ๋˜๋Š” BaseProps๋ฅผ ์ถฉ์กฑํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ์ž‘๋™ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ๊ฒƒ์€ ์™„์ „ํžˆ ์ž˜๋ชป๋œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ๋ณ€์ˆ˜ ํ• ๋‹น์ด ์ž‘๋™ํ•˜๋Š” ๋ฐฉ์‹์— ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์ƒˆ ๋ฌธ์ œ์—์„œ ์–ธ์–ด ๋””์ž์ด๋„ˆ์™€ ํ•จ๊ป˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ณ  ์—ฌ๊ธฐ์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฏ€๋กœ ์—ฌ๊ธฐ์—์„œ ์•Œ๋ฆผ์„ ๋ฐ›์ง€ ์•Š๋„๋ก ํ•˜์„ธ์š”.

์ฐธ๊ณ ๋กœ ๊ธฐ๋ณธ render() ๋ฉ”์„œ๋“œ๋„ ์žฌ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ๊ธฐ๋ณธ ๊ตฌ์„ฑ ์š”์†Œ๋Š” ์•„๋ฌด ๊ฒƒ๋„ ๋ Œ๋”๋งํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์›ํ•˜๋Š” ๊ฒƒ์ด๋ผ๊ณ  ํ™•์‹ ํ•œ๋‹ค๋ฉด ๋ณดํ˜ธ๋œ ๋ฉค๋ฒ„ getBaseState() ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์ƒํƒœ๋ฅผ ์„ค์ •ํ•  ๋•Œ ํŒŒ์ƒ๋œ ์ƒ์„ฑ์ž์—์„œ ์ด๊ฒƒ์„ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(๋”ฐ๋ผ์„œ ๊ธฐ๋ณธ ์ƒํƒœ ๋…ผ๋ฆฌ๋ฅผ ๋ณต์ œํ•  ํ•„์š”๊ฐ€ ์—†์Œ). ๊ทธ๋Ÿฌ๋‚˜ ๋‹น์‹ ์ด ์ •๋ง๋กœ ์›ํ•˜๋Š” ๊ฒƒ์€ ํŒŒ์ƒ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์ „ํ˜€ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ตฌ์„ฑ์„ ์‚ฌ์šฉํ•˜๋„๋ก ๊ตฌ์กฐ ์กฐ์ •์„ ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค(์—ฌ๋Ÿฌ ํ•˜์œ„ ๊ฐœ์ฒด๋ฅผ ํฌํ•จํ•˜๋Š” ํ•˜๋‚˜์˜ ๊ฐœ์ฒด๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ). ํ›จ์”ฌ ๊น”๋”ํ•ด ์งˆ ๊ฒƒ ๊ฐ™์•„์š”.

๋‚˜๋Š” ๋‹จ์ง€ ๋‹น์‹ ๊ณผ ์ด ๋ฌธ์ œ์— ๋Œ€ํ•ด ํ† ๋ก ํ•˜๊ธฐ ์œ„ํ•ด ์ƒˆ๋กœ์šด ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ๋…์„œ์—์„œ ํ•œ ๋ฐœ์ง ๋ฌผ๋Ÿฌ์„œ๊ณ  ์‹ถ์ง€ ์•Š์ง€๋งŒ, ์•„์•„...

๋‚˜๋Š” ์ƒ์„ฑ์ž์—์„œ setState () ์— ๋Œ€ํ•ด ์ •์ •ํ•  ๊ฒƒ์ด์ง€๋งŒ, componentWillMount ์—์„œ ๊ทธ๊ฒƒ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•œ ๋Š๋‚Œ์€ ๋ณ€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์˜ ์‹ค์ œ ์˜ˆ:
https://github.com/ericanderson/set-state-example

ํŠนํžˆ index.tsx:

import * as React from "react";
import * as ReactDOM from "react-dom";

/* tslint:disable:max-classes-per-file*/

interface BaseProps {
  baseProp: string;
}

interface BaseState {
  baseState: string;
}

class Base<TProps extends BaseProps, TState extends BaseState> extends React.Component<TProps, TState> {
  public componentWillMount() {
    this.setState({
      baseState: this.props.baseProp,
    });
  }

  public render() {
    return (
      <p>
        <code>this.state.baseState: </code>
        {this.state.baseState}
      </p>
    );
  }
}

interface DerivedProps extends BaseProps {
  derivedProp: string;
}

interface DerivedState extends BaseState {
  derivedState: string;
}

export class Derived extends Base<DerivedProps, DerivedState> {
  public componentWillMount() {
    super.componentWillMount();
    this.setState({
      derivedState: this.props.derivedProp,
    });
  }

  public render() {
    return (
      <div>
        <p>
          <code>this.state.derivedState: </code>
          {this.state.derivedState}
        </p>
        {super.render()}
      </div>
    );
  }
}

ReactDOM.render(<Derived derivedProp="its derived" baseProp="its basic" />, document.getElementById("main"));

@pawelpabich ์ดˆ๊ธฐ ์ƒํƒœ๋กœ ๋‹คํ˜•์„ฑ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๊ตฌํ˜„ํ•˜๋ ค๋ฉด ๊ธฐ๋ณธ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์ถ”์ƒํ™”ํ•˜๊ณ  ํŒŒ์ƒ ํด๋ž˜์Šค์—์„œ ๊ตฌํ˜„ํ•  ์ถ”์ƒ getInitialState() (๋˜๋Š” ์œ ์‚ฌํ•œ ํ…Œ๋งˆ) ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. @ericanderson ์ด ๋ณด์—ฌ์ค€ ๊ฒƒ์ฒ˜๋Ÿผ ์ƒ์„ฑ์ž์—์„œ ๋˜๋Š” setState ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒํƒœ๋ฅผ ํ•œ ๋ฒˆ๋งŒ ํ• ๋‹นํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

์•„๋ž˜๋Š” ์ƒํƒœ ๊ตฌ์„ฑ๊ณผ ๊ด€๋ จ๋œ ๋ฌธ์ œ๋ฅผ ์™„์ „ํžˆ ๋ถ„๋ฆฌํ•˜์—ฌ ์™„์ „ํžˆ ๋‹คํ˜•์„ฑ ์†”๋ฃจ์…˜์œผ๋กœ ๋ณ€ํ™˜ํ•œ ์˜ˆ์ž…๋‹ˆ๋‹ค.

interface BaseProps {
  baseProp: string;
}

interface BaseState {
  baseState: string;
}

abstract class Base<TProps extends BaseProps, TState extends BaseState> extends React.Component<TProps, TState> {
  constructor(props: TProps) {
      super(props);

      this.state = this.getInitialState();
  }

  protected abstract getInitialState(): TState;

  protected getBaseState() {
    return this.props.baseProp;
  }

  render() {
      return <div>{this.state.baseState}</div>;
  }
}

interface DerivedProps extends BaseProps {
  derivedProp: string;
}

interface DerivedState extends BaseState {
  derivedState: string;
}

export class Derived extends Base<DerivedProps, DerivedState> {
  getInitialState(): DerivedState {
    return {
      baseState: this.getBaseState(),
      derivedState: this.props.derivedProp,
    };
  }

  render() {
      return <div>{this.state.derivedState}</div>;
  }
}

@patsisson ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

@caesay ๋‚˜๋Š” ๋‚ด๊ฐ€ ํ‹€๋ ธ๋‹ค๋Š” ๊ฒƒ์„ ์ธ์ •ํ•˜๊ณ  ์–ด๋–ค ์ด์œ ๋กœ ํ• ๋‹น์ด ์„œ๋กœ๋ฅผ ๋ฌด์‹œํ•˜๋Š” ๊ฒƒ์„ ๋ณด์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. CAPS์™€ ! ๋ฅผ ์‚ฌ์šฉํ•ด๋„ ๋ฌธ์ œ์—์„œ ๋ฒ—์–ด๋‚  ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.

@patsissons ์™€ @ericanderson ์€ ๋ฌธ์ œ์— ์ง‘์ค‘ํ–ˆ๊ณ  ์ด์ œ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์†”๋ฃจ์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค.

@pawelpabich ๋‚ด ๋งค๋„ˆ๋ฆฌ์ฆ˜์ด ์ „๋ฌธ์ ์ด์ง€ ๋ชปํ•˜๋‹ค๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋‚ด๊ฐ€ ์—ฌ๋Ÿฌ ์„ค๋ช…, ์ƒ˜ํ”Œ ๋“ฑ์„ ์ œ๊ณตํ–ˆ๊ณ  ๋‹น์‹ ์ด ๋‚ด ๋ง์„ ๋“ฃ์ง€ ์•Š๊ธฐ๋กœ ์„ ํƒํ•œ ๊ฒƒ์„ ๊ณ ๋ คํ•˜๋ฉด ์ดํ•ดํ•  ๋งŒํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฉด ๋ถ€๋ชจ๊ฐ€ ์„ค์ •ํ•œ ์ƒํƒœ๋ฅผ ๋ฎ์–ด์“ฐ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

[_ํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ_] ๊ธฐ๋ณธ โ€‹โ€‹๊ตฌ์„ฑ ์š”์†Œ์˜ ์ƒํƒœ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋ ค๋ฉด ํŒŒ์ƒ ๊ตฌ์„ฑ ์š”์†Œ์˜ ์ƒํƒœ๋ฅผ ๊ธฐ๋ณธ ๊ตฌ์„ฑ ์š”์†Œ ์ƒ์„ฑ์ž๋กœ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

[_ํŒŒ์ƒ๋œ ๊ตฌ์„ฑ ์š”์†Œ์˜ ์ƒํƒœ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋ ค๋Š” ๊ฒฝ์šฐ_] ๋ณดํ˜ธ๋œ ๋ฉค๋ฒ„ getBaseState()๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์ƒํƒœ๋ฅผ ์„ค์ •ํ•  ๋•Œ ํŒŒ์ƒ๋œ ์ƒ์„ฑ์ž์—์„œ ์ด๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@patsisson ์ด ํ•œ ์ผ์€ ์—ฌ๊ธฐ์— ์ด๋ฏธ ์–ธ๊ธ‰๋œ ์ฃผ์„์„ ๊ฐ€์ ธ์™€์„œ ์ฝ”๋“œ ์ƒ˜ํ”Œ์„ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ํ•„์š”ํ•˜์ง€ ์•Š์•˜์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ stackoverflow๊ฐ€ ์•„๋‹ˆ๋ฉฐ ์šฐ๋ฆฌ๋Š” ์ข…์ข… ๊ฑฐ๊ธฐ์—์„œ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด์ง„ ์ฝ”๋“œ ์ƒ˜ํ”Œ์„ ์ œ๊ณตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋ฐ˜์‘ ๋ฐ typescript์— ์ต์ˆ™ํ•˜์ง€ ์•Š์œผ๋ฉฐ ์•„๋งˆ๋„ sth๋ฅผ ๋ชจ๋ฅด์ง€๋งŒ ์•ฑ์ด ์˜ค๋ฅ˜, ๊ฒฝ๊ณ  ๋ฐ ํžŒํŠธ ์—†์ด ์ปดํŒŒ์ผ๋˜์ง€๋งŒ ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜๋Š” ์˜ˆ์‹œ ์ปดํฌ๋„ŒํŠธ์ž…๋‹ˆ๋‹ค. Readonly ์ƒํƒœ์— ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. Readonly ๋ณ€๊ฒฝ ์ „์— ์•ฑ์ด ์ž‘๋™ํ–ˆ๋‹ค๋ฉด ์ด ๋ณ€๊ฒฝ ํ›„์—๋Š” ์ž‘๋™์ด ์ค‘์ง€๋˜๊ณ  ์ปดํŒŒ์ผ ์‹œ๊ฐ„ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

import * as React from 'react';

export default class HomePage extends React.Component<any, Map<string, string>> {

  public componentWillMount() {
    const map = new Map<string, string>();
    map.set('aKey', 'aValue');
    this.setState(map);
  }

  public render() {

      return (
        <div className="home">
          <div className="greeting">
            Home page: {this.state.get('aKey')} // <-- I get an error here
          </div>
        </div>
      );
  }
}

์˜ค๋ฅ˜:

homePage.tsx:12 Uncaught TypeError: this.state.get is not a function
    at HomePage.render (homePage.tsx:12)
    at eval (ReactCompositeComponent.js:793)
    at measureLifeCyclePerf (ReactCompositeComponent.js:73)
    at ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (

์ƒํƒœ๋Š” ํ•ญ์ƒ ์ผ๋ฐ˜ ํ‚ค ๊ฐ์ฒด์—ฌ์•ผ ํ•˜๋ฏ€๋กœ ๋Œ€์‹  ์ƒํƒœ๋ฅผ ์ •์˜ํ•˜์‹ญ์‹œ์˜ค.
{ values: Map <string, string> } ์™€ ๊ฐ™์ด ์ฝ๊ณ 
this.state.values.get('aKey')

Op vr 29 9์›” 29์ผ 2017 om 09:01 schreef Janusz Biaล‚obrzewski <
์•Œ๋ฆผ@github.com>:

๋‚˜๋Š” ๋ฐ˜์‘ํ•˜๊ณ  ํƒ€์ดํ•‘ํ•˜๋Š” ๊ฒƒ์ด ์ฒ˜์Œ์ด๊ณ  ์•„๋งˆ๋„ sth๋ฅผ ๋ชจ๋ฅด์ง€๋งŒ ์‹ฌ์ง€์–ด
์•ฑ์ด ์˜ค๋ฅ˜, ๊ฒฝ๊ณ  ๋ฐ ํžŒํŠธ ์—†์ด ์ปดํŒŒ์ผ๋˜์ง€๋งŒ ๋Ÿฐํƒ€์ž„์ด ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.
์˜ค๋ฅ˜. ์•„๋ž˜๋Š” ์˜ˆ์‹œ ์ปดํฌ๋„ŒํŠธ์ž…๋‹ˆ๋‹ค. ๋‚˜๋Š” ์˜ค๋ฅ˜๋ฅผ ์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ๋Œ๋ฆฝ๋‹ˆ๋‹ค.
์ƒํƒœ. ์•ฑ์ด ์ฝ๊ธฐ ์ „์šฉ ๋ณ€๊ฒฝ ์ด์ „์— ์ž‘๋™ํ–ˆ๋‹ค๋ฉด ์ด ํ›„์—
๋ณ€๊ฒฝํ•˜๋ฉด ์ž‘๋™์ด ์ค‘์ง€๋˜๊ณ  ์ปดํŒŒ์ผ ์‹œ๊ฐ„ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

* 'react'์—์„œ React๋กœ ๊ฐ€์ ธ์˜ค๊ธฐ;
๋‚ด๋ณด๋‚ด๊ธฐ ๊ธฐ๋ณธ ํด๋ž˜์Šค HomePage๋Š” React.Component๋ฅผ ํ™•์žฅํ•ฉ๋‹ˆ๋‹ค.> {

๊ณต๊ฐœ componentWillMount() {
const ๋งต = ์ƒˆ ๋งต();
map.set('aKey', 'aValue');
this.setState(์ง€๋„);
}

๊ณต๊ฐœ ๋ Œ๋”() {

  return (
    <div className="home">
      <div className="greeting">
        Home page: {this.state.get('aKey')} // <-- I get an error here
      </div>
    </div>
  );

}
}

์˜ค๋ฅ˜:

ํ™ˆํŽ˜์ด์ง€. tsx:12 ์žกํžˆ์ง€ ์•Š์€ TypeError: this.state.get์€ ํ•จ์ˆ˜๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.
HomePage.render์—์„œ(homePage.tsx:12)
ํ‰๊ฐ€ ์‹œ(ReactCompositeComponent.js:793)
measureLifeCyclePerf์—์„œ (ReactCompositeComponent.js:73)
ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext์—์„œ (

โ€”
๋‹น์‹ ์ด ์–ธ๊ธ‰๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์„ ๋ฐ›๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์ด ์ด๋ฉ”์ผ์— ์ง์ ‘ ๋‹ต์žฅํ•˜๊ณ  GitHub์—์„œ ํ™•์ธํ•˜์„ธ์š”.
https://github.com/DefinitelyTyped/DefinitelyTyped/issues/14250#issuecomment-333047367 ,
๋˜๋Š” ์Šค๋ ˆ๋“œ ์Œ์†Œ๊ฑฐ
https://github.com/notifications/unsubscribe-auth/ABvGhM5hDyRNyUeZuIiGeTZk1N-rfuA4ks5snJW5gaJpZM4LuDWV
.

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ state๋ฅผ Readonly<S> ๋กœ ์„ ์–ธํ•˜๋Š” ๊ฒƒ์€ ์˜๋ฏธ๊ฐ€ ์—†๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ค‘์ฒฉ๋œ ๋ฉค๋ฒ„๋Š” Readonly์˜ ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์–ธ์  ๊ฐ€๋Š” Readonly ๊ฐ€ ์žฌ๊ท€์ ์œผ๋กœ ์ ์šฉ๋  ์ˆ˜ ์žˆ์ง€๋งŒ ์ง€๊ธˆ์€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ–ˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์€ ์‚ฌ์šฉ์ž์˜ ๋ชซ์ž…๋‹ˆ๋‹ค. ๊ท€ํ•˜์˜ ๊ฒฝ์šฐ ์‹ค์ œ๋กœ ReadonlyMap ๋˜๋Š”

interface State {
    readonly [key: string]: string;
}

๋˜๋Š” ์ค‘์ฒฉ:

interface State {
    map: { readonly [key: string]: string };
}

๊นŠ์€ ์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

export type DeepReadonly<T> =
  T extends Array<any> ?
  ReadonlyArray<T[0]> :
  T extends Date ?
  T :
  T extends Function ?
  T :
  T extends object ?
  { readonly [P in keyof T]: DeepReadonly<T[P]> } :
  T;

export type Writable<T> =
  T extends ReadonlyArray<any> ?
  Array<WritableObject<T[0]>> :
  T extends Array<any> ?
  Array<WritableObject<T[0]>> :
  WritableObject<T>;

type WritableObject<T> =
  T extends Date ?
  T :
  T extends Function ?
  T :
  T extends object ?
  { -readonly [P in keyof T]: Writable<T[P]> } :
  T;
์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰