리액트와 뷰에서 똑같은 앱을 만들었습니다. 여기 차이점이 있습니다. [2019년판]입니다 (I created the exact same app in React and Vue. Here are the differences. [2019 Edition])

이 글은 Sunil SandhuI created the exact same app in React and Vue. Here are the differences. [2019 Edition]글을 번역했습니다. 저의 모든 글은 허가를 받고 진행 하였습니다

React vs vue입니다. 마지막으로, Vue와 React의 나란히 코드 비교! [2019년 업데이트 및 다시 작성: 이제 React Hooks로]

회사에서 Vue를 사용했기 때문에, 저는 그것을 꽤 확실하게 이해했습니다. 하지만 저는 울타리 반대편에 있는 풀들이 어떤 것인지 궁금했습니다. - 이 시나리오의 풀들은 React입니다.
React 문서를 읽고 튜토리얼 비디오를 몇 개 보았는데, 모든 것이 훌륭했지만, 제가 정말로 알고 싶은 것은 React와 Vue가 얼마나 다른지였습니다. "다르다"는 것은 둘 다 가상 DOMS를 가지고 있는지, 페이지를 렌더링하는 방법을 말하는 것이 아닙니다. 누군가 시간을 내서 코드를 설명해 주기를 바랬어요! 저는 이것을 설명하는 글을 찾고 싶었습니다. 그래서 Vue나 React(또는 웹 개발 전체)를 처음 접하는 사람이 둘 사이의 차이점을 더 잘 이해할 수 있도록 말이죠.
불행하게도, 저는 이 문제를 해결할 수 있는 어떤 것도 찾을 수 없었어요. 그래서 저는 그 유사성과 차이점을 보기 위해 제가 직접 이것을 만들어야 한다는 것을 깨달았습니다. 그렇게 하면서 이 부분에 대한 글이 최종적으로 존재하게끔 모든 과정을 문서화해야겠다고 생각했습니다.
presentation
누가 더 잘 입었어요?
사용자가 목록에서 항목을 추가하고 삭제할 수 있는 상당히 표준화된 작업관리 앱을 구축해 보기로 했습니다. 두 앱은 모두 기본 CLI(반응을 위한 Create-React-app, Vue의 경우 vue-cli)를 사용하여 구축되었습니다. CLI는 Command Line Interface의 약자입니다. 🤓

어쨌든, 이 소개는 제가 예상했던 것보다 이미 더 길어요. 먼저 두 앱의 모양을 간단히 살펴보겠습니다.

presentation
React vs vue입니다. 이 움직일 수 없는 물체가 저항할 수 없는 힘을 만나게 됩니다!
두 앱의 CSS 코드는 정확히 동일하지만 위치에는 차이가 있습니다. 그런 점을 염두에 두고, 이제 두 앱의 파일 구조를 살펴보겠습니다.
presentation
그들의 구조도 거의 동일하다는 것을 알 수 있을 것입니다. 여기서 유일한 차이점은 React 앱에 세 개의 CSS 파일이 있지만 Vue 앱에는 CSS 파일이 없다는 것입니다. 그 이유는 Create-React-app에서 React 구성 요소에는 스타일을 유지할 수 있는 파일이 포함된 반면, Vue CLI는 스타일이 실제 구성 요소 파일 내에 선언되는 포괄적인 접근 방식을 채택하기 때문입니다.
궁극적으로는 둘 다 동일한 목표를 달성하며, React 또는 Vue에서 CSS를 다르게 구성할 수 없다고 말할 수 없습니다. 그것은 정말 개인적인 선호로 귀결됩니다. 스타일 구성 요소 및 감성과 같은 많은 CSS-in-JS 솔루션이 있기 때문에 특히 React와 관련하여 개발자 커뮤니티에서 CSS를 어떻게 구성해야 하는지에 대한 많은 논의를 듣게 될 것입니다. 그나저나 CSS-in-JS는 말 그대로 그런 소리입니다. 이러한 기능이 유용하기는 하지만 현재로서는 두 CLI에 모두 포함된 구조를 따르도록 하겠습니다.
하지만 더 나아가기 전에 일반적인 Vue 및 React 구성 요소의 모양을 간단히 살펴보겠습니다.
presentation
좌측 React | 오른쪽은 Vue입니다.
이제 그건 불가능해요, 그 빌어먹을 세부사항으로 들어가죠!

