원본 URL :https://sunilsandhu.com/posts/i-created-the-exact-same-app-in-react-and-vue-2020-edition
몇 년 전, 나는 React and Vue에서 상당히 표준적인 To Do App을 만들려고 노력했습니다. 두 앱 모두 기본 CLI (React 용 create-react-app 및 Vue 용 vue-cli)를 사용하여 구축되었습니다.
나는 원래 쓴 기사는 바이러스 성가는 끝났다. 높이에서 분당 ~ 1000 회 조회를 받았으며 여전히 기술 기사에 대해 겸손하게 생각합니다. 많은 사람들이 저와 비슷한 상황에 처해 있고 그러한 기사가 쓰여지기를 기다리고 있다는 것을 알게되어 정말 기뻤습니다.
React Hooks가 릴리스되었을 때 클래스 컴포넌트 사용을 Functional Hooks로 대체 한 ' 2019 Edition '으로 원본 기사를 추적했습니다 . Vue 버전 3과 컴포지션 API가 출시되면서 이제이 기사를 '2020 Edition'으로 다시 업데이트 할 차례입니다.
두 앱의 CSS 코드는 정확히 동일하지만 위치에 차이가 있습니다. 이를 염두에두고 다음으로 두 앱의 파일 구조를 살펴 보겠습니다.
구조가 비슷하다는 것을 알 수 있습니다. 지금까지의 주요 차이점은 React 앱에는 두 개의 CSS 파일이 있고 Vue 앱에는없는 CSS 파일이 있다는 것입니다. 그 이유는 create-react-app가 스타일에 따라 별도의 CSS 파일을 사용하여 기본 React 구성 요소를 작성하는 반면 Vue CLI는 기본 Vue 구성 요소에 대해 HTML, CSS 및 JavaScript를 포함하는 단일 파일을 작성하기 때문입니다.
궁극적으로 둘 다 동일한 것을 달성하며 React 또는 Vue에서 파일을 다르게 구성 할 수는 없습니다. 그것은 실제로 개인 취향에 달려 있습니다. 스타일 구성 요소 및 감정과 같은 여러 CSS-in-JS 솔루션이 있기 때문에 특히 React와 관련하여 CSS가 어떻게 구성되어야하는지에 대해 개발자 커뮤니티로부터 많은 토론을들을 것입니다. CSS-in-JS는 말 그대로 들립니다. 이것들은 유용하지만 지금은 두 CLI에 배치 된 구조를 따릅니다.
그러나 더 나아 가기 전에 일반적인 Vue 및 React 구성 요소가 어떻게 보이는지 살펴 보겠습니다.
일반적인 React 파일 :
일반적인 Vue 파일 :
이제 그 길을 벗어났습니다. 딱딱한 세부 사항을 살펴 봅시다!
그러나 먼저 "데이터 변경"이라는 의미는 무엇입니까? 좀 기술적으로 들리지 않습니까? 기본적으로 우리가 저장 한 데이터를 변경하는 것을 의미합니다. 따라서 사람의 이름 값을 John에서 Mark로 변경하려면 '데이터를 변경'해야합니다. 이것이 바로 React와 Vue의 주요 차이점입니다. Vue는 기본적으로 데이터를 자유롭게 업데이트 할 수있는 데이터 객체를 생성하지만 React는 상태 후크라고하는 것을 통해이를 처리합니다.
아래 이미지에서 두 가지에 대한 설정을 살펴보고 다음에 무슨 일이 일어나고 있는지 설명하겠습니다.
반응 상태 :
Vue 상태 :
따라서 동일한 데이터를 둘 다에 전달했음을 알 수 있지만 구조는 약간 다릅니다.
React를 사용하거나 최소한 2019 년부터는 일반적으로 일련의 후크를 통해 상태를 처리합니다. 이전에 이런 유형의 개념을 보지 못했다면 처음에는 조금 이상하게 보일 수 있습니다. 기본적으로 다음과 같이 작동합니다.
할 일 목록을 만들고 싶다고 가정 해 봅시다. list라는 변수를 만들어야 할 수도 있고 문자열이나 객체의 배열을 취해야 할 수도 있습니다 (각 todo 문자열에 ID 및 기타 다른 것을 제공하려는 경우)
const [list, setList] = useState([])
.
우리는 React가 Hook라고하는 것을 사용하고 있는데 useState 이것은 기본적으로 컴포넌트 내에서 로컬 상태를 유지할 수 있게합니다.
또한 [] 내부에 useState() 빈 배열을 전달한 것을 알 수 있습니다.
우리가 거기에 넣은 것은 우리가 목록을 처음에 설정하려는 것입니다.이 경우에는 빈 배열이되고 싶습니다.
그러나 위의 이미지에서 배열 내부의 일부 데이터를 전달 했으므로 list의 초기화 데이터가됩니다.
setList의 기능이 궁금하십니까?
이것에 대해서는 나중에 더있을 것입니다!
Vue에서는 일반적으로 setup() 노출하려는 데이터와 함수를 사용하여 객체를 반환하는 함수 내부의 구성 요소에 대한 모든 변경 가능한 데이터를 배치합니다
(기본적으로 사용하려는 항목을 의미합니다).
앱의 각 상태 (일명 변경하려는 데이터) 데이터가 ref() 함수 안에 래핑되어 있음을 알 수 있습니다.
이 ref() 함수는 Vue에서 가져 와서 데이터가 변경 / 업데이트 될 때마다 앱이 업데이트 될 수 있도록하는 기능입니다.
간단히 말해 Vue에서 가변 데이터를 만들려면 변수를 ref() 함수에 할당하고 기본 데이터를 그 안에 넣습니다.
Sunil 이름의 데이터가 있다고 가정 해 봅시다.
React에서 우리가 만든 더 작은 상태의 조각을 가지 므로, useState() 의 라인을 따라 무언가를 만들었을 것입니다
const [name, setName] = useState('Sunil')
우리의 앱에서는 단순히 이름을 호출하여 동일한 데이터를 참조합니다.
name = 'John'
React는 이러한 종류의 쉽고 간결한 변이를 막기위한 제한이 있기 때문에 여기서 간단히 작성할 수 없다는 점이 다릅니다.
그래서 React에서 우리는 글을 쓸 것 setName('John') 입니다.
여기에서 setName 비트가 작동합니다.
기본적으로 const [name, setName] = useState('Sunil') 에서 두 개의 변수를 만듭니다. 하나는 변수가되고 const name = 'Sunil' , 두 번째 변수 const setName 는 이름을 새 값으로 다시 만들 수있는 함수가 할당됩니다.
Vue에서 이것은 setup() 함수 내부에 있으며 호출되었을 것
const name = ref(‘Sunil')
입니다.
우리 앱에서는을 호출하여이를 참조 할 것 name.value 입니다.
Vue를 사용하면 ref() 함수 내부에서 만든 값을 사용하려면 단순히 변수를 호출하는 대신 value 변수를 찾습니다
다시 말해, 상태를 유지하는 name변수의 값을 원하면 name.value 찾습니다
name 의 값을 업데이트하려면 name.value 을 업데이트하면 name 됩니다
예를 들어, 이름을 Sunil에서 John으로 바꾸고 싶다고 가정 해 봅시다.
나는 이것을 작성하여 이것을 name.value = "John" 할 것 입니다.
나는 존이라고 불리우는 것에 대해 어떻게 생각하는지 모르겠지만, 일이 일어난다! �
효과적으로 React와 Vue는 여기서 동일한 작업을 수행하여 업데이트 할 수있는 데이터를 생성합니다. Vue는 기본적으로 ref() 함수 내부에서 랩핑 된 데이터 조각이 업데이트 될 때마다 기본적으로 자체 버전의 name과 setName을 결합합니다.
React는 상태를 업데이트하기 위해 내부 값으로 setName ()을 호출해야합니다 .Vue는 데이터 객체 내부의 값을 업데이트하려고 할 때이 작업을 원한다고 가정합니다.
그렇다면 왜 React는 함수에서 값을 분리하는 데 신경을 쓰며 왜 useState() 필요한가?
기본적으로 React는 상태가 변경 될 때마다 특정 수명주기 후크를 다시 실행할 수 있기를 원합니다.
이 예에서 React는 setName() 일부 상태가 변경되었음을 알 수 있으므로 해당 수명주기 후크를 실행할 수 있습니다.
주기 상태를 직접 변경 한 경우 React는 변경 사항 및 실행주기 등을 추적하기 위해 더 많은 작업을 수행해야합니다.
이제 돌연변이가 발생 했으므로 To Do Apps 모두에 새 항목을 추가하는 방법을 살펴보면서 엉뚱하고하자.
새로운 할 일 항목을 어떻게 만듭니까?
const createNewToDoItem = () => { const newId = generateId(); const newToDo = { id: newId, text: toDo }; setList([...list, newToDo]); setToDo(""); };
React에서 입력 필드에는 value 라는 속성이 있습니다 . 이 값은 onChange 이벤트 리스너를 통해 값이 변경 될 때마다 자동으로 업데이트됩니다 . JSX (기본적으로 HTML의 변형)는 다음과 같습니다.
<input type="text" placeholder="I need to..." value={toDo} onChange={handleInput} onKeyPress={handleKeyPress} />
따라서 값이 변경 될 때마다 상태가 업데이트됩니다. handleInput 함수는 다음과 같습니다.
const handleInput = (e) => { setToDo(e.target.value); };
이제 사용자 가 페이지 에서 + 버튼을 눌러 새 항목을 추가 할 때마다 createNewToDoItem 함수가 트리거됩니다. 이 기능을 다시 살펴보고 진행중인 작업을 분석해 보겠습니다.
const createNewToDoItem = () => { const newId = generateId(); const newToDo = { id: newId, text: toDo }; setList([...list, newToDo]); setToDo(""); };
기본적으로 이 newId 기능은 기본적으로 새 toDo 항목에 부여 할 새 ID를 생성합니다
newToDo 변수 NEWID의 값을 부여하는 ID 키가 걸리는 것을 목적으로한다.
또한 text 가치에서 가치를 얻는 열쇠가 toDo 있습니다.
toDo 입력 값이 변경 될 때마다 업데이트되는 것과 동일 합니다.
그런 다음 setList 함수를 실행 list 하고 새로 작성된 전체 뿐만 아니라 전체를 포함하는 newToDo 배열을 전달 합니다.
...list
비트가 이상하게 보일 경우 처음 세 점은 스프레드 연산자로 알려진 것으로, 기본적으로 list 전체 항목 배열을 배열로 전달하는 대신 기본적으로 모든 값을 별도의 항목으로 전달합니다.
혼란 스러운가?
그렇다면 스프레드에 대해 읽어 보는 것이 좋습니다.
어쨌든, 마침내 우리 setToDo() 는 빈 문자열을 실행 하고 전달합니다.
입력 값이 비어있어 새로운 할 일을 입력 할 수 있습니다.
function createNewToDoItem() { const newId = generateId(); list.value.push({ id: newId, text: todo.value }); todo.value = ""; }
Vue에서 입력 필드에는 v-model 이라는 핸들이 있습니다 . 이를 통해 양방향 바인딩 이라는 것을 수행 할 수 있습니다 . 입력 필드를 신속하게 살펴보고 진행 상황을 설명하겠습니다.
<input type="text" placeholder="I need to..." v-model="todo" v-on:keyup.enter="createNewToDoItem" />
V-Model은이 필드의 입력을 setup() 함수 상단에 생성 한 변수에 연결 한 다음 반환 한 객체의 내부에 키로 노출시킵니다.
우리는 지금까지 객체에서 반환 된 내용을 다루지 않았으므로 귀하의 정보를 위해 ToDo.vue setup()
내부의 함수 에서 반환 한 내용은 다음과 같습니다
return { list, todo, showError, generateId, createNewToDoItem, onDeleteItem, displayError };
우리의 상태 값은, 다른 우리는 우리의 응용 프로그램의 다른 곳에서 호출 할 수 할 기능은 모두 여기 list , todo 그리고 showError 있다.
자, 탄젠트에서 돌아와서 페이지가 로드되면 todo 빈 문자열로 설정했습니다
const todo = ref("")
const todo = ref("add some text here"):
입력 필드와 같이 이미 일부 데이터가있는 경우 입력 필드 안에 이미 텍스트가 추가되어 로드됩니다
어쨌든, 입력 필드에 입력하는 텍스트가 무엇이든 todo.value 빈 문자열로 다시 돌아갑니다
이것은 효과적으로 양방향 바인딩입니다. 입력 필드는 ref () 값을 업데이트 할 수 있고 ref () 값은 입력 필드를 업데이트 할 수 있습니다.
그래서 다시 찾고 createNewToDoItem() 이전의 코드 블록을, 우리는 우리의 내용을 밀어 볼 todo.value
에 list 눌러 - 배열 todo.value 에 list.value
- 다음 업데이트 todo.value 빈 문자열로. 또한 React 예제에서 사용 된 것과 동일한 newId () 함수를 사용했습니다.
const deleteItem = (id) => { setList(list.filter((item) => item.id !== id)); };
따라서 deleteItem () 함수가 ToDo.js 안에 있지만 , 먼저 deleteItem () 함수를 소품으로 전달하여 ToDoItem.js 내에서 쉽게 참조 할 수있었습니다 . 따라서 :
<ToDoItem key={item.id} item={item} deleteItem={deleteItem} />
이것은 먼저 자식이 접근 할 수 있도록 함수를 전달합니다. 그런 다음 ToDoItem 구성 요소 내 에서 다음을 수행합니다.
<button className="ToDoItem-Delete" onClick={() => deleteItem(item.id)}> - </button>
부모 구성 요소 안에있는 함수를 참조하기 위해해야 할 일은 props.deleteItem 을 참조하는 것 입니다. 이제 코드 예제에서 props.deleteItem 대신 deleteItem을 작성했음을 알 수 있습니다. 우리가로 알려진 기술을 사용하기 때문이다 destructuring 우리가 일부 촬영 할 수 있습니다 소품 객체를 변수에 할당합니다. 그래서 우리의 ToDoItem.js의 파일, 우리는 다음이있다 :
const ToDoItem = (props) => { const { item, deleteItem } = props; }
이는 props.item과 동일한 값이 할당 된 item이라는 변수와 props.deleteItem에서 값이 할당 된 deleteItem이라는 두 가지 변수를 생성했습니다. props.item과 props.deleteItem을 사용하여이 모든 파괴적인 것을 피할 수 있었지만 언급 할 가치가 있다고 생각했습니다!
function onDeleteItem(id) { list.value = list.value.filter(item => item.id !== id); }
Vue에서는 약간 다른 접근 방식이 필요합니다. 우리는 본질적으로 여기에서 세 가지 일을해야합니다 :
먼저 요소에서 함수를 호출하려고합니다.
<button class="ToDoItem-Delete" @click="deleteItem(item.id)"> - </button>
그런 다음 자식 구성 요소 (이 경우 ToDoItem.vue ) 내에 메서드로 emit 함수를 만들어야합니다 .
function deleteItem(id) { emit("delete", id); }
이와 함께 ToDo.vue 안에 ToDoItem.vue 를 추가하면 실제로 함수를 참조한다는 것을 알 수 있습니다 .
<ToDoItem v-for="item in list" :item="item" @delete="onDeleteItem" :key="item.id" />
이것이 바로 사용자 정의 이벤트 리스너입니다. 'delete'문자열로 이미 터가 트리거되는 경우를 수신합니다. 이 소리가 들리면 onDeleteItem 이라는 함수를 트리거합니다 . 이 함수는 ToDoItem.vue 대신 ToDo.vue 안에 있습니다. 앞에서 설명한 것처럼이 함수는 단순히 배열 에서 필터링합니다 .
id list.value Vue 예제 $emit 에서 @click 리스너 내부를 간단히 다음과 같이 작성할 수 있음을 주목할 가치가 있습니다
<button class="ToDoItem-Delete" @click="emit("delete", item.id)"> - </button>
이것은 단계 수를 3에서 2로 줄 였을 것이며, 이것은 단순히 개인 취향에 달려 있습니다.
요컨대, React의 하위 구성 요소는 소품을 통해 부모 기능에 액세스 할 수 있습니다 (소품을 아래로 전달하면 상당히 표준적인 관행이며 다른 React 예제 에서이 많은 시간을 보게됩니다) .Vue에서는 일반적으로 부모 구성 요소 내에서 수집되는 자식에서 이벤트를 생성합니다.
클릭 이벤트와 같은 간단한 작업을위한 이벤트 리스너는 간단합니다. 다음은 새 ToDo 항목을 작성하는 단추에 대한 클릭 이벤트를 작성하는 방법의 예입니다.
<button className="ToDo-Add" onClick={createNewToDoItem}> + </button>
여기에서 매우 쉬우 며 바닐라 JS로 인라인 onClick을 처리하는 방법과 거의 같습니다. Vue 섹션에서 언급했듯이 enter 버튼을 누를 때마다 처리 할 이벤트 리스너를 설정하는 데 시간이 조금 더 걸렸습니다. 이를 위해서는 입력 태그가 onKeyPress 이벤트를 처리해야합니다.
<input type="text" placeholder="I need to..." value={toDo} onChange={handleInput} onKeyPress={handleKeyPress} />
이 함수 는 다음과 같이 'enter'키를 눌렀을 때마다 createNewToDoItem 함수를 트리거했습니다 .
const handleKeyPress = (e) => { if (e.key === "Enter") { createNewToDoItem(); } };
Vue에서는 매우 간단합니다. 우리는 단순히 @ 기호 를 사용하고 우리가 원하는 이벤트 리스너 유형을 사용합니다
예를 들어 클릭 이벤트 리스너를 추가하기 위해 다음을 작성할 수 있습니다.
<button class="ToDo-Add" @click="createNewToDoItem"> + </button>
참고 : @click 실제로 쓰는 것은 v-on:click 속기입니다
Vue 이벤트 리스너의 멋진 점은 이벤트 리스너가 두 번 이상 트리거되는 것을 막는 .once와 같이 체인으로 묶을 수있는 것들이 많이 있다는 것입니다.
키 스트로크를 처리하기 위해 특정 이벤트 리스너를 작성하는데도 많은 단축키가 있습니다.
Enter 버튼을 누를 때마다 새 ToDo 항목을 작성하는 데 React에서 이벤트 리스너를 작성하는 데 시간이 조금 더 걸린다는 것을 알았습니다.
Vue에서는 다음과 같이 간단하게 작성할 수있었습니다.
<input type=”text” v-on:keyup.enter=”createNewToDoItem”/>
이에 반응하여 소품이 생성 된 지점에서 자식 구성 요소에 소품을 전달합니다. 같은 :
<ToDoItem key={item.id} item={item} deleteItem={deleteItem} />;
여기 두 개의 소품이 ToDoItem 컴포넌트에 전달 된 것을 볼 수 있습니다. 이제부터 this.props를 통해 자식 구성 요소에서 참조 할 수 있습니다.
item.todo 소품 에 액세스하려면 호출하면 props.item 됩니다. key 소품 이 있다는 것을 알았을 것입니다
(기술적으로 실제로 3 개의 소품을 전달합니다).
이 업데이트를 만들고 (각 있기 때문에 우리가 여기 같은 구성 요소의 여러 버전 중 변경 추적에 올 때 쉽게 물건을 만들면서,의 내부 반응에 대한이 주로 할 일이 의 카피 ToDoItem (구성 요소).
또한 컴포넌트에 고유 키가 있는지 확인하는 것이 중요합니다. 그렇지 않으면 콘솔에서 React가이를 알려줍니다.
Vue에서는 소품이 생성되는 지점에서 자식 구성 요소에 소품을 전달합니다. 같은 :
<ToDoItem v-for="item in list" :item="item" @delete="onDeleteItem" :key="item.id" />
이 작업이 완료되면 다음과 같이 자식 구성 요소의 props: [ "todo" ] props 배열에 전달합니다
그런 다음 todo 에서 이름으로 참조 할 수 있습니다
해당 prop 키를 어디에 두어야할지 확실하지 않은 경우 다음은 export default 자식 구성 요소에서 전체 개체의 모양입니다.
export default { name: "ToDoItem", props: ["item"], setup(props, { emit }) { function deleteItem(id) { emit("delete", id); } return { deleteItem, }; }, };
Vue에서 데이터를 루핑 할 때 실제로 list 보다는 오히려 list.value 루핑했습니다
반복하려고하면 list.value 여기서 작동하지 않습니다.
먼저 하위 구성 요소를 호출하는 위치에서 소품으로 참조하여 하위 구성 요소에 함수를 전달합니다. 그런 다음 props.whateverTheFunctionIsCalled 를 참조 하거나 onDestructing 을 사용 하는 경우 whatTheFunctionIsCalled 를 참조 하여 onClick 과 같은 어떤 방법으로도 자식에 대한 함수 호출을 추가합니다 . 그러면 상위 컴포넌트에있는 기능이 트리거됩니다. '목록에서 삭제하는 방법' 섹션에서이 전체 프로세스의 예를 볼 수 있습니다 .
우리의 자식 컴포넌트에서, 우리는 단순히 부모 함수로 값을 내보내는 함수를 작성합니다. 부모 컴포넌트에서, 우리는 그 값이 방출 될 때 수신하는 함수를 작성하여 함수 호출을 트리거 할 수 있습니다. '목록에서 삭제하는 방법' 섹션에서이 전체 프로세스의 예를 볼 수 있습니다 .
데이터를 추가, 제거 및 변경하고 소품 형식의 데이터를 부모에서 자식으로 전달하고 자식에서 부모로 이벤트 리스너 형식으로 데이터를 보내는 방법을 살펴 보았습니다. 물론 React와 Vue 사이에 다른 많은 차이점과 단점이 있지만이 기사의 내용이 두 프레임 워크가 물건을 처리하는 방법을 이해하는 데 약간의 기초로 사용되기를 바랍니다.
이 기사에 사용 된 스타일을 포크하고 자신의 동등한 작품을 만들고 싶다면 언제든지 그렇게하십시오! �
Vue ToDo : https://github.com/sunil-sandhu/vue-todo-2020
할 일 : https://github.com/sunil-sandhu/react-todo-2020
이 기사를 다른 언어로 번역하려면 위의 번역 목록에 추가 할 수 있도록 완료 시점을 알려주십시오.