由于上下文中未使用的属性,组件重新渲染
Posted
技术标签:
【中文标题】由于上下文中未使用的属性,组件重新渲染【英文标题】:Component re-renders because of unused property in context 【发布时间】:2019-10-29 08:50:55 【问题描述】:我有一个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
的孩子。
第二次尝试是直接在JSX上使用useMemo
:
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>
), [])
它也有效,它更简洁,但我不确定这是否是一个好习惯。
我的两种方法是否正确?如果没有,你有什么建议?
【问题讨论】:
【参考方案1】:我想我找到了最好的方法,这要感谢https://kentcdodds.com/blog/how-to-use-react-context-effectively: 在两个上下文中分离上下文。一份给国家,一份给调度:
type StateContext = boolean
type DispatchContext =
start: () => void
stop: (message?: string | void) => void
export const AsyncStateContext = createContext(false)
export const AsyncDispatchContext = createContext(start: noop, stop: noop)
如果消费者不需要状态,我只需添加const start, stop = useContext(AsyncDispatchContext)
并且我没有重新渲染。
【讨论】:
以上是关于由于上下文中未使用的属性,组件重新渲染的主要内容,如果未能解决你的问题,请参考以下文章