데이터를 어떻게 변형합니까?

하지만 먼저, "데이터를 수정한다"는 것은 무엇을 의미할까요? 좀 기술적인 것 같지 않아요? 이것은 기본적으로 우리가 저장한 데이터를 바꾸는 것을 의미합니다. 그래서 만약 우리가 사람의 이름의 가치를 존에서 마크로 바꾸고자 한다면, 우리는 '데이터를 수정하는 것'이 될 것입니다. 이것이 리액트(React)와 뷰(Vue)의 중요한 차이점입니다. Vue는 기본적으로 데이터를 자유롭게 업데이트할 수 있는 데이터 개체를 생성하지만, React는 이를 상태 후크(state hook)라고 하는 방식으로 처리합니다.
아래 이미지에서 두 가지 모두에 대한 설정을 살펴본 다음, 이후 상황에 대해 설명하겠습니다.
presentation
1.React
presentation
2.Vue
그래서 같은 자료를 두 가지 모두에 전달했지만 구조가 좀 다르다는 것을 알 수 있습니다.
Vue에서는 일반적으로 data() 함수의 내부에 있는 데이터를 반환하는 구성 요소의 모든 가변성 데이터를 모두 배치합니다(2.Vue 이미지에서 볼 수 있듯이).
리액트(React)을 사용하면, 또는 적어도 2019년 이후에는 일반적으로 일련의 후크(Hooks)를 통해 상태를 처리합니다. 이런 컨셉을 본 적이 없다면 처음에는 좀 이상하게 보일 수도 있습니다. 기본적으로 다음과 같이 작동합니다.
우리가 todos 목록을 만들고 싶다고 가정해보죠. list라는 변수를 생성해야 할 수 있으며, 각 문자열 또는 객체의 배열이 필요할 수 있습니다(각 todo문자열마다 ID를 부여하고 다른 작업을 수행하려면). 이 설정은 const [list, setList] = useState([])를 작성하여 설정합니다. 여기서는 리액트가 후크(Hook)라고 부르는 useState를 사용하고 있습니다. 이를 통해 구성 요소 내에서 로컬 상태를 유지할 수 있습니다.
또한 UseState()의 내부에 빈 array []를 전달했습니다. 우리가 그 안에 넣은 것은 우리가 처음에 원하는 list입니다. 우리의 경우, 우리는 빈 array을 원합니다. 하지만 위의 이미지를 보면 array 내부의 일부 데이터를 전달했으며, 이 데이터는 list의 초기화된 데이터로 남게 됩니다. setList가 어떤 역할을 하는지 궁금합니다. 이따가 더 있을 거예요.

그렇다면 앱에서 가변성 데이터를 어떻게 참조할 수 있을까요?

