前言
vue 中有 computed 计算属性这个概念,是非常好用的,不仅避免了人为 set 还具有及时响应的特点。
有了计算属性这个功能,可以很方便的对 props 进行一些中间处理,最后展示结果到视图上(或使用至需要的地方)。
在 react 中主要有三种使用 “计算属性” 的方法。
Class Component
对于类组件,直接使用 get
方法即可达成计算属性:
class ClassComponent extends Component {
// 对于 props 的一些处理
get computed() {
return this.props.value
}
// 支持计算属性相互依赖
// 在 vue 中,由于不支持 data 相互依赖,但支持 computed 相互依赖,这也是 vue 中非常好用的一点!
get computed2() {
return this.computed + '2'
}
render() {
return (
<div>{this.computed}, {this.computed2}</div>
)
}
}
function App() {
const [state, setState] = useState('old')
useEffect(() => {
// 模拟一些异步处理,变化传入的 props
setTimeout(() => {
setState('new')
}, 4000)
}, [])
return (
<ClassComponent value={state}></ClassComponent>
)
}
通过 class 的 get
方法,即可完成即时变化的计算属性,同时支持计算属性相互依赖。
Function Component
在函数组件中,一般使用 useMemo
进行计算属性的计算(当依赖列表变化时重新计算):
// 对 props 的处理函数
const handler = (v) => v
function FC({ value }) {
// 通过依赖列表变化 useMemo 重新计算结果达到计算属性实时更新
const computed = useMemo(() => handler(value), [value])
return (
<div>{computed}</div>
)
}
function App() {
const [state, setState] = useState('old')
useEffect(() => {
// 模拟一些异步处理,变化传入的 props
setTimeout(() => {
setState('new')
}, 4000)
}, [])
return (
<FC value={state}></FC>
)
}
Function Component Async
当处理 props 的方法为异步时,useMemo
将不再适用,需要借用 useEffect
内部支持执行 async 函数的特性转化一步:
// 模拟异步处理 props 的逻辑
const asyncHandler = (v) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`已处理 ${v}`)
}, 2000)
})
}
/**
* 处理 async 业务的 hooks 封装
* @param {Function} func 异步逻辑函数
* @param {Array} dep 依赖列表
* @param {Object} initialValue 初始值
*/
function useAsyncComputed(func, dep, initialValue) {
const [val, setVal] = useState(initialValue)
// 借用 useEffect 执行异步逻辑
useEffect(() => {
let cancel = false
const handler = async () => {
const res = await func()
if(!cancel) {
setVal(res)
}
}
handler()
// 卸载时标记 cancel 已退出,在进程中的异步逻辑将不会再改变 val 值
return () => {
cancel = true
}
}, dep)
return val
}
function AsyncFC({ value }) {
const computed = useAsyncComputed(() => asyncHandler(value), [value], value)
return (
<div>{computed}</div>
)
}
function App() {
const [state, setState] = useState('old')
useEffect(() => {
// 模拟一些异步处理,变化传入的 props
setTimeout(() => {
setState('new')
}, 4000)
}, [])
return (
<AsyncFC value={state}></AsyncFC>
)
}
在上文中我们封装了 useAsyncComputed
自定义 hooks 来处理含异步业务的计算属性,所以执行流程是:
-
初始显示传入的
value
值为old
-
过 2 s 后,异步业务
asyncHandler
执行完毕,计算属性展示为已处理 old
-
再过 2 s 后,传入的 props 改变为
new
,触发异步业务useAsyncComputed
,此时展示值仍为上一步的已处理 old
-
再过 2 s 后,异步处理完毕,展示值为
已处理 new
实际处理中,可以增加 loading 效果,改进用户体验。
总结
以上方法是快速的在一个组件内达到计算属性效果,当然不限于此,还可以考虑全局状态管理 react-redux + redux-saga 来处理异步业务完成即时更新的效果。