Created
October 3, 2022 20:54
-
-
Save brandonchadlange/4fc268600d1636b80bb926e4e8ee82fc to your computer and use it in GitHub Desktop.
Todos full implementation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface Todo { | |
description: string; | |
complete: boolean; | |
} | |
const useTodoListViewModel = () => { | |
const [todos, setTodos] = useState<Todo[]>([]); | |
const createTodo = (description: string) => { | |
const newTodo: Todo = { | |
description, | |
complete: false, | |
}; | |
setTodos((current) => [...current, newTodo]); | |
}; | |
return { | |
todos, | |
createTodo, | |
}; | |
}; | |
const TodoList = ({ todos }: { todos: Todo[] }) => { | |
const todoList = todos.map((todo) => <Todo todo={todo} />); | |
return <ul>{todoList}</ul>; | |
}; | |
const useTodoViewModel = (todo: Todo) => { | |
const [checked, setChecked] = useState(todo.complete); | |
const textDecoration = { | |
textDecoration: todo.complete ? "line-through" : "none", | |
}; | |
const toggleChecked = () => { | |
setChecked((checked) => !checked); | |
}; | |
return { | |
description: todo.description, | |
checked, | |
textDecoration, | |
toggleChecked, | |
}; | |
}; | |
const Todo = ({ todo }: { todo: Todo }) => { | |
const vm = useTodoViewModel(todo); | |
return ( | |
<li> | |
<label> | |
<input | |
defaultChecked={vm.checked} | |
onChange={vm.toggleChecked} | |
type="checkbox" | |
/> | |
<span style={{ ...vm.textDecoration }}>{vm.description}</span> | |
</label> | |
</li> | |
); | |
}; | |
const useAddTodoVm = (onAdd: (description: string) => void) => { | |
const [inputText, setInputText] = useState(""); | |
const addTodo = () => { | |
onAdd(inputText); | |
setInputText(""); | |
}; | |
return { | |
inputText, | |
setInputText, | |
addTodo, | |
}; | |
}; | |
interface AddTodoViewModel { | |
inputText: string; | |
setInputText: (inputText: string) => void; | |
addTodo: () => void; | |
} | |
const AddTodo = ({ viewModel }: { viewModel: AddTodoViewModel }) => { | |
return ( | |
<> | |
<input | |
value={viewModel.inputText} | |
onChange={(e) => viewModel.setInputText(e.target.value)} | |
type="text" | |
placeholder="Add todo" | |
/> | |
<button onClick={viewModel.addTodo}>Add</button> | |
</> | |
); | |
}; | |
const Todos = () => { | |
const listVm = useTodoListViewModel(); | |
const addTodoVm = useAddTodoVm(listVm.createTodo); | |
return ( | |
<> | |
<TodoList todos={listVm.todos} /> | |
<AddTodo viewModel={addTodoVm} /> | |
</> | |
); | |
}; | |
export default Todos; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@brandonchadlange how about these
pattern
INTERFACE
VIEW MODEL
component