자, ‘Sunil이라는 가치를 부여받은 name이라는 자료가 있다고 가정해 보겠습니다.
Vue의 경우, 이것은 data() 개체 안에 있으며 name: ‘Sunil'이라고 불렸을 것입니다. 저희 앱에서는 this.name으로 불리는 calling을 참조하겠습니다. this.name = ‘John’으로 불리는 것을 업데이트할 수도 있습니다. 이렇게 하면 내 이름이 John으로 바뀔 거예요. John이라고 불리는 것에 대해 제가 어떻게 생각하는지 잘 모르겠지만, 이봐요, 무슨 일이 있어요! 😅
React에서는 useState()를 사용하여 만든 작은 상태 조각이 있으므로, const [name, setName] = useState('Sunil')의 행을 따라 무언가를 생성했을 가능성이 높습니다. 당사의 앱에서는 단순히 name을 calling하는 것으로 동일한 데이터를 참조합니다. 여기서 중요한 차이점은 우리가 단순히 name = ‘John’을 쓸 수 없다는 것입니다. 왜냐하면 리액트에는 이런 종류의 쉽고 걱정없는 가변성을 막기 위한 제한이 있기 때문입니다. 그래서 리액트에서는 setName('John')을 씁니다.. 여기서 setName 비트가 재생됩니다. 기본적으로 const [name, setName] = useState('Sunil')에서 두 개의 변수를 생성합니다. 이 변수 중 하나는 const name = 'Sunil'이 되며, 두 번째 const setNamename을 새 값으로 재생성할 수 있는 기능을 할당했습니다.
효과적으로 React하고 Vue도 여기서 동일한 작업을 수행하며 업데이트할 수 있는 데이터를 생성합니다. Vue는 기본적으로 데이터 조각이 업데이트될 때마다 기본적으로 고유한 name 버전과 setName을 결합합니다. 즉, React에서 상태를 업데이트하려면 값이 내장된 setName()을(를) 호출해야 합니다. Vue는 데이터 개체 내에서 값을 업데이트하려는 경우 이 작업을 수행하려고 한다고 가정합니다. 그렇다면 React는 왜 기능과 값을 구분하는 데까지 신경을 쓰며, useState()가 필요한 이유는 무엇일까요? 설명을 위해 이것을 Revanth Kumar에게 넘기겠습니다.
"리액트는 상태가 바뀔 때마다 특정 라이프 사이클 후크를 재실행하고 싶어하기 때문입니다. useState 함수를 호출하면 상태가 변경되었음을 알 수 있습니다. 직접 상태를 변경한 경우 응답은 변경 사항 및 실행할 라이프사이클 후크 등을 추적하기 위해 더 많은 작업을 수행해야 합니다. 그래서 간단하게 리액트(React)에서 useState를 사용합니다."
presentation
Bean은 가장 잘 알고 있었어요.
두 가지 우리 To Do Apps에 새로운 아이템을 추가하는 방법을 살펴봄으로써 아주 진부하고 진부하게 변했습니다.

새 To Do Items을 작성하려면 어떻게 해야 합니까?

React:
const createNewToDoItem = () => { const newId = Math.max.apply(null, list.map((t) => t.id)) + 1 const newToDo = { id: newId, text: toDo }; setList([...list, newToDo]); setToDo(""); };

리액트는 어떻게 그런 일을 했을까요?

React에서, 우리의 입력 필드는 value라고 불리는 속성을 가지고 있습니다. 이 값은 onChange event listener 기능을 통해 값이 변경될 때마다 자동으로 업데이트됩니다. JSX(기본적으로 HTML의 변형)는 다음과 같습니다.
<input type="text" value={toDo} onChange={handleInput}/>
따라서 값이 변경될 때마다 상태가 업데이트됩니다. handleInput 기능은 다음과 같습니다.
const handleInput = (e) => { setToDo(e.target.value); };
이제 사용자가 페이지의 + 버튼을 눌러 새 항목을 추가할 때마다 createNewToDoItem 기능이 트리거됩니다. 이 기능을 다시 한 번 살펴보면서 현재 진행 중인 상황을 분석해 보겠습니다.
const createNewToDoItem = () => { const newId = Math.max.apply(null, list.map((t) => t.id)) + 1 const newToDo = { id: newId, text: toDo }; setList([...list, newToDo]); setToDo(""); };
기본적으로 newId 기능은 기본적으로 newtoDo 항목에 부여할 새 ID를 만드는 것입니다. newtoDo 변수는 newId의 값이 지정된 id 키를 사용하는 개체입니다. 또한 text 키도 있어 toDo에서 toDo까지의 값을 값으로 가져옵니다. 이는 입력 값이 변경될 때마다 업데이트되는 toDo와 동일합니다.
그런 다음 setList 기능을 실행하고 전체 list과 새로 생성된 newToDo가 포함된 어레이를 전달합니다.
만약 ...list, 비트(bit)가 이상해 보인다면, 처음의 세 개의 점은 스프레드 연산자로 알려진 것입니다. 이 연산자는 단순히 전체 항목을 배열로 전달하는 것이 아니라 list의 모든 값을 별도의 항목으로 전달합니다. 혼란스럽습니까? 만약 그렇다면, 저는 그것이 훌륭하기 때문에 널리 읽기를 강력히 추천합니다!
어쨌든 드디어 setToDo()를 실행하고 빈 문자열로 전달합니다. 입력 값이 비어 새 totDos를 입력할 준비가 되었습니다.

