비트 컴퓨터 [React] - ⑩

145471 단어 React교육React

1. 실습 ①

참조



Todo



import { observer } from "mobx-react-lite";

const { makeObservable, observable, computed, action, autorun } = require("mobx");

class ObservableTodoStore {
  todos = [];
  pendingRequests = 0;

  constructor() {
    makeObservable(this, {
      todos: observable,
      pendingRequests: observable,
      completedTodosCount: computed,
      report: computed,
      addTodo: action,
    });
    autorun(() => console.log(this.report));
  }

  get completedTodosCount() {
    return this.todos.filter(
      todo => todo.completed === true
    ).length;
  }

  get report() {
    if (this.todos.length === 0)
      return "<none>";
    const nextTodo = this.todos.find(todo => todo.completed === false);
    return `Next todo: "${nextTodo ? nextTodo.task : "<none>"}". ` +
      `Progress: ${this.completedTodosCount}/${this.todos.length}`;
  }

  addTodo(task) {
    this.todos.push({
      task: task,
      completed: false,
      assignee: null
    });
  }
}

const observableTodoStore = new ObservableTodoStore();

observableTodoStore.addTodo("read MobX tutorial");
observableTodoStore.addTodo("try MobX");
observableTodoStore.todos[0].completed = true;
observableTodoStore.todos[1].task = "try MobX in own project";
observableTodoStore.todos[0].task = "grok MobX tutorial";

const TodoList = observer(({store}) => {
  const onNewTodo = () => {
    store.addTodo(prompt('Enter a new todo:','coffee plz'));
  }

  return (
    <div>
      { store.report }
      <ul>
        { store.todos.map(
          (todo, idx) => <TodoView todo={ todo } key={ idx } />
        ) }
      </ul>
      { store.pendingRequests > 0 ? <marquee>Loading...</marquee> : null }
      <button onClick={ onNewTodo }>New Todo</button>
      <small> (double-click a todo to edit)</small>

    </div>
  );
})

const TodoView = observer(({todo}) => {
  const onToggleCompleted = () => {
    todo.completed = !todo.completed;
  }

  const onRename = () => {
    todo.task = prompt('Task name', todo.task) || todo.task;
  }

  return (
    <li onDoubleClick={ onRename }>
      <input
        type='checkbox'
        checked={ todo.completed }
        onChange={ onToggleCompleted }
      />
      { todo.task }
      { todo.assignee
        ? <small>{ todo.assignee.name }</small>
        : null
      }

    </li>
  );
})

function App() {
  return (
    <div>
      <TodoList store={observableTodoStore}></TodoList>
    </div>
  );
}


export default App;



수정





import './App.css';

import { observer } from "mobx-react-lite";

const { makeObservable, observable, computed, action, autorun } = require("mobx");

class ObservableTodoStore {
  todos = [];
  pendingRequests = 0;

  constructor() {
    makeObservable(this, {
      todos: observable,
      pendingRequests: observable,
      completedTodosCount: computed,
      report: computed,
      addTodo: action,
    });
    autorun(() => console.log(this.report));
  }

  get completedTodosCount() {
    return this.todos.filter(
      todo => todo.completed === true
    ).length;
  }

  get report() {
    if (this.todos.length === 0)
      return "<none>";
    const nextTodo = this.todos.find(todo => todo.completed === false);
    return <h2><span>다음 할 일: </span>{nextTodo ? nextTodo.task : `수고했어!\n`} <br/>
              <span>진행 상황: </span>{this.completedTodosCount} / {this.todos.length}</h2>
  }

  addTodo(task) {
    this.todos.push({
      task: task,
      completed: false,
      assignee: null
    });
  }
}

const observableTodoStore = new ObservableTodoStore();

observableTodoStore.addTodo("read MobX tutorial");
observableTodoStore.addTodo("try MobX");
observableTodoStore.todos[0].completed = true;
observableTodoStore.todos[0].task = "커피 사기";
observableTodoStore.todos[1].task = "뚜비 놀아주기";

const TodoList = observer(({store}) => {
  const onNewTodo = () => {
    store.addTodo(prompt('Enter a new todo:','coffee plzzz....☕'));
  }

  return (
    <div>
      { store.report }
      <ul>
        { store.todos.map(
          (todo, idx) => <TodoView todo={ todo } key={ idx } />
        ) }
      </ul>
      { store.pendingRequests > 0 ? <marquee>Loading...</marquee> : null }
      <button onClick={ onNewTodo }>New Todo</button>
      <bold> (double-click a todo to edit)</bold>

    </div>
  );
})

