Container에 이어서 mobx로 to do app 구현하기를 해봤다.
여러개의 컴포넌트에서 store를 import해서 쓰니까 확실히 사용법을 익히게 되었다.
디렉토리 구조
- src > pages > Todo.jsx / Input.jsx / List.jsx : Components 역할
- src > stores > todo.js : input과 todoList state 관리하는 store 역할
- src > useStore.js : store를 모아서 api처럼 사용하는 역할
todo.js : Store : app과 관련된 상태 input과 list를 같이 관리한다.
import { observable } from 'mobx';
export const todo = observable({
input: "",
todoList: [],
setInput(text) {
this.input = text;
//input value 관리
},
clearInput() {
this.input = "";
//input value 지우기
},
add() {
const temp = { key: Date.now(), what: this.input };
this.todoList.push(temp);
//todo object를 생성해서 list에 추가
},
remove(id) {
this.todoList = this.todoList.filter(item => item.key !== id);
st); //삭제할 object를 list에서 제거
},
reset() {
this.todoList.splice(0);
//list reset
},
});
- 더 공부할 것 : array 함수(splice, filter 등)
Todo.jsx : todo list과 input을 보여주는 component
import React from 'react'
import { useObserver } from 'mobx-react'
import useStore from '../useStore'
import Input from './Input'
import List from './List'
const Todo = () => {
const { todo } = useStore();
const handleReset = () => {
todo.reset(); }
return useObserver(() => (
<div>
<Input />
<ul>
{todo.todoList.map(item => <List key={item.key} item={item} />)}
</ul>
<button onClick={handleReset}>RESET!</button>
</div>
)
);
}
export default Todo
- map 함수를 통해 list 반복을 할 때 항상 key값을 고유한 값으로 주어야 한다.
List.jsx : 각 todo list component
import React, { memo } from 'react'
import useStore from '../useStore'
const List = memo(({ item }) => {
const { todo } = useStore();
const { what } = item;
const handleRemove = () => {
todo.remove(item.key);
};
return (
<li>
<p>{what}</p>
<button onClick={handleRemove}>I DID IT</button>
</li>
)
}
)
export default List
- 주의할 점 : 부모 컴포넌트에서 그려지는 자식컴포넌트라 해도, STORE를 이용할 경우 useStore를 import 해줘야한다! (useObserver는 NO!)
- Re-rendering을 막기 위해 memo 사용
Input.jsx : 할 일을 입력하기 위한 Input
import React, { useRef, memo } from 'react'
import { useObserver } from 'mobx-react'
import useStore from '../useStore'
const Input = memo(() => {
const { todo } = useStore();
const inputRef = useRef();
const handleChange = () => {
todo.setInput(inputRef.current.value);
}
const handleClick = (e) => {
e.preventDefault();
todo.add();
todo.clearInput();
inputRef.current.focus();
}
return useObserver(() => (
<div>
<input ref={inputRef} type="text" value={todo.input} placeholder="input what you're doing..." onChange={handleChange} />
<button onClick={handleClick}>I CAN DO IT!</button>
</div>
)
);
}
)
export default Input
사실 구현해놓고 보니 input value를 굳이 상태로 관리했어야하나 싶기도 하다. 그래도 뭐 그냥 상태연습으로 치고…
- useRef를 이용해 input 제어하기(공부더하기)