Vue:

createNewToDoItem() { const newId = Math.max.apply(null, this.list.map(t => t.id)) + 1;
this.list.push({ id: newId, text: this.todo }); this.todo = ""; }

Vue는 어떻게 그런 일을 했을까요?

Vue의 입력 필드(input)에는 v-model이라는 핸들이 있습니다. 이것은 우리가 two-way binding이라고 알려진 것을 할 수 있게 해줍니다. 입력 필드를 빠르게 살펴본 다음 진행 상황을 설명하겠습니다.
<input type="text" v-model="todo"/>
V-Model은 이 필드의 입력을 DoItem이라는 데이터 개체에 있는 키에 연결합니다. 페이지가 로드되면 DoItem이 빈 문자열로 설정되어야 합니다(예:todo: ‘’). 여기에 'todo: ‘add some text here’'와 같은 일부 데이터가 이미 있는 경우 입력 필드는 입력 필드 내에 이미 있는 추가 텍스트와 함께 로드됩니다. 어쨌든 빈 문자열로 돌아가면 입력 필드에 입력하는 텍스트가 todo 값에 바인딩됩니다. 이는 사실상 양방향 바인딩입니다(입력 필드는 데이터 개체를 업데이트하고 데이터 개체는 입력 필드를 업데이트할 수 있음).
앞에서 createNewToDoItem() 코드 블록을 다시 살펴보면, todo 내용을 list 배열로 밀어 넣은 다음 todo 내용을 빈 문자열로 업데이트하는 것을 볼 수 있습니다.
또한 React 예제와 동일한 newId() 함수를 사용했습니다.

목록에서 어떻게 삭제합니까?

React:

const deleteItem = (item) => { setList(list.filter((todo) => todo !== item)); };

리액트는 어떻게 그런 일을 했을까요?

따라서 deleteItem() 함수가 ToDo.js 내부에 위치하는 동안, 먼저 다음과 같이deleteItem()함수를 <ToDoItem/>의 소품으로 전달하여 ToDoItem.js 내에서 매우 쉽게 참조할 수 있었습니다.
<ToDoItem deleteItem={deleteItem}/>
이렇게 하면 먼저 기능이 아래로 전달되어 자식(child)가 액세스할 수 있게 됩니다. 그런 다음 ToDoItem 구성 요소 내에서 다음을 수행합니다.
<button className="ToDoItem-Delete" onClick={() => deleteItem(item)}> - </button>
부모(parent) 구성 요소 안에있는 함수를 참조하기 위해해야 할 일은 props.deleteItem을 참조하는 것입니다. 이제 코드 예제에서 props.deleteItem 대신 deleteItem을 작성했음을 알 수 있습니다. 이는 props 객체의 일부를 가져 와서 변수에 할당 할 수있는 구조화(destructuring)라고하는 기술을 사용했기 때문입니다. ToDoItem.js 파일에는 다음이 있습니다.
const ToDoItem = (props) => { const { item, deleteItem } = props; }
이는 props.item과 동일한 값이 할당 된 item이라는 변수와 props.deleteItem에서 값이 할당 된 deleteItem이라는 두 가지 변수를 생성했습니다. props.itemprops.deleteItem을 사용하여이 모든 파괴적인 것을 피할 수 있었지만 언급 할 가치가 있다고 생각했습니다!

Vue:

onDeleteItem(item){ this.list = this.list.filter(todo => todo !== item); }Vue는 어떻게 그런 일을 했을까요?

Vue는 어떻게 그런 일을 했을까요?