const TodoView = observer(({todo}) => {
  const onToggleCompleted = () => {
    todo.completed = !todo.completed;
  }

  const onRename = () => {
    todo.task = prompt('Task name', todo.task) || todo.task;
  }

  return (
    <li onDoubleClick={ onRename }>
      <input
        type='checkbox'
        checked={ todo.completed }
        onChange={ onToggleCompleted }
      />
      { todo.task }
      { todo.assignee
        ? <small>{ todo.assignee.name }</small>
        : null
      }

    </li>
  );
})

function App() {
  return (
    <div>
      <TodoList store={observableTodoStore}></TodoList>
    </div>
  );
}


export default App;



  • App.css

@font-face {
  font-family: 'KOHIBaeumOTF';
  src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/[email protected]/KOHIBaeumOTF.woff') format('woff');
  font-weight: normal;
  font-style: normal;
}


@font-face {
  font-family: 'GmarketSansMedium';
  src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/[email protected]/GmarketSansMedium.woff') format('woff');
  font-weight: normal;
  font-style: normal;
}


*{
  list-style:none;
  font-family: 'GmarketSansMedium';
  /* font-family: 'Yeongdo-Rg'; */
 
}

html{
  background-color: #EFFFFD;
}




h2{
  font-size: 1rem;
  border-radius: 25px;
  color: white;
  background-color: #85F4FF;
  padding: 10px;
}

h2 span{
  color: #0043b0;
  
}

div{
  border-radius: 25px;
  background-color: #B8FFF9;
  color: rgb(255,255,255);
  padding: 40px;
  text-align: center;
}
  
/* 
h1{
  font-family: 'KOHIBaeumOTF';
  border-radius: 30px;
  color: #064420;
  background-color: #E4EFE7;
  padding: 10px;
  text-align: center;
} */


button {
  background: none;
  border: 3px solid #fff;
  border-radius: 5px;
  color: #fff;
  display: block;
  font-size: 1.6em;
  font-weight: bold;
  margin: 1em auto;
  padding: 1em 2em;
  position: relative;
  text-transform: uppercase;
}

button::before,
button::after {
  background: #fff;
  content: '';
  position: absolute;
  z-index: -1;
}

button:hover {
  color: #0043b0;
}





실행 흐름




2. 실습 ②

참조



ex1)




//1.
class Animal {

  energyLevel;

  constructor(name) {
      this.energyLevel = 100;
      makeAutoObservable(this);
  }

  reduceEnergy() {
      this.energyLevel -= 10;
  }

  get isHungry() {
      return this.energyLevel < 50;
  }
}

const giraffe = new Animal();

autorun(() => {
  console.log("Energy level:", giraffe.energyLevel)
})

autorun(() => {
  if (giraffe.isHungry) {
      console.log("Now I'm hungry!");
  } else {
      console.log("I'm not hungry!");
  }
})

console.log("Now let's change state!");
for (let i = 0; i < 10; i++) {
  giraffe.reduceEnergy();
}


function App() {
  return (
    <div className="App">
      
    </div>
  );
}

export default App;



ex2)



//2.
class Animal {

  energyLevel;

  constructor() {
      this.energyLevel = 100;
      // makeAutoObservable(this);
      makeObservable(
        this, 
        {
          energyLevel:observable,
          isHungry:computed,
          reduceEnergy: action,
        }
      );
  }

  reduceEnergy() {
      this.energyLevel -= 10;
  }

  get isHungry() {
      return this.energyLevel < 50;
  }
}

const giraffe = new Animal();

autorun(() => {
  console.log("Energy level:", giraffe.energyLevel)
})

autorun(() => {
  if (giraffe.isHungry) {
      console.log("Now I'm hungry!");
  } else {
      console.log("I'm not hungry!");
  }
})

console.log("Now let's change state!");
for (let i = 0; i < 10; i++) {
  giraffe.reduceEnergy();
}


function App() {
  return (
    <div className="App">
      
    </div>
  );
}

export default App;



ex3)





//3.
class Animal {

  energyLevel;

  constructor() {
      this.energyLevel = 100;
      // makeAutoObservable(this);
      makeObservable(
        this, 
        {
          energyLevel:observable,
          isHungry:computed,
          reduceEnergy: action,
        }
      );

      autorun(() => {
        console.log("Energy level:", this.energyLevel)
      })

      autorun(() => {
        if (this.isHungry) {
            console.log("Now I'm hungry!");
        } else {
            console.log("I'm not hungry!");
        }
      })
  }

