# C_T7.1 code review
## Code review by 阿傑
### function 不 pure 的問題
原本寫的
```javascript
// taskStore.js
async function postTask(task) {
// 關掉add task表單
const globalState = useGlobalStateStore()
globalState.isAddingTask = !globalState.isAddingTask
const payload = {
records: [
{
fields: task,
},
],
}
await airtable.POST('/tblBEw21vjxZX7CxR', payload)
fetchTasks()
}
```
改把邏輯放在頁面檔案裡面
```javascript
// MyTask.vue
function postTasks(tasks) {
globalState.isAddingTask = !globalState.isAddingTask
taskStore.postTask(tasks)
}
```
另一個
原本寫的
```javascript
async function fetchTasks() {
const fetchedData = await airtable.GET('/tblBEw21vjxZX7CxR')
originalTasks.value = fetchedData.records
tasks.value = formattedTasks.value
sortTasks()
}
// 裡面還有賦值,嚴重的副作用
// sort還會動到formattedTasks
function sortTasks(tasks) {
tasks.value = formattedTasks.value.sort((taskA, taskB) => taskB.starred - taskA.starred)
tasks.value = formattedTasks.value.sort((taskA, taskB) => taskA.completed - taskB.completed)
}
```
改成
```javascript
async function fetchTasks() {
const fetchedData = await airtable.GET('/tblBEw21vjxZX7CxR')
originalTasks.value = fetchedData.records
tasks.value = sortTasks(formattedTasks.value)
}
function sortTasks(tasks) {
return [...tasks]
.sort((taskA, taskB) => taskB.starred - taskA.starred)
.sort((taskA, taskB) => taskA.completed - taskB.completed)
}
```
### 過多的判斷邏輯
原本寫的
```html
<component
v-if="props.status === 'in-progress'"
v-for="task in taskStore.inProgressTasks"
// 這行的邏輯
:is="task.editing ? TaskForm : TaskAbstract"
:key="task.id"
:task="task"
@submit="taskStore.updateTask($event)"
@change:status="taskStore.updateTask($event)"
/>
```
改成把 TaskForm 和 TaskAbstract 再包成一個 component
```html
<TaskItem
v-if="props.status === 'my-task'"
v-for="task in taskStore.tasks"
:task="task"
:isEditing="task.editing"
:key="task.id"
@submit="taskStore.updateTask($event)"
@change:status="taskStore.updateTask($event)"
/>
```
這樣還可以把 TaskForm 和 TaskAbstract 拆開寫
```html
// TaskItem.vue
<template>
<TaskForm v-if="isEditing" :task="props.task" @submit="emits('submit', $event)"></TaskForm>
<TaskAbstract
v-else
:task="props.task"
@change:status="emits('change:status', $event)"
></TaskAbstract>
</template>
```
### vite.config.js 引入 scss 檔案
可以新增一個`index.scss`用`@forward`方式引入所有abstracts

在`vite.config.js`直接`@use`這個資料夾,並拿掉namespace

元件內就可以直接使用變數了
```css
.input {
background-color: $primary_white;
border: 2px solid $primary_gray;
border-radius: 5px;
}
```
### 邏輯再再再簡化
原本依照status來判斷要渲染哪一個元件
```html
// 當status等於all
<TaskItem
v-if="props.status === 'all'"
v-for="task in taskStore.tasks"
:task="element"
@submit="taskStore.updateTask($event)"
@change:status="taskStore.updateTask($event)"
/>
// 當status等於in-progress
<TaskItem
v-if="props.status === 'in-progress'"
v-for="task in taskStore.inProgressTasks"
:task="element"
@submit="taskStore.updateTask($event)"
@change:status="taskStore.updateTask($event)"
/>
// 當status等於completed
<TaskItem
v-if="props.status === 'completed'"
v-for="task in taskStore.completedTasks"
:task="element"
@submit="taskStore.updateTask($event)"
@change:status="taskStore.updateTask($event)"
/>
```
改成直接在v-for中渲染相對應的Array
```html
<TaskItem
v-for="task in taskItems"
:task="element"
@submit="taskStore.updateTask($event)"
@change:status="taskStore.updateTask($event)"
/>
```
```javascript
// <script setup>
// early return的話盡量不使用else if的寫法
const taskItems = computed(() => {
if (props.status === 'in-progress') {
return taskStore.inProgressTasks
}
if (props.status === 'completed') {
return taskStore.completedTasks
}
})
// 甚至可以改成多層的三元運算子
const taskItems = computed(() =>
props.status === 'in-progress'
? taskStore.inProgressTasks
: props.status === 'completed'
? taskStore.completedTasks
: taskStore.tasks
)
```
### defineModel
超難懂QQ 可以不用一開始就寫出來,但如果同事這樣寫,至少要看得懂
原本傳入了task,然後emits兩個events: `submit`和`change:status`
```html
// MyTaskView.vue
<TaskItem
v-for="task in taskStore.tasks"
:task="task"
@submit="taskStore.updateTask($event)"
@change:status="taskStore.updateTask($event)"
/>
```
```html
// TaskItem.vue
<script setup>
const props = defineProps({
task: {
type: Object,
required: true,
},
})
const emits = defineEmits(['submit', 'change:status'])
</script>
<template>
<TaskForm
:task="props.task"
@submit="emits('submit', $event)"
@change:status="emits('change:status', $event)"
></TaskForm>
</template>
```
改成用defineModel的方式,把`task`作為一個像是v-model的modelValue來傳遞和更新
```html
// MyTaskView.vue
// 使用task這個名稱傳入內容
// 使用update:前綴加上task名稱作為event名字
<TaskItem
v-for="task in taskStore.tasks"
:task="task"
@update:task="taskStore.updateTask($event)"
/>
```
可以把`task`直接當成ref的感覺來取用或賦值
```html
// TaskItem.vue
<script setup>
// 不用再傳props和emits
// 定義名稱為task
const task = defineModel('task')
</script>
<template>
<div>
<TaskForm
v-if="task.editing"
:task="task"
@submit="task = $event"
@change:status="task = $event"
></TaskForm>
</div>
</template>
```
### Lazy Loading Routes
阿傑說都會用動態引入頁面檔
```javascript
routes: [
{
path: '/',
name: 'my-task',
component: () => import('../views/MyTask.vue'), // 動態引入
props: (route) => ({ status: route.query.status || 'all' }),
},
],
```