Vue에는 약간 다른 접근 방식이 필요합니다. 기본적으로 다음 세 가지 작업을 수행해야 합니다.
먼저, 구성 요소에서 함수를 다음과 같이 부릅니다.
<div class=”ToDoItem-Delete” @click=”deleteItem(item)”>-</div>
그런 다음 자식 구성 요소 (이 경우 ToDoItem.vue) 내에 메서드로 emit 함수를 만들어야합니다.
deleteItem(item) { this.$emit('delete', item) }
그런 다음 하위 구성 요소(이 경우 ToDoItem.vue) 내부에 방출 기능(function)을 만들어야 합니다.ToDo.vue)는 다음과 같습니다.
<ToDoItem v-for="todo in list" :todo="todo" @delete="onDeleteItem" // <-- this :) :key="todo.id" />
이것이 바로 사용자 정의 이벤트 리스너(event-listener)입니다. 'delete'문자열로 emit가 트리거되는 경우를 수신합니다. 이것이 들리면 onDeleteItem이라는 함수를 트리거합니다. 이 함수는 ToDoItem.vue가 아닌 ToDo.vue 내부에 있습니다. 앞에서 설명한 것처럼이 함수는 단순히 클릭 한 항목을 제거하기 위해 data object 내부의 todo array을 필터링합니다.
또한 Vue 예제에서는 다음과 같이 간단히 $emit 부분을 @click Listener 내부에 쓸 수 있었습니다.
<div class=”ToDoItem-Delete” @click=”$emit(‘delete’, item)”>-</div>
이렇게 하면 3단계에서 2단계로 내려간 횟수가 줄어들 수 있으며, 이는 단순히 개인적인 선호로 내려간 것입니다.
요컨대, React의 하위 구성 요소는 props을 통해 부모 기능에 액세스 할 수 있습니다 (props을 아래로 전달하면 상당히 표준적인 관행이며 다른 React 예제 에서이 많은 시간을 보게됩니다) .Vue에서는 일반적으로 부모 구성 요소 내에서 수집되는 자식에서 이벤트를 생성합니다.

이벤트 리스너(event listeners)를 어떻게 전달합니까?

React:

클릭 이벤트와 같은 간단한 작업을 위한 Event listeners는 바로 앞으로 이동됩니다. 다음은 새 ToDo item을 생성하는 버튼에 대한 클릭 이벤트를 생성하는 방법의 예입니다.
<button className=”ToDo-Add” onClick={createNewToDoItem}>+</div>.
여기에서 매우 쉬우 며 vanilla JS로 인라인 onClick을 처리하는 방법과 거의 같습니다. Vue 섹션에서 언급했듯이 enter 버튼을 누를 때마다 처리 할 event listener를 설정하는 데 시간이 조금 더 걸렸습니다. 이를 위해서는 입력 태그가 onKeyPress 이벤트를 처리해야합니다.
<input type=”text” onKeyPress={handleKeyPress}/>.
이 기능은 기본적으로 createNewToDoItem 기능을 트리거했습니다. 'enter' 키가 눌린 것을 인식할 때마다 다음과 같이 작동합니다.
handleKeyPress = (e) => { if (e.key === ‘Enter’) { createNewToDoItem(); } };

Vue:

Vue에서는 매우 직관적입니다. 우리는 단순히 @ symbol을 사용하고, 그 다음에 우리가 원하는 event-listener의 유형을 사용합니다. 예를 들어 클릭 event-listener를 추가하려면 다음을 쓸 수 있습니다.
<button class=”ToDo-Add” @click=”createNewToDoItem()”>+</div>
참고: @click은 실제로 v-on:click을 쓰는 단축어입니다. Vue event listeners의 멋진 점은 event listeners가 두 번 이상 트리거되는 것을 방지하는 .once와 같이 다양한 기능을 사용할 수 있다는 것입니다. 또한 키 스트로크를 처리하기 위한 특정 event listeners를 작성할 때 여러 가지 바로 가기가 있습니다. 입력 버튼을 누를 때마다 새 작업관리 항목을 만들기 위해 응답에서 event listeners를 만드는 데 시간이 꽤 오래 걸렸습니다. Vue에서는 다음과 같이 간단히 쓸 수 있었습니다.
<input type=”text” v-on:keyup.enter=”createNewToDoItem”/>

데이터를 하위 구성 요소로 어떻게 전달합니까?

React:

