最近又在学习 React 的基础,看了一篇文章:www.robinwieruch.de/react-compu…
React
import React from 'react';
import sortBy from 'lodash.sortby';
import { v4 as uuidv4 } from 'uuid';
function App() {
const [name, setName] = React.useState('');
const [list, setList] = React.useState([
{ id: '1', name: 'Apple', count: 5 },
{ id: '2', name: 'Banana', count: 3 },
{ id: '3', name: 'Peach', count: 10 },
]);
const [sort, setSort] = React.useState('name');
function handleSortName() {
setSort('name');
}
function handleSortCount() {
setSort('count');
}
function handleChange(event) {
setName(event.target.value);
}
function handleAdd() {
const newItem = {
id: uuidv4(),
name: name,
count: 0,
};
const newList = list.concat(newItem);
setList(newList);
}
const sortedList = sortBy(list, sort); // C
return (
<div>
<h1>Computed Properties in React</h1>
<div>
<input type="text" value={name} onChange={handleChange} />
<button type="button" onClick={handleAdd}>
Add
</button>
</div>
<button type="button" onClick={handleSortName}>
Sort by Name
</button>
<button type="button" onClick={handleSortCount}>
Sort by Count
</button>
<ul>
{sortedList.map((item) => (
<li key={item.id}>
<span>{item.name}</span>:<span>{item.count}</span>
</li>
))}
</ul>
</div>
);
}
export default App;
React 中并没有 Computed property 这个概念。如 C,sortedList 只是一个变量,不是 state,也没有 computed。对比 computed,react 就是
just deriving values from the raw state.
关键在于:我们让组件每一次更新渲染时,重新计算 sortedList。想象一下,组件每次更新,function component 执行。
关于设置 state,可以参考 React 哲学。第三步,确定 UI state 的最小(且完整)表示。首先我们可以在 onClick 事件中处理修改 list state,这样没有 sort state。但是一旦逻辑更加复杂,比如新增 item,要使得列表仍然保持排序,就必须增加显式的 sort state。
(性能)不过当组件每一次渲染时,都会重新计算 sortedList,这时候就可以使用 useMemo:
const sortedList = React.useMemo(() => {
console.log('Calculates computed properties ...');
return sort.isReverse
? sortBy(list, sort.property).reverse()
: sortBy(list, sort.property);
}, [list, sort]);
Vue
Vue 就使用 computed 的实现:
<template>
<div>
<ul>
<li v-for="item in sortedList" :key="item.id">
{{ item.name }}: {{ item.count }}
</li>
</ul>
<input v-model="name" type="text" />
<button type="button" @click="handleAddItem">Add</button>
<button type="button" @click="handleSortByName">Sort By Name</button>
<button type="button" @click="handleSortByCount">Sort By Count</button>
</div>
</template>
<script>
import {
reactive,
toRefs,
computed
} from 'vue'
import { sortBy } from 'lodash'
export default {
setup: () => {
const state = reactive({
list: [
{ id: '2', name: 'Banana', count: 3 },
{ id: '1', name: 'Apple', count: 5 },
{ id: '3', name: 'Peach', count: 10 }
],
sort: '',
name: '',
})
const handleSortByName = () => {
state.sort = 'name'
}
const handleSortByCount = () => {
state.sort = 'count'
}
const sortedList = computed(() => {
return sortBy(state.list, state.sort)
})
const handleAddItem = () => {
state.list.push({
id: state.list.length + 1,
name: state.name,
count: 0
})
}
return {
...toRefs(state),
sortedList
handleSortByName,
handleSortByCount,
handleAddItem
}
}
};
</script>