  reduceEnergy() {
      this.energyLevel -= 10;
  }

  get isHungry() {
      return this.energyLevel < 50;
  }
}

const giraffe = new Animal();


console.log("Now let's change state!");
for (let i = 0; i < 10; i++) {
  giraffe.reduceEnergy();
}


function App() {
  return (
    <div className="App">
      
    </div>
  );
}

export default App;



ex4)


  • autorun은 객체가 생성될 때 자동으로 실행된다.
  1. observer 변수가 값이 갱신이 일어나면 autorun이 호출된다.

  2. observer 변수를 사용하는 autorun이 호출된다.

  3. 함수가 observer 변수를 사용하고 있고, observer 변수를 갱신이 일어나면 자동 호출된다.

  1. 옵저버 변수 갱신시에 옵저버 변수를 사용하는 autorun이나, compute자동 호출
  2. compute 변수 갱신 시에 compute변수를 사용하는 autorun 호출

[참고] get, set

class Person{
    constructor(firstName, lastName){
        this.firstName = firstName;
        this.lastName = lastName;
    }
    //getter
    get fullName(){
        console.log('---getter 호출---');
        return `${this.firstName} ${this.lastName}`;
    }
    //setter
    set fullName(name){
        console.log('***setter 호출***');
        [this.firstName, this.lastName] = 
            name.split(' ') //공백으로 분리 시키기
    }
}


import { action, autorun, computed, makeAutoObservable, makeObservable, observable } from 'mobx';
import './App.css';


//4.
class Animal {

  energyLevel;

  constructor() {
      this.energyLevel = 100;
      // makeAutoObservable(this);
      makeObservable(
        this, 
        {
          //mobx가 energyLevel를 항상 주시하세요
          energyLevel:observable,
          //computed가 함수이냐, 변수이냐 -> 변수이다!
          //boolean 타입의 변수로 사용되고 있다.
          isHungry:computed,
          //energyLevel의 값의 변화를 주는 함수
          reduceEnergy: action,
        }
      );


      //energyLevel의 상태가 변화하면 호출된다.
      autorun(() => {
        console.log("Energy level1:", this.energyLevel)
      })


      autorun(() => {
        console.log("Energy level2:", this.energyLevel)
      })
      

      //isHungry에 변화가 감지되면 호출된다.
      //false -> true / true -> false
      autorun(() => {
        console.log(this.isHungry ? "배고파" : "배고프지 않아");
        /*
        if (this.isHungry) {
            console.log("배고파!");
        } else {
            console.log("배고프지 않아!");
        }*/
      })
  }

  //옵저버 변수가 값이 갱신이 일어나면  autorun이 호출된다.
  // 옵저버 변수를 사용하는 autorun이 호출된다.
  reduceEnergy() {
      console.log('에너지 줄임');
      this.energyLevel -= 10;
  }

  //isHungry => 리턴 결과
  //이 함수가 옵저버 변수를 사용하고 있고,
  // 옵저버 변수가 갱신이 일어나면 자동 호출된다.
  get isHungry() {
      console.log('isHungry');
      return this.energyLevel < 95;
      // return 100; //옵저버 함수를 사용하지 않는 경우 
  }
}

const giraffe = new Animal();


console.log("-----change state!-----");
for (let i = 0; i < 2; i++) {
  giraffe.reduceEnergy();
}


function App() {
  return (
    <div className="App">
      
    </div>
  );
}

export default App;






✅ computed


  • computed 함수는 연산된 값을 사용해야 할 때 사용됩니다.

  • 이 값을 조회할 때 마다 특정 작업을 처리하는것이 아니라, 이 값에서 의존하는 값이 바뀔 때 미리 값을 계산해놓고 조회 할 때는 캐싱된 데이터를 사용한다

  • computed가 observe 하던 값의 변화에 따라 결과를 저장해 cache에 저장 reaction의 parameter로 전달된 함수 실행


import { observable, reaction, computed, autorun } from 'mobx';

// Observable State 만들기
const calculator = observable({
  a: 1,
  b: 2
});

// **** 특정 값이 바뀔 때 특정 작업 하기!
reaction(
  () => calculator.a,
  (value, reaction) => {
    console.log(`a 값이 ${value} 로 바뀌었네요!`);
  }
);

reaction(
  () => calculator.b,
  value => {
    console.log(`b 값이 ${value} 로 바뀌었네요!`);
  }
);

// **** computed 로 특정 값 캐싱
const sum = computed(() => {
  console.log('계산중이예요!');
  return calculator.a + calculator.b;
});

sum.observe(() => calculator.a); // a 값을 주시
sum.observe(() => calculator.b); // b 값을 주시

calculator.a = 10;
calculator.b = 20;

//**** 여러번 조회해도 computed 안의 함수를 다시 호출하지 않지만..
console.log(sum.value);
console.log(sum.value);


// 내부의 값이 바뀌면 다시 호출 함
calculator.a = 20;
console.log(sum.value);

계산중이예요! 
a 값이 10 로 바뀌었네요! 
계산중이예요! 
b 값이 20 로 바뀌었네요! 
계산중이예요! 
30
30
a 값이 20 로 바뀌었네요! 
계산중이예요! 
40



makeObservable


  • MobX 6버전 (2020년 9월 업데이트) 에서 부터 데코레이터 사용하지 않고, makeObservable을 사용하는것으로 권장하는것으로 바뀌었다.

  • 예전 버전의 mobx에서는 decorate 사용, 최신버전에서 makeObservable 사용


import { action, makeObservable, observable } from 'mobx'

class Count {
  number: number = 0

  constructor() {
    makeObservable(this, {
      number: observable,
      increase: action,
      decrease: action,
    })
  }

  increase = () => {
    this.number++
  }
  decrease = () => {
    this.number--
  }
}

const countStore = new Count()
export default countStore




import React, { Component } from "react";
import { makeObservable, observable, action } from "mobx";
import { observer } from "mobx-react";

class Counter extends Component {
  number = 0;

  constructor() {
    super();
    makeObservable(this, {  // 예전 버전의 mobx에서는 decorate 사용,  최신버전에서 makeObservable사용
      number: observable,  // observable이니 내가 관찰할 상태 
      increase: action,    // action 이니 상태의 변화를 일으킬 친구
      decrease: action,    // action 이니 상태의 변화를 일으킬 친구
    });
  }

  increase = () => {
    this.number++;
  };

  decrease = () => {
    this.number--;
  };

  render() {
    return (
      <div>
        <h1>{this.number}</h1>
        <button onClick={this.increase}>+1</button>
        <button onClick={this.decrease}>-1</button>
      </div>
    );
  }
}

export default observer(Counter);  
// observer로 감싸줌으로써 이 Counter 클래스는 mobx가 @observable로 지정된 state를 적절히 rerendering 시켜주는 역할을 하게된다.

마지막의 export default observer(Counter) 를 통해서
observable값이 변할때 forceUpdate를 호출함으로서 자동으로 변화를 감지해 화면에 반영되는 것입니다.

  • setState이런거 안해줘도 됩니다



makeAutoObservable


  • super나 subclassed에서는 사용이 불가하기 때문에 makeAutoObservable 방식도 알아두어야 한다.

import { makeAutoObservable } from 'mobx'

class Count {
  number: number = 0

  constructor() {
    makeAutoObservable(this)
  }

  increase = () => {
    this.number++
  }
  decrease = () => {
    this.number--
  }
}

const countStore = new Count()
export default countStore



✅ observable

참조



import { observable, reaction, computed, autorun } from 'mobx';

// **** Observable State 만들기
const calculator = observable({
  a: 1,
  b: 2
});

  • 이렇게 Observable State 를 만들고나면 MobX 가 이 객체를 "관찰 할 수" 있어서 변화가 일어나면 바로 탐지해낼수있습니다.



  • object로 만들면 코드가 더 줄어든다. observable로 감싸주기만 하면 된다.
import { observable } from 'mobx'

const countObject = observable({
  // 헷갈릴 수 있으니 num으로 작명
  num: 0,
  increase() {
    this.num++
  },
  decrease() {
    this.num--
  },
})

export default countObject



observe


  • observe함수는 관찰 가능 항목의 변화를 감시하는 데 사용됩니다.

  • 형식

observe(target, propertyName?, listener, invokeImmediately?)

  • propertyName관찰 할 속성을 지정하는 선택적 매개 변수입니다.

    • observe(user.name, listener)과 다릅니다 observe(user, "name", listener)

      • 첫 번째는 전류 valueuser.name관찰하고 후자 name은 사용자의 속성을 관찰합니다 .
  • listenerObservable이 변경 될 때마다 호출되는 콜백입니다.

    • newValueoldValue매개 변수를 사용하여 리스너를 호출하는 boxed Observable을 제외하고 변형을 설명하는 단일 변경 객체를 수신합니다 .



import { observable, observe } from "mobx";
const person = observable({
  firstName: "John",
  lastName: "Smith"
});
const disposer = observe(person, change => {
  console.log(
    `${change.type} ${change.name} from ${change.oldValue} to ${
      change.object[change.name]
    }`
  );
});
person.firstName = "Jane";



observer


  • 상단에 MobX 관련 기능을 선언한 후, 코드 하단 쪽에 decorate함수를 호출한 부분이 있다.

    • 해당 decorate가 Counter 컴포넌트에게 상태변환을 할 수 있도록 도와주는 함수이다.

    • 마치 리덕스에서 Connect함수의 인자로 mapStateToProps, mapDispatchToProps를 넣는 것과 유사한 형태이다.

  • 마지막 줄의 observer는 observable로 선언한 상태 값(위 코드에서는 number 값)이 변할 때, 컴포넌트 API인 forceUpdate()를 자동 호출하여 변경된 값이 화면에 반영된다.



import React, { Component} from 'react';
import { decorate, observable, action } from 'mobx';
import { observer } from 'mobx-react';

class Counter extends Component {
  number = 0;
  
  increase = () => {
    this.number++;
  }
  
  decrease = () => {
    this.number--;
  }
  
  render() {
    return (
      <div>
        <h1>{this.number}</h1>
        <button onClick={this.increase}>+1</button>
        <button onClick={this.decrease}>-1</button>
      </div>
    )
  }
}

// 데코레이터 설정 부분
decorate(Counter ,{
  number: 'observable',
  increase: 'action',
  decrease: 'action'
});

export default observer(Counter);




import React from 'react'
import { observer } from 'mobx-react'
import store from './store'

// 컴포넌트를 observer로 감싸주어 state가 실시간으로 변경되는 것을 감지한다
const App: React.FC = observer(() => {
  const { countClass, countObject } = store

  return (
    <div style={{ padding: '50px' }}>
      <div style={{ marginBottom: '50px' }}>
        <h1>Count (Class)</h1>
        <div>number: {countClass.number}</div>
        <button onClick={() => countClass.increase()}>plus</button>
        <button onClick={() => countClass.decrease()}>minus</button>
      </div>

      <div style={{ marginBottom: '50px' }}>
        <h1>Count (Object)</h1>
        <div>num: {countObject.num}</div>
        <button onClick={() => countObject.increase()}>increment</button>
      </div>
    </div>
  )
})

export default App
// export default observer(App) // 이렇게 감싸줄수도 있다



autorun


  • reaction의 중요성은 observable state에 대한 소비자(consumer)를 만들어내거나 무언가 관련된 요소가 바뀔 때 자동적으로 부수효과를 실행하는 데 있습니다.

  • 형식
autorun(effect: (reaction) => void)

  • autorun 함수는 변화를 감지할 때마다 실행하는 함수 한 개를 수용하며, autorun 자체를 생성할 때도 한 번 실행됩니다.

  • autorunobservable 또는 computed로 주석 설정한 observable state의 변화에만 반응합니다.


  • 트래킹 동작 원리


    • autorun은 반응형 컨텍스트 내의 effect를 실행함으로써 동작합니다.

    • 제공된 함수가 실행되는 동안 MobX는 effect로부터 직접적으로 혹은 간접적으로 읽어들이는 모든 observable 및 computed 값을 트래킹 합니다.

    • 함수 동작이 끝나면 MobX는 읽어들인 모든 observable 항목들을 모으고 구독하며, 해당 항목들 중 일부가 다시 변경될 때까지 기다립니다.

    • 변경이 완료되면 autorun은 다시 트리거 되고 전체 과정을 반복합니다.

⚪ effect 함수 내부의 obsevable를 subscribe 합니다.
⚪ obsevable이 변경되면 autorun 를 실행시킵니다.
⚪ autorun은 초기화시 실행 됩니다.



  
import { makeAutoObservable, autorun } from "mobx"

class Animal {
    name
    energyLevel

    constructor(name) {
        this.name = name
        this.energyLevel = 100
        makeAutoObservable(this)
    }

    reduceEnergy() {
        this.energyLevel -= 10
    }

    get isHungry() {
        return this.energyLevel < 50
    }
}

const giraffe = new Animal("Gary")

autorun(() => {
    console.log("Energy level:", giraffe.energyLevel)
})

autorun(() => {
    if (giraffe.isHungry) {
        console.log("Now I'm hungry!")
    } else {
        console.log("I'm not hungry!")
    }
})

console.log("Now let's change state!")
for (let i = 0; i < 10; i++) {
    giraffe.reduceEnergy()
}
  
  


//1. initialize -> 2. read & subscripbe
Energy level: 100
I'm not hungry!

//3. update state
Now let's change state!

//4. notify and re-run autorun
Energy level: 90
Energy level: 80
Energy level: 70
Energy level: 60
Energy level: 50
Energy level: 40
Now I'm hungry!
Energy level: 30
Energy level: 20
Energy level: 10
Energy level: 0

  • 위 코드의 처음 두 줄에 보이듯이, 두 개의 autorun 함수는 초기화될 때 한 번 실행됩니다.

    • for 루프가 없어도 해당 두 줄은 보일 것입니다.
  • reduceEnergy action으로 energyLevel를 변경하기 위해 for 루프를 실행하면, autorun 함수가 observable state의 변화를 감지하는 '모든 순간' 새로운 로그를 출력합니다.

  • 함수 "Energy level"의 측면에서 '모든 순간'이란 observable 속성을 가진 energyLevel이 변경되는 10회입니다.

  • 함수 "Now I'm hungry"의 측면에서 '모든 순간'이란 computed 속성을 가진 isHungry가 변경되는 1회입니다.

⚪처음 초기화 시 실행 된다.
⚪인자로 받은 함수내에 있는 모든 observable를 추적한다.



  • autorun 은 reaction 이나 computed 의 observe 대신에 사용 될 수 있는데, autorun 으로 전달해주는 함수에서 사용되는 값이 있으면 자동으로 그 값을 주시하여 그 값이 바뀔 때 마다 함수가 주시되도록 해줍니다. 여기서 만약에 computed 로 만든 값의 .get() 함수를 호출해주면, 하나하나 observe 해주지 않아도 됩니다.


import { observable, reaction, computed, autorun } from 'mobx';

// Observable State 만들기
const calculator = observable({
  a: 1,
  b: 2
});

// computed 로 특정 값 캐싱
const sum = computed(() => {
  console.log('계산중이예요!');
  return calculator.a + calculator.b;
});

// **** autorun 은 함수 내에서 조회하는 값을 자동으로 주시함
autorun(() => console.log(`a 값이 ${calculator.a} 로 바뀌었네요!`));
autorun(() => console.log(`b 값이 ${calculator.b} 로 바뀌었네요!`));
autorun(() => sum.get()); // sum

calculator.a = 10;
calculator.b = 20;

// 여러번 조회해도 computed 안의 함수를 다시 호출하지 않지만..
console.log(sum.value);
console.log(sum.value);

calculator.a = 20;

// 내부의 값이 바뀌면 다시 호출 함
console.log(sum.value);


a 값이 1 로 바뀌었네요! 
b 값이 2 로 바뀌었네요! 
계산중이예요! 
a 값이 10 로 바뀌었네요! 
계산중이예요! 
b 값이 20 로 바뀌었네요! 
계산중이예요! 
30
30
a 값이 20 로 바뀌었네요! 
계산중이예요! 
40



reaction


  • 형식
reaction(() => value, (value, previousValue, reaction) => { sideEffect }, options?)

  • autorun 보다 더 세밀한 제어가 가능

  • 2가지 인자를 받는데 첫번째 함수의 observable를 추적하고 renturn 값을 2번째 함수에서 사용합니다.

  • 첫번째 함수에서 쓰인 observable의 변화에만 반응합니다.

  • autorun과 달리 초기화시 실행 되지 않습니다.


reaction(
  () => giraffe.isHungry,
  isHungry => {
    if (isHungry) {
      console.log("Now I'm hungry!");
    } else {
      console.log("I'm not hungry!");
    }
    console.log("Energy level:", giraffe.energyLevel);
  }
);
Now let's change state!
Now I'm hungry!
Energy level: 40

⚪처음 초기화 시 실행 되지 않는다.
⚪effect 함수 내에서 쓰이는 giraffe.energyLevel의 변화는 추적하지 않는다.



좋은 웹페이지 즐겨찾기