TodoMVC
This is an example of real-time collaborative TodoMVC using CreatReactApp and Yorkie JS SDK.
App.tsx
1import React, { useState, useEffect } from 'react';2import yorkie, { Document, JSONArray } from 'yorkie-js-sdk';3import 'todomvc-app-css/index.css';45import Header from './Header';6import MainSection from './MainSection';7import { Todo } from './model';8import './App.css';910const initialState = [{11 id: 0,12 text: 'Yorkie JS SDK',13 completed: false,14}, {15 id: 1,16 text: 'Garbage collection',17 completed: false,18}, {19 id: 2,20 text: 'RichText datatype',21 completed: false,22}] as Array<Todo>;2324export default function App() {25 const [doc,] = useState<Document<{ todos: JSONArray<Todo> }>>(() =>26 new yorkie.Document<{ todos: JSONArray<Todo> }>(27 `react-todomvc-${(new Date()).toISOString().substring(0, 10).replace(/-/g, '')}`28 )29 );30 const [todos, setTodos] = useState<Array<Todo>>([]);3132 const actions = {33 addTodo: (text: string) => {34 doc?.update((root) => {35 root.todos.push({36 id: root.todos.reduce((maxId, todo) => Math.max(todo.id, maxId), -1) + 1,37 completed: false,38 text,39 });40 });41 },42 deleteTodo: (id: number) => {43 doc?.update((root) => {44 let target;45 for (const todo of root.todos) {46 if (todo.id === id) {47 target = todo as any;48 break;49 }50 }51 if (target) {52 root.todos.deleteByID!(target.getID());53 }54 });55 },56 editTodo: (id: number, text: string) => {57 doc?.update((root) => {58 let target;59 for (const todo of root.todos) {60 if (todo.id === id) {61 target = todo;62 break;63 }64 }65 if (target) {66 target.text = text;67 }68 });69 },70 completeTodo: (id: number) => {71 doc?.update((root) => {72 let target;73 for (const todo of root.todos) {74 if (todo.id === id) {75 target = todo;76 break;77 }78 }79 if (target) {80 target.completed = !target.completed;81 }82 });83 },84 clearCompleted: () => {85 doc?.update((root) => {86 for (const todo of root.todos) {87 if (todo.completed) {88 const t = todo as any;89 root.todos.deleteByID!(t.getID());90 }91 }92 }, '');93 }94 };9596 useEffect(() => {97 const client = new yorkie.Client(import.meta.env.VITE_YORKIE_API_ADDR, {98 apiKey: import.meta.env.VITE_YORKIE_API_KEY,99 });100101 async function attachDoc(doc: Document<{ todos: JSONArray<Todo> }>, callback: (todos: any) => void) {102 // 01. create client with RPCAddr(envoy) then activate it.103 await client.activate();104105 // 02. attach the document into the client.106 await client.attach(doc);107108 // 03. create default todos if not exists.109 doc.update((root) => {110 if (!root.todos) {111 root.todos = initialState;112 }113 }, 'create default todos if not exists');114115 // 04. subscribe change event from local and remote.116 doc.subscribe((event) => {117 callback(doc.getRoot().todos);118 });119120 // 05. set todos the attached document.121 callback(doc.getRoot().todos);122 }123124 attachDoc(doc, (todos) => {125 setTodos(todos);126 });127 }, []);128129 return (130 <div className="App">131 <Header addTodo={actions.addTodo} />132 <MainSection todos={todos} actions={actions} />133 </div>134 );135}
- User 1
- User 2
- User 1
- User 2
Event Log