React-Router中useParams与useNavigate导致组件不必要重渲染的原因及性能影响咨询
大家好,我遇到了一个组件重渲染的问题,想请各位帮忙分析下原因:每次点击同一个链接时,我的组件都会出现不必要的重渲染,我怀疑这和使用useParams、useNavigate钩子有关。现在我担心这种情况会影响应用性能,尤其是父组件也跟着重渲染的问题。
父组件代码:
export const Conversation = () => { // const { id } = useParams() as { id: string }; const setChat = useChat((state) => state.actions.setChat); // const navigate = useNavigate(); const { isLoading, isError, isRefetching, refetch, data } = useQuery(({ signal }) => conversationApi.get('67096041d913474deb2ea5bc', signal), { keys: [], retry: 5, retryDelay: 2000, onSelect: ({ messages, ...data }) => data, onSuccess: ({ messages }) => { setChat({ messages, params: { id: '67096041d913474deb2ea5bc', type: SourceRefPath.CONVERSATION, query: { recipientId: '67096041d913474deb2ea5bc', session_id: useSocket.getState().session_id } } }); }, }); if (isLoading) return <ChatSkeleton />; if (isError) { return ( <OutletError title='Something went wrong' description='Cannot load conversation' callToAction={ <Button onClick={refetch} className='mt-5' disabled={isRefetching}> {isRefetching ? <Loader2 className='w-6 h-6 animate-spin' /> : 'try again'} </Button> } /> ); } return ( // <ConversationProvider conversation={data}> <Content /> // </ConversationProvider> ); };
Content组件代码:
export const Content = () => { // const { _id, isInitiatorBlocked, isRecipientBlocked, recipient, isRecipientTyping, handleTypingStatus } = useConversation(useShallow(contentSelector)); const showDetails = useChat((state) => state.showDetails); // const description = getConversationDescription({ data: { recipient, isInitiatorBlocked, isRecipientBlocked }, isRecipientTyping }); console.log('rerender') return ( <OutletContainer> test {/* <div className='flex-1 flex flex-col'> <OutletHeader name={recipient.name} isOfficial={recipient.isOfficial} description={description} dropdownMenu={<ConversationDDM />} /> <MessagesList getPreviousMessages={(id, cursor) => conversationApi.getPreviousMessages(id, cursor)} /> <SendMessage handleTypingStatus={handleTypingStatus()} restrictMessaging={[ { reason: !!(isInitiatorBlocked || isRecipientBlocked), message: isRecipientBlocked ? `You blocked ${recipient.name}` : `${recipient.name} has restricted incoming messages` }, { reason: !_id && recipient.isPrivate, message: `${recipient.name} does not accept new messages` } ]} /> </div> {showDetails && ( <OutletDetails title='User Info' name={recipient.name} avatarUrl={recipient.avatar?.url} description={description} info={[ { data: recipient.status, type: OutletDetailsTypes.BIO }, { data: recipient.login, type: OutletDetailsTypes.LOGIN }, ]} /> )} */} </OutletContainer> ); };
用于导航的NavLink组件代码:
export const ConversationItem = ({ feedItem: { item } }: { feedItem: ExctactLocalFeedItem<FeedTypes.CONVERSATION> }) => { const recipient = item.recipient; const draft = useLayout((state) => state.drafts).get(recipient._id); return ( <li> <NavLink to={`/conversation/${recipient._id}`} className={({ isActive }) => cn( 'flex items-center gap-5 p-2 rounded-lg transition-colors duration-200 ease-in-out', isActive ? 'dark:bg-primary-dark-50 bg-primary-gray/10' : 'dark:hover:bg-primary-dark-50/30 hover:bg-primary-gray/5' ) } > {recipient.avatar ? ( <span className='relative w-[50px] h-[50px]'> <Image src={recipient.avatar.url} skeleton={<AvatarByName name={recipient.name} size='lg' />} className='object-cover object-center min-w-[50px] max-w-[50px] h-[50px] rounded-full' /> {recipient.presence === PRESENCE.ONLINE && <ProfileIndicator />} </span> ) : ( <AvatarByName name={recipient.name} size='lg' isOnline={recipient.presence === PRESENCE.ONLINE} /> )} <div className='flex flex-col items-start w-full overflow-hidden'> <Typography as='h2' weight='medium' className='flex w-full items-center' > {recipient.name} {recipient.isOfficial && ( <Typography className='ml-2'> <Verified className='w-5 h-5' /> </Typography> )} {!!item.unreadMessages && ( <span className='text-primary-dark-200 font-semibold text-sm flex items-center justify-center ml-auto size-5 rounded-full bg-primary-white'> {item.unreadMessages} </span> )} </Typography> {!!item.participantsTyping?.length ? ( <Typography as='p' variant='secondary' className='line-clamp-1'> typing... </Typography> ) : draft?.state === 'send' ? ( <Typography as='p' variant='secondary' className='line-clamp-1 break-all'> <Typography as='span' variant='error'> Draft: </Typography> {draft.value} </Typography> ) : ( !!item.lastMessage && ( <div className='flex items-center w-full gap-5'> <Typography className='break-all dark:text-primary-white/30 text-primary-gray line-clamp-1'> {item.lastMessage?.text} </Typography> <Typography className='ml-auto' variant='secondary'> {new Date(item.lastMessage.createdAt).toLocaleTimeString(navigator.language, { hour: 'numeric', minute: 'numeric' })} </Typography> </div> ) )} </div> </NavLink> </li> ); };
备注:内容来源于stack exchange,提问作者Flain
相关产品推荐
相关产品推荐

