191031 TIL MobX todo

» 1.5막, TIL (Today I Learned)

오늘 할 일

  1. 벨로퍼트 MobX 씹어먹기
  2. MobX & React로 뭐 만들어보기

observable

Usage: 
observable(value)
@observable classProperty = value

예시:

const calculator = observable({
  a: 1,
  b: 2
})

reaction

Usage: 
reaction(() => data, (data, reaction) => { sideEffect }, options?)

예시:

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

computed

예시:

const sum = computed(() => {
  console.log('calculating...');
  return calculator.a + calculator.b;
})

observe

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

예시

const person = observable({
  firstName: "soom",
  lastName: "Shin"
})

const disposer = observe(person, change => {
  console.log(change.type, change.name, "from", change.oldValue, 'to', change.object[change.name])
});

person.firstName = "soomin"

disposer();

//update firstName from soom to soomin 

autorun

reaction이나 computed의 observe대신 쓸 수 있음.
autorun에 전달해주는 함수에서 사용되는 값이 있으면 자동으로 그 값을 주시하여 그 값이 바뀔때마다 함수 주시됨.
computed로 만든 값의 .get() 함수를 호출해주면 observe 하나하나 안 달아줘도 됨.
설명 출처는 벨로퍼트님


image 공식사이트에 아주 좋은 이미지가 있어서 가져옴…


리액트로 todo 만들었던거 MobX써서 수정해보려고 하는데, 어디까지 빼도 되는지 구분이 잘 안되네…

image

ContextAPI -> MobX로 바꾸기

처음부터 아예 만들어보려고 했는데 너무 삽질이 큰 거 같아서 기존에 강의 보고 만든 걸 MobX로 바꿔보았다.

먼저 한 것

1. mobx, mobx-react 설치 및 decorator 추가

yarn add mobx mobx-react 
yarn add --dev customize-cra react-app-rewired @babel/plugin-proposal-decorators 

//package.json
   "scripts": {
-    "start": "react-scripts start",
-    "build": "react-scripts build",
-    "test": "react-scripts test",
+    "start": "react-app-rewired start",
+    "build": "react-app-rewired build",
+    "test": "react-app-rewired test",
     "eject": "react-scripts eject"
   },

// root에 config-overrides.js 파일 생성
const { override, addDecoratorsLegacy } = require('customize-cra')
// Adds legacy decorator support to the Webpack configuration.
module.exports = override(addDecoratorsLegacy())

2. store 생성 및 연결

//src > stores > todo.js  
import { observable, action, computed } from 'mobx';

export default class todoStore {
  // 기존 context파일에 initialTodos 가져옴 
  @observable todoList = [
    { id: 1, text: '프로젝트 생성하기', done: true },
    { id: 2, text: '밥먹기', done: true },
    { id: 3, text: '기능구현하기', done: false },
    { id: 4, text: '커피마시기', done: false }
  ];
}

// index.js
import { Provider } from 'mobx-react';
import TodoStore from './stores/todo';

const todo = new TodoStore();

ReactDOM.render(
	<Provider todo={todo}>
		<App/>
	</Provider>, document.getElementById('root')
);

//Todohead.js
import { inject, observer } from 'mobx-react';

const TodoHead = ({ todos }) => {
	// 기존의 state에서 가져오던 todos를 props로 넘겨줌
	// const todos = useTodoState();
	const undoneTasks = todos.filter(todo => !todo.done);
	
	return (
		<TodoHeadBlock>
			<div className="tasks-left">  {undoneTasks.length} 남았당!</div>
		</TodoHeadBlock>
	)
}

// 여기서 TodoList 주입 
export default inject(({ todo }) => ({
	todos: todo.todoList,
}))(observer(TodoHead));

3. dispatch로 전달하던 함수들 store로 이동 및 연결

//store
@action
toggle = id => {
    const item = this.todoList.find(item => item.id === id);
    item.done = !item.done;
};

//Todoitem.js
const TodoItems = observer(({ item, onToggle, onRemove}) => {
// 기존 dispatch로 넘겨주던 함수를 props로 받아옴 
/*	const dispatch = useTodoDispatch();
 	const onToggle = () => dispatch({ type: 'TOGGLE', id }); */

	return (
		<TodoItemBlock>
			<CheckCircle done={item.done} onClick={() => onToggle(item.id)}>
				{item.done && <MdDone/>}
			</CheckCircle>
			<Text done={item.done}> {item.text} </Text>
			<Remove onClick={() => onRemove(item.id)}>
				<MdDelete/>
			</Remove>
		</TodoItemBlock>
	);
});

contextAPI를 꺼도 작동 잘하면 문제 없긔~

- hooks 쓴 MobX 자료가 너무 없어서 어제 헤맸는데, hooks가 ... 필요 없어서 자료가 없는건가? 
- 아니, MobX 쓰면 리액트 배운걸 써먹을 데가 별로 없겠는걸? (아니겠지?)