У меня есть AsyncContext
, который позволяет мне запускать / останавливать любые асинхронные вычисления.За кулисами он управляет глобальным загрузчиком и снэк-баром.
export type Context = {
loading: boolean
start: () => void
stop: (message?: string) => void
}
const defaultContext: Context = {
loading: false,
start: noop,
stop: noop,
}
export const AsyncContext = createContext(defaultContext)
Здесь потребитель:
const MyChild: FC = () => {
const {start, stop} = useContext(AsyncContext)
async function fetchUser() {
try {
start()
const res = await axios.get('/user')
console.log(res.data)
stop()
} catch (e) {
stop('Error: ' + e.message)
}
}
return (
<button onClick={fetchData}>
Fetch data
</button>
)
}
Как видите, MyChild
не заботится о loading
,Но он включен в контекст, поэтому компонент повторно выполняет рендеринг 2 раза.
Чтобы предотвратить это, моя первая попытка состоит в том, чтобы разделить мой компонент на две части и использовать memo
:
type Props = {
start: AsyncContext['start']
stop: AsyncContext['stop']
}
const MyChild: FC = () => {
const {start, stop} = useContext(AsyncContext)
return <MyChildMemo start={start} stop={stop} />
}
const MyChildMemo: FC<Props> = memo(props => {
const {start, stop} = props
async function fetchUser() {
try {
start()
const res = await axios.get('/user')
console.log(res.data)
stop()
} catch (e) {
stop('Error: ' + e.message)
}
}
return (
<button onClick={fetchData}>
Fetch data
</button>
)
})
Это работает, но я не хочу разделять всех потомков, которые используют AsyncContext
.
Вторая попытка - использовать useMemo
непосредственно на JSX:
const MyChild: FC = () => {
const {start, stop} = useContext(AsyncContext)
async function fetchUser() {
try {
start()
const res = await axios.get('/user')
console.log(res.data)
stop()
} catch (e) {
stop('Error: ' + e.message)
}
}
return useMemo(() => (
<button onClick={fetchData}>
Fetch data
</button>
), [])
}
Это также работает, оно более сжато, но я не уверен, что это хорошая практика.
Является ли какой-либо из моих двух подходов правильным?Если нет, что бы вы посоветовали?