이에 대응하여, 우리는 props을 만들어지는 지점에서 자식 구성요소에 전달합니다. 다음과 같습니다.
<ToDoItem key={key.id} item={todo} />
여기 두 개의 props이 ToDoItem 구성 요소로 전달되는 것을 볼 수 있습니다. 이제 this.props을 통해 하위 구성 요소의 item.todo prop을 참조할 수 있습니다. 그래서 그 아이템에 접근하기 위해서요.그냥 props.item이라고 부르죠

Vue:

Vue에서는 소품을 제작 지점의 자식 구성요소에 전달합니다. 다음과 같습니다.
<ToDoItem v-for="item in list" :item="item" @delete="onDeleteItem" :key="item.id" />
일단 이 작업이 끝나면, 우리는 그것들을 자식 구성요소에 있는 props 배열로 전달합니다. props: [ ‘todo’ ] 그런 다음 자식에서 이름으로 참조할 수 있습니다. 따라서 우리의 경우 ‘todo’입니다.

상위 구성 요소로 데이터를 다시 내보내는 방법은 무엇입니까?

React:

먼저 하위 구성 요소를 호출하는 위치에서 소품으로 참조하여 하위 구성 요소에 함수를 전달합니다. 그런 다음 props.whateverTheFunctionIsCalled를 참조하거나 onDestructing을 사용하는 경우 whateverFunctionIsCalled를 참조하여 onClick과 같은 모든 방법으로 자식에 대한 함수 호출을 추가합니다. 그러면 상위 컴포넌트에있는 기능이 트리거됩니다. ‘목록에서 삭제하는 방법’섹션에서이 전체 프로세스의 예를 볼 수 있습니다.

Vue:

자식 구성 요소에서는 값을 상위 기능으로 다시 보내는 기능을 작성하기만 하면 됩니다. 상위 구성 요소에서는 해당 값이 방출될 때 이를 수신하는 기능을 작성하여 함수 호출을 트리거할 수 있습니다. '목록에서 삭제하는 방법' 섹션에서 이 전체 프로세스의 예를 볼 수 있습니다.

그리고 여기 있습니다! 🎉

데이터를 추가, 삭제, 변경하고, 부모로부터 자식에게 props 형태로 데이터를 전달하고, event listeners 형태로 자식으로부터 부모에게 데이터를 보내는 방식을 살펴봤습니다. 물론 리액트(React)와 Vue(Vue) 사이에는 많은 차이점과 기발한 점이 있지만, 이 글의 내용이 두 프레임워크가 어떻게 물질을 다루는지를 이해하는 데 도움이 되었으면 합니다.
만약 여러분이 이 글에 사용된 스타일을 찾는데 관심이 있고, 여러분 자신만의 동등한 작품을 만들고 싶다면, 그렇게 하는 것을 주저하지 마세요! 👍

Gitub은 두 앱에 모두 연결됩니다.

Vue ToDo: https://github.com/sunil-sandhu/vue-todo-2019
React ToDo: https://github.com/sunil-sandhu/react-todo-2019

이 글의 2018년 버전입니다.

https://medium.com/javascript-in-plain-english/i-created-the-exact-same-app-in-react-and-vue-here-are-the-differences-e9a1ae8077fd

이 글은 번역 글입니다. 원본 링크입니다.


안녕하세요! Early adopter입니다.
페이스북 [DTF] 디자인 번역 공장 - Design Translation Factory 그룹도 많이 가입해주시길 바랍니다.
"보버"에서 "디자인 번역 공장" 연재를 저와 함께 해주실 분을 찾습니다. 하단 "리뷰" 또는 "페이스북"으로 편하게 메시지 주세요!
PS. 제가 사용하는 블로그 "보버"에 "함께 쓰는 블로그"라는 기능이 요번에 추가됐네요 ㅋ (미디엄에 퍼블리케이션 같은 기능..)
하단 링크 글을 보시면 "디자인 번역 공장"에 어떻게 함께 연재할 수 있는지 자세히 설명되어있습니다. 또는 쉽게 FB 메시지 주세요!
https://bit.ly/2LxR0Bz