halo,你们好,我是 132,今天闲着没事,对 suspense 和 context 进行了封装react
由于我一直对尺寸有超高的强迫症,因此 fre core 只提供最最最核心的机制git
好比,我提供 promise 的内部捕获,但不提供 Suspense 组件的封装github
好比我提供 state ,但不提供 contextjson
可是不少人会质疑,基于现有的 API 和 机制,到底能不能本身封装出来api
答案是,of course!promise
不信,我封装给你看——bash
suspense 的本质就是在外部 throw promise,而后由 fre 内部捕获到,而后打断调和,等 resolve 后,在继续调和闭包
react 目前的 suspense 还不支持数据请求,只支持异步组件框架
既然 react 不支持,那我就封装一个异步
export function createSuspense(promise) {
let pending = true
let result
let currentState = null
return state => {
if (currentState !== state) {
pending = true
currentState = state
}
if (pending) {
throw promise(state).then(res => {
pending = false
result = res
})
} else {
return result
}
}
}
复制代码
如上,createSuspense 接收 promise 函数,它返回一个闭包,这个函数负责把 promise throw 出去
它这么用:
function fetchUsers (pageSize) {
console.log('fetch users from clicli...')
return fetch(`https://api.clicli.us/users?level=4&page=1&pageSize=${pageSize}`)
.then(res => res.json())
.then(data => {
return data.users
})
}
const useUser = createSuspense(fetchUsers)
复制代码
咱们将返回的函数做为 hook,能够随意用到任何组件
function App () {
const [pageSize, setPageSize] = useState(1)
const users = useUser(pageSize)
return (
<main>
<h1>Fetching clicli users</h1>
<button onClick={() => setPageSize(pageSize + 1)}>Click {pageSize}</button>
{users.map(user => (
<img src={`https://q1.qlogo.cn/g?b=qq&nk=${user.qq}&s=640`} />
))}
</main>
)
}
复制代码
这样一来,就能够愉快的使用 suspense 进行数据请求了
目前 react 尚未肯定相似的 API,目前的 Suspense 组件是用来控制 lazy 组件的
这类组件的 API,好处是嵌套,坏处就是复用
因此综上所述,我提了这个 rfc:github.com/reactjs/rfc…
若是反响好的话,我就尝试提 pr 试试::>_<::
可是无论怎么说,这个实现是没问题的,至少是 fre ,我能给出的最合适的实现了
结合上面的 Suspense API,咱们发现了一个 hooks 封装的经常使用套路:返回闭包
使用一样的套路,咱们能够 20 行封装出 Context API
export function createContext(defaultValue) {
const listeners = new Set()
let backupValue = defaultValue
return () => {
const [value, setValue] = useState(backupValue)
useEffect(() => {
backupValue = value
listeners.forEach(f => f !== setValue && f(value))
}, [value])
useEffect(() => {
listeners.add(setValue)
return () => {
listeners.delete(setValue)
}
}, [])
return [value, setValue]
}
}
复制代码
用法是相似的:
const useTheme = createContext('light')
function App() {
const [theme, setTheme] = useTheme()
return (
<div> {theme} <A /> <button onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}> change </button> </div>
)
}
function A() {
const [theme] = useTheme()
return <div>{theme}</div>
}
复制代码
如上,hooks 就是这么灵活,咱们能够肆意封装,这些封装未必须要框架内置,用户彻底能够本身搞定
以上的两个封装的例子都在 fre 仓库里
你们有兴趣能够跑用例,或者去 react rfcs 中一块儿讨论哈!