observer 변수가 갱신되면, observer 변수를 사용하는 computed가 호출된다.
단, computed가 어디에선가 사용되고 있을 때 호출된다.
ex) render에서 사용, autorun에서 사용
import './App.css';
import { observer } from "mobx-react";
import { makeObservable, observable, computed, action, autorun, get } from "mobx";
import { configure } from '@testing-library/react';
import { Component } from 'react';
//경고 막기
configure({enforceActions:"never",});
class Tiger{
count = 0;
constructor(){
makeObservable(this,{
count: observable,
comA: computed,
increase:action,
});
//autorun에서 사용해도 호출된다.
autorun(() => {
console.log("Auto Run : " );
});
}
get comA(){
console.log('comA : ', this.count);
return 100;
};
//1. observer 변수가 갱신되면, observer 변수를 사용하는 computed가 호출된다.
// 단, computed가 어디에선가 사용되고 있을 때 호출된다.
// ex) render에서 사용, autorun에서 사용
increase(){
console.log('increase');
this.count++;
}
}
const tiger = new Tiger();
console.log('--------------------');
class App extends Component {
f1 = () => {
tiger.increase();
}
render() {
return (
<div>
<button onClick={this.f1}>버튼</button>
<h1>{tiger.count}</h1>
<h1>{tiger.comA}</h1>
</div>
);
}
}
export default observer(App);
import './App.css';
import { observer } from "mobx-react";
import { makeObservable, observable, computed, action, autorun, get } from "mobx";
import { configure } from '@testing-library/react';
import { Component } from 'react';
//경고 막기
configure({enforceActions:"never",});
class Tiger{
count = 0;
constructor(){
makeObservable(this,{
count: observable,
comA: computed,
increase:action,
});
//autorun에서 사용해도 호출된다.
autorun(() => {
console.log("Auto Run : " );
});
}
get comA(){
console.log('comA : ', this.count);
return 100;
};
//1. observer 변수가 갱신되면, observer 변수를 사용하는 computed가 호출된다.
// 단, computed가 어디에선가 사용되고 있을 때 호출된다.
// ex) render에서 사용, autorun에서 사용
//2. compute 변수가 <변경 or 갱신>이 일어나면 compute 변수를 사용하는 autorun이 호출된다.
increase(){
console.log('increase');
this.count++;
}
}
const tiger = new Tiger();
console.log('--------------------');
class App extends Component {
f1 = () => {
tiger.increase();
}
render() {
return (
<div>
<button onClick={this.f1}>버튼</button>
<h1>{tiger.count}</h1>
<h1>{tiger.comA}</h1>
</div>
);
}
}
export default observer(App);
import './App.css';
import { observer } from "mobx-react";
import { makeObservable, observable, computed, action, autorun, get } from "mobx";
import { configure } from '@testing-library/react';
import { Component } from 'react';
//경고 막기
configure({enforceActions:"never",});
class Tiger{
count = 0;
constructor(){
makeObservable(this,{
count: observable,
comA: computed,
comB: computed,
increase:action,
});
// autorun에서 사용해도 호출된다.
autorun(() => {
console.log("Auto Run1 : ", this.comA );
});
autorun(() => {
console.log("Auto Run2 : ", this.comB );
});
}
get comA(){
console.log('comA : ', this.count);
//조건이 만족될 때만 호출이 발생한다.
return this.count > 2;
}
get comB(){
console.log('comB : ', this.count);
//return에 변수를 넣으면 갱신이 발생한다.
return this.count;
};
increase(){
console.log('increase');
this.count++;
}
}
const tiger = new Tiger();
console.log('--------------------');
class App extends Component {
f1 = () => {
tiger.increase();
}
render() {
return (
<div>
<button onClick={this.f1}>버튼</button>
<h1>{tiger.count}</h1>
<h1>{tiger.comA}</h1>
<h1>{tiger.comB}</h1>
</div>
);
}
}
export default observer(App);
computed 값을 사용하여 다른 observable 정보를 얻을 수 있습니다.
computed 값은 느리게 평가하여 출력을 캐싱하고 observables 중 하나가 변경된 경우에만 다시 계산합니다.
아무것도 관찰되지 않으면 완전히 작동을 멈춥니다.
개념적으로 스프레드시트의 수식과 매우 유사하며 과소평가할 수 없습니다. 저장해야 하는 state를 줄이는 데 도움이 되며 매우 최적화되어 있습니다. 가능한 모든 곳에 사용하세요.
makeObservable
을 사용하여 getter를 computed로 선언합니다.
makeAutoObservable
, observable
또는 extendObservable
를 사용하시면 됩니다.
import { makeObservable, observable, computed, autorun } from "mobx"
class OrderLine {
price = 0
amount = 1
constructor(price) {
makeObservable(this, {
price: observable,
amount: observable,
total: computed
})
this.price = price
}
get total() {
console.log("Computing...")
return this.price * this.amount
}
}
const order = new OrderLine(0)
const stop = autorun(() => {
console.log("Total: " + order.total)
})
// 계산중...
// Total: 0
console.log(order.total)
// 재계산 되지 않음!
// 0
order.amount = 5
// 계산중...
// autorun 실행 안됨
order.price = 2
// 계산중...
// Total: 10
stop()
order.price = 3
// computation, autorun 둘다 다시 계산되지 않습니다.
import './App.css';
import { observer } from "mobx-react";
import { makeObservable, observable, computed, action, autorun, get, configure } from "mobx";
import { Component } from 'react';
//3)
//경고 막기
configure({enforceActions:"never",});
class OrderLine {
price = 0;
amount = 1;
constructor(price) {
makeObservable(this, {
price: observable,
amount: observable,
total: computed
});
autorun(() => {
console.log("Total: " + this.total);
});
autorun(() => {
console.log("Price: " + this.price);
});
}
get total() {
console.log("Computing...");
//처음이 0이기 때문에 3번을 먼저 실행해도 결과의 변화가 없어 autorun이 실행되지 않는다.
return this.price * this.amount;
}
}
const order = new OrderLine(0);
console.log("---------객체 생성 완료---------");
class App extends Component {
f1 = () => {
console.log(order.total);
}
f2 = () => {
order.price += 1;
}
f3 = () => {
order.amount += 10;
}
f4 = () => {
order.price = 0;
order.amount = 0;
}
render() {
return (
<div>
<button onClick={this.f1}>one: total</button>
<button onClick={this.f2}>two: price</button>
<button onClick={this.f3}>three: amount</button>
<button onClick={this.f4}>reset</button>
<h1>price: {order.price}</h1>
<h1>amount: {order.amount}</h1>
<h1>total: {order.total}</h1>
</div>
);
}
}
export default observer(App);
import './App.css';
import { observer } from "mobx-react";
import { makeObservable, observable, computed, action, autorun, get, configure, makeAutoObservable } from "mobx";
import { Component } from 'react';
// //경고 막기
configure({enforceActions:"never",});
//5)
class Animal {
energyLevel;
constructor() {
this.energyLevel = 100;
makeObservable(this, {
energyLevel: observable,
inc: action
});
//observer 데이터가 갱신되면
//observer 데이터를 사용하는 autorun이 호출된다.
autorun(() => {
console.log("Energy level:", this.energyLevel);
});
}
inc(){
console.log('inc');
this.energyLevel += 10;
}
}
const giraffe = new Animal();
console.log("Now let's change state!");
class App extends Component {
f1 = () => {
giraffe.inc();
}
render() {
return (
<div>
<button onClick={this.f1}>one</button>
</div>
);
}
}
export default observer(App);
import './App.css';
import { observer } from "mobx-react";
import { Component } from 'react';
import { makeObservable, observable, computed, action, autorun, get, configure } from "mobx";
configure({enforceActions:"never",});
class ObservableTodoStore {
todos = [];
constructor() {
makeObservable(this, {
todos: observable,
completedTodosCount: computed,
report: computed,
addTodo: action,
});
autorun(() => console.log(this.report));
}
get completedTodosCount() {
console.log('completedTodosCount');
return this.todos.filter(
todo => todo.completed === true
).length;
}
get report() {
console.log('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,
});
}
}
const observableTodoStore = new ObservableTodoStore();
console.log('----객체 생성 완료----');
// 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>
// );
// })
class App extends Component {
f1 = () => {
observableTodoStore.addTodo("read MobX tutorial");
}
f2 = () => {
observableTodoStore.addTodo("try MobX");
}
f3 = () => {
observableTodoStore.todos[0].completed = true;
}
f4 = () => {
observableTodoStore.todos[0].task = "커피 사기";
}
f5 = () => {
observableTodoStore.todos[1].task = "뚜비 놀아주기";
}
render() {
return (
<div>
{/* <TodoList store={observableTodoStore}></TodoList> */}
<button onClick={this.f1}>one</button>
<button onClick={this.f2}>two</button>
<button onClick={this.f3}>three</button>
<button onClick={this.f4}>four</button>
<button onClick={this.f5}>five</button>
<h1>{observableTodoStore.completedTodosCount}</h1>
{
observableTodoStore.todos.map(value => {
return <h1>{value.task} {value.completed.toString()}</h1>
})
}
</div>
);
}
}
export default observer(App);
npm install --save redux
npm install --save react-redux
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { createStore } from 'redux';
import { reducer } from './App'
import { Provider } from 'mobx-react';
const store = createStore(reducer);
const listener = ()=>{
ReactDOM.render(
<App store={store}/>,
document.getElementById('root')
);
};
store.subscribe(listener);
listener();
import './App.css';
import React, { Component } from 'react';
class App extends Component {
increase = ()=>{
this.props.store.dispatch(add());
}
render() {
console.log(this.props.store.getState().num);
return (
<div>
<h1>App</h1>
<button onClick={this.increase}>버튼</button>
</div>
);
}
}
const add = () => {
return {type:ADD};
}
const ADD = 'ADD';
const initState = {
num:100,
};
export const reducer = (state = {num:100}, action) => {
switch(action.type){
case ADD:
return{
num: state.num + 1
};
default:
return state;
}
}
export default App;
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { createStore } from 'redux';
import { reducer } from './App'
import { Provider } from 'react-redux';
const store = createStore(reducer);
const listener = ()=>{
ReactDOM.render(
<Provider store={store}>
<App indexProp = {'react'}/>
</Provider>,
document.getElementById('root')
);
};
store.subscribe(listener);
listener();
import './App.css';
import React, { Component } from 'react';
import { connect } from 'react-redux';
class App extends Component {
increase = ()=>{
// this.props.store.dispatch(add());
this.props.dispatch(add());
}
render() {
// console.log(this.props.store.getState().num);
//console.log(this.props.store); //undefined (Provider 사용시 접근 X)
console.log(this.props.indexProp);
return (
<div>
<h1>App</h1>
<button onClick={this.increase}>버튼</button>
<h1>{this.props.num}</h1>
</div>
);
}
}
const add = () => {
return {type:ADD};
}
const ADD = 'ADD';
const initState = {
num:100,
};
export const reducer = (state = {num:100}, action) => {
switch(action.type){
case ADD:
return{
num: state.num + 1
};
default:
return state;
}
}
let mapStateToProps = (state, props) => {
console.log('mapStateToProps');
return {
num: state.num,
}
}
export default connect(
mapStateToProps, null
)(App);
import './App.css';
import React, { Component } from 'react';
import { connect } from 'react-redux';
class App extends Component {
increase = ()=>{
// this.props.store.dispatch(add());
this.props.dispatch(add());
}
render() {
// console.log(this.props.store.getState().num);
//console.log(this.props.store); //undefined (Provider 사용시 접근 X)
console.log(this.props.indexProp);
return (
<div>
<h1>App</h1>
<button onClick={this.increase}>버튼</button>
<h1>{this.props.num}</h1>
</div>
);
}
}
const add = () => {
return {type:ADD};
}
const ADD = 'ADD';
const initState = {
num:100,
};
export const reducer = (state = {num:100}, action) => {
switch(action.type){
case ADD:
return{
num: state.num + 1
};
default:
return state;
}
}
let mapStateToProps = (state, props) => {
console.log('mapStateToProps');
return {
num: state.num,
}
}
App = connect(mapStateToProps, null)(App);
export default App;
applyMiddleware()
import { applyMiddleware, createStore } from 'redux';
const store = createStore(reducer, applyMiddleware(mw));
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { applyMiddleware, createStore } from 'redux';
import { reducer } from './App'
import { Provider } from 'react-redux';
const mw = store => nextMiddle => action => {
console.log('1---------------------------');
console.log(store.getState().num);
let result = nextMiddle(action);
console.log('result', result);
//reducer 이후 코드
console.log('2---------------------------');
console.log(store.getState().num);
}
const store = createStore(reducer, applyMiddleware(mw));
const listener = ()=>{
ReactDOM.render(
<Provider store={store}>
<App indexProp = {'react'}/>
</Provider>,
document.getElementById('root')
);
};
store.subscribe(listener);
listener();
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { applyMiddleware, createStore } from 'redux';
import { reducer } from './App'
import { Provider } from 'react-redux';
const mw = store => nextMiddle => action => {
// console.log('1---------------------------');
// console.log(store.getState().num);
// let result = nextMiddle(action);
// console.log('result', result);
// //reducer 이후 코드
// console.log('2---------------------------');
// console.log(store.getState().num);
//reducer 실행 전
console.log('reducer 실행 전');
console.log('---------------------------');
let before = store.getState().num;
nextMiddle(action);
let after = store.getState().num;
//reducer 이후 코드
console.log('---------------------------');
console.log('reducer 실행 후');
console.log('reduce 전: ', before, 'reduce 후: ', after);
}
const store = createStore(reducer, applyMiddleware(mw));
const listener = ()=>{
ReactDOM.render(
<Provider store={store}>
<App indexProp = {'react'}/>
</Provider>,
document.getElementById('root')
);
};
store.subscribe(listener);
listener();
import './App.css';
import React, { Component } from 'react';
import { connect } from 'react-redux';
class App extends Component {
increase = ()=>{
// this.props.store.dispatch(add());
this.props.dispatch(add());
}
render() {
// console.log(this.props.store.getState().num);
//console.log(this.props.store); //undefined (Provider 사용시 접근 X)
// console.log(this.props.indexProp);
return (
<div>
<h1>App</h1>
<button onClick={this.increase}>버튼</button>
<h1>{this.props.num}</h1>
</div>
);
}
}
const add = () => {
return {type:ADD};
}
const ADD = 'ADD';
const initState = {
num:100,
};
export const reducer = (state = {num:100}, action) => {
console.log('reducer');
switch(action.type){
case ADD:
return{
num: state.num + 1
};
default:
return state;
}
}
let mapStateToProps = (state, props) => {
console.log('mapStateToProps');
return {
num: state.num,
}
}
App = connect(mapStateToProps, null)(App);
export default App;
npm install --save redux-logger
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { applyMiddleware, createStore } from 'redux';
import { reducer } from './App'
import { Provider } from 'react-redux';
import { createLogger } from 'redux-logger';
const mw = store => nextMiddle => action => {
console.log('reducer 실행 전');
console.log('---------------------------');
let before = store.getState().num;
nextMiddle(action);
let after = store.getState().num;
//reducer 이후 코드
console.log('---------------------------');
console.log('reducer 실행 후');
console.log('reduce 전: ', before, 'reduce 후: ', after);
}
const logger = createLogger();
// const store = createStore(reducer, applyMiddleware(mw));
const store = createStore(reducer, applyMiddleware(logger));
const listener = ()=>{
ReactDOM.render(
<Provider store={store}>
<App indexProp = {'react'}/>
</Provider>,
document.getElementById('root')
);
};
store.subscribe(listener);
listener();