mirror of
https://git.mirrors.martin98.com/https://github.com/langgenius/dify.git
synced 2025-08-15 17:25:52 +08:00
fix: toggling AppDetailNav causes unnecessary component rerenders (#3718)
This commit is contained in:
parent
9eebe9d54e
commit
40e36e9b52
@ -5,6 +5,7 @@ import React, { useCallback, useEffect, useState } from 'react'
|
||||
import { usePathname, useRouter } from 'next/navigation'
|
||||
import cn from 'classnames'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useShallow } from 'zustand/react/shallow'
|
||||
import s from './style.module.css'
|
||||
import { useStore } from '@/app/components/app/store'
|
||||
import AppSideBar from '@/app/components/app-sidebar'
|
||||
@ -32,7 +33,11 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
||||
const media = useBreakpoints()
|
||||
const isMobile = media === MediaType.mobile
|
||||
const { isCurrentWorkspaceManager } = useAppContext()
|
||||
const { appDetail, setAppDetail, setAppSiderbarExpand } = useStore()
|
||||
const { appDetail, setAppDetail, setAppSiderbarExpand } = useStore(useShallow(state => ({
|
||||
appDetail: state.appDetail,
|
||||
setAppDetail: state.setAppDetail,
|
||||
setAppSiderbarExpand: state.setAppSiderbarExpand,
|
||||
})))
|
||||
const [navigation, setNavigation] = useState<Array<{
|
||||
name: string
|
||||
href: string
|
||||
|
@ -26,7 +26,8 @@ export type ICardViewProps = {
|
||||
const CardView: FC<ICardViewProps> = ({ appId }) => {
|
||||
const { t } = useTranslation()
|
||||
const { notify } = useContext(ToastContext)
|
||||
const { appDetail, setAppDetail } = useAppStore()
|
||||
const appDetail = useAppStore(state => state.appDetail)
|
||||
const setAppDetail = useAppStore(state => state.setAppDetail)
|
||||
|
||||
const updateAppDetail = async () => {
|
||||
fetchAppDetail({ url: '/apps', id: appId }).then((res) => {
|
||||
|
@ -22,7 +22,7 @@ export type IChartViewProps = {
|
||||
|
||||
export default function ChartView({ appId }: IChartViewProps) {
|
||||
const { t } = useTranslation()
|
||||
const { appDetail } = useAppStore()
|
||||
const appDetail = useAppStore(state => state.appDetail)
|
||||
const isChatApp = appDetail?.mode !== 'completion' && appDetail?.mode !== 'workflow'
|
||||
const isWorkflow = appDetail?.mode === 'workflow'
|
||||
const [period, setPeriod] = useState<PeriodParams>({ name: t('appLog.filter.period.last7days'), query: { start: today.subtract(7, 'day').format(queryDateFormat), end: today.format(queryDateFormat) } })
|
||||
|
@ -213,7 +213,7 @@ const DatasetDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
||||
document.title = `${datasetRes.name || 'Dataset'} - Dify`
|
||||
}, [datasetRes])
|
||||
|
||||
const { setAppSiderbarExpand } = useStore()
|
||||
const setAppSiderbarExpand = useStore(state => state.setAppSiderbarExpand)
|
||||
|
||||
useEffect(() => {
|
||||
const localeMode = localStorage.getItem('app-detail-collapse-or-expand') || 'expand'
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import React, { useEffect } from 'react'
|
||||
import { useShallow } from 'zustand/react/shallow'
|
||||
import NavLink from './navLink'
|
||||
import type { NavIcon } from './navLink'
|
||||
import AppBasic from './basic'
|
||||
@ -26,11 +27,13 @@ export type IAppDetailNavProps = {
|
||||
}
|
||||
|
||||
const AppDetailNav = ({ title, desc, icon, icon_background, navigation, extraInfo, iconType = 'app' }: IAppDetailNavProps) => {
|
||||
const { appSidebarExpand, setAppSiderbarExpand } = useAppStore()
|
||||
const { appSidebarExpand, setAppSiderbarExpand } = useAppStore(useShallow(state => ({
|
||||
appSidebarExpand: state.appSidebarExpand,
|
||||
setAppSiderbarExpand: state.setAppSiderbarExpand,
|
||||
})))
|
||||
const media = useBreakpoints()
|
||||
const isMobile = media === MediaType.mobile
|
||||
const [modeState, setModeState] = useState(appSidebarExpand)
|
||||
const expand = modeState === 'expand'
|
||||
const expand = appSidebarExpand === 'expand'
|
||||
|
||||
const handleToggle = (state: string) => {
|
||||
setAppSiderbarExpand(state === 'expand' ? 'collapse' : 'expand')
|
||||
@ -39,9 +42,9 @@ const AppDetailNav = ({ title, desc, icon, icon_background, navigation, extraInf
|
||||
useEffect(() => {
|
||||
if (appSidebarExpand) {
|
||||
localStorage.setItem('app-detail-collapse-or-expand', appSidebarExpand)
|
||||
setModeState(appSidebarExpand)
|
||||
setAppSiderbarExpand(appSidebarExpand)
|
||||
}
|
||||
}, [appSidebarExpand])
|
||||
}, [appSidebarExpand, setAppSiderbarExpand])
|
||||
|
||||
return (
|
||||
<div
|
||||
@ -61,7 +64,7 @@ const AppDetailNav = ({ title, desc, icon, icon_background, navigation, extraInf
|
||||
)}
|
||||
{iconType !== 'app' && (
|
||||
<AppBasic
|
||||
mode={modeState}
|
||||
mode={appSidebarExpand}
|
||||
iconType={iconType}
|
||||
icon={icon}
|
||||
icon_background={icon_background}
|
||||
@ -81,10 +84,10 @@ const AppDetailNav = ({ title, desc, icon, icon_background, navigation, extraInf
|
||||
>
|
||||
{navigation.map((item, index) => {
|
||||
return (
|
||||
<NavLink key={index} mode={modeState} iconMap={{ selected: item.selectedIcon, normal: item.icon }} name={item.name} href={item.href} />
|
||||
<NavLink key={index} mode={appSidebarExpand} iconMap={{ selected: item.selectedIcon, normal: item.icon }} name={item.name} href={item.href} />
|
||||
)
|
||||
})}
|
||||
{extraInfo && extraInfo(modeState)}
|
||||
{extraInfo && extraInfo(appSidebarExpand)}
|
||||
</nav>
|
||||
{
|
||||
!isMobile && (
|
||||
@ -96,7 +99,7 @@ const AppDetailNav = ({ title, desc, icon, icon_background, navigation, extraInf
|
||||
>
|
||||
<div
|
||||
className='flex items-center justify-center w-6 h-6 text-gray-500 cursor-pointer'
|
||||
onClick={() => handleToggle(modeState)}
|
||||
onClick={() => handleToggle(appSidebarExpand)}
|
||||
>
|
||||
{
|
||||
expand
|
||||
|
@ -6,6 +6,7 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { setAutoFreeze } from 'immer'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import { useShallow } from 'zustand/react/shallow'
|
||||
import HasNotSetAPIKEY from '../base/warning-mask/has-not-set-api'
|
||||
import FormattingChanged from '../base/warning-mask/formatting-changed'
|
||||
import GroupName from '../base/group-name'
|
||||
@ -367,7 +368,12 @@ const Debug: FC<IDebug> = ({
|
||||
handleVisionConfigInMultipleModel()
|
||||
}, [multipleModelConfigs, mode])
|
||||
|
||||
const { currentLogItem, setCurrentLogItem, showPromptLogModal, setShowPromptLogModal } = useAppStore()
|
||||
const { currentLogItem, setCurrentLogItem, showPromptLogModal, setShowPromptLogModal } = useAppStore(useShallow(state => ({
|
||||
currentLogItem: state.currentLogItem,
|
||||
setCurrentLogItem: state.setCurrentLogItem,
|
||||
showPromptLogModal: state.showPromptLogModal,
|
||||
setShowPromptLogModal: state.setShowPromptLogModal,
|
||||
})))
|
||||
const [width, setWidth] = useState(0)
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
|
||||
|
@ -8,6 +8,7 @@ import produce from 'immer'
|
||||
import { useBoolean, useGetState } from 'ahooks'
|
||||
import { clone, isEqual } from 'lodash-es'
|
||||
import { CodeBracketIcon } from '@heroicons/react/20/solid'
|
||||
import { useShallow } from 'zustand/react/shallow'
|
||||
import Button from '../../base/button'
|
||||
import Loading from '../../base/loading'
|
||||
import AppPublisher from '../app-publisher'
|
||||
@ -65,7 +66,10 @@ type PublishConfig = {
|
||||
const Configuration: FC = () => {
|
||||
const { t } = useTranslation()
|
||||
const { notify } = useContext(ToastContext)
|
||||
const { appDetail, setAppSiderbarExpand } = useAppStore()
|
||||
const { appDetail, setAppSiderbarExpand } = useAppStore(useShallow(state => ({
|
||||
appDetail: state.appDetail,
|
||||
setAppSiderbarExpand: state.setAppSiderbarExpand,
|
||||
})))
|
||||
const [formattingChanged, setFormattingChanged] = useState(false)
|
||||
const { setShowAccountSettingModal } = useModalContext()
|
||||
const [hasFetchedDetail, setHasFetchedDetail] = useState(false)
|
||||
|
@ -21,7 +21,7 @@ const LogAnnotation: FC<Props> = ({
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const router = useRouter()
|
||||
const { appDetail } = useAppStore()
|
||||
const appDetail = useAppStore(state => state.appDetail)
|
||||
|
||||
const options = [
|
||||
{ value: PageType.log, text: t('appLog.title') },
|
||||
|
@ -12,6 +12,7 @@ import {
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { debounce } from 'lodash-es'
|
||||
import classNames from 'classnames'
|
||||
import { useShallow } from 'zustand/react/shallow'
|
||||
import type {
|
||||
ChatConfig,
|
||||
ChatItem,
|
||||
@ -79,7 +80,14 @@ const Chat: FC<ChatProps> = ({
|
||||
chatAnswerContainerInner,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const { currentLogItem, setCurrentLogItem, showPromptLogModal, setShowPromptLogModal, showAgentLogModal, setShowAgentLogModal } = useAppStore()
|
||||
const { currentLogItem, setCurrentLogItem, showPromptLogModal, setShowPromptLogModal, showAgentLogModal, setShowAgentLogModal } = useAppStore(useShallow(state => ({
|
||||
currentLogItem: state.currentLogItem,
|
||||
setCurrentLogItem: state.setCurrentLogItem,
|
||||
showPromptLogModal: state.showPromptLogModal,
|
||||
setShowPromptLogModal: state.setShowPromptLogModal,
|
||||
showAgentLogModal: state.showAgentLogModal,
|
||||
setShowAgentLogModal: state.setShowAgentLogModal,
|
||||
})))
|
||||
const [width, setWidth] = useState(0)
|
||||
const chatContainerRef = useRef<HTMLDivElement>(null)
|
||||
const chatContainerInnerRef = useRef<HTMLDivElement>(null)
|
||||
|
@ -12,7 +12,7 @@ type IDevelopMainProps = {
|
||||
}
|
||||
|
||||
const DevelopMain = ({ appId }: IDevelopMainProps) => {
|
||||
const { appDetail } = useAppStore()
|
||||
const appDetail = useAppStore(state => state.appDetail)
|
||||
const { t } = useTranslation()
|
||||
|
||||
if (!appDetail) {
|
||||
|
@ -40,7 +40,7 @@ const AppNav = () => {
|
||||
const { t } = useTranslation()
|
||||
const { appId } = useParams()
|
||||
const { isCurrentWorkspaceManager } = useAppContext()
|
||||
const { appDetail } = useAppStore()
|
||||
const appDetail = useAppStore(state => state.appDetail)
|
||||
const [showNewAppDialog, setShowNewAppDialog] = useState(false)
|
||||
const [showNewAppTemplateDialog, setShowNewAppTemplateDialog] = useState(false)
|
||||
const [showCreateFromDSLModal, setShowCreateFromDSLModal] = useState(false)
|
||||
|
@ -31,7 +31,7 @@ const Nav = ({
|
||||
onLoadmore,
|
||||
isApp,
|
||||
}: INavProps) => {
|
||||
const { setAppDetail } = useAppStore()
|
||||
const setAppDetail = useAppStore(state => state.setAppDetail)
|
||||
const [hovered, setHovered] = useState(false)
|
||||
const segment = useSelectedLayoutSegment()
|
||||
const isActived = Array.isArray(activeSegment) ? activeSegment.includes(segment!) : segment === activeSegment
|
||||
|
@ -35,7 +35,7 @@ const NavSelector = ({ curNav, navs, createText, isApp, onCreate, onLoadmore }:
|
||||
const { t } = useTranslation()
|
||||
const router = useRouter()
|
||||
const { isCurrentWorkspaceManager } = useAppContext()
|
||||
const { setAppDetail } = useAppStore()
|
||||
const setAppDetail = useAppStore(state => state.setAppDetail)
|
||||
|
||||
const handleScroll = useCallback(debounce((e) => {
|
||||
if (typeof onLoadmore === 'function') {
|
||||
|
@ -33,7 +33,7 @@ const Header: FC = () => {
|
||||
const workflowStore = useWorkflowStore()
|
||||
const appDetail = useAppStore(s => s.appDetail)
|
||||
const appSidebarExpand = useAppStore(s => s.appSidebarExpand)
|
||||
const appID = useAppStore(state => state.appDetail?.id)
|
||||
const appID = appDetail?.id
|
||||
const {
|
||||
nodesReadOnly,
|
||||
getNodesReadOnly,
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
import cn from 'classnames'
|
||||
import useSWR from 'swr'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useShallow } from 'zustand/react/shallow'
|
||||
import {
|
||||
useIsChatMode,
|
||||
useWorkflow,
|
||||
@ -40,7 +41,11 @@ const ViewHistory = () => {
|
||||
const [open, setOpen] = useState(false)
|
||||
const { formatTimeFromNow } = useWorkflow()
|
||||
const workflowStore = useWorkflowStore()
|
||||
const { appDetail, setCurrentLogItem, setShowMessageLogModal } = useAppStore()
|
||||
const { appDetail, setCurrentLogItem, setShowMessageLogModal } = useAppStore(useShallow(state => ({
|
||||
appDetail: state.appDetail,
|
||||
setCurrentLogItem: state.setCurrentLogItem,
|
||||
setShowMessageLogModal: state.setShowMessageLogModal,
|
||||
})))
|
||||
const historyWorkflowData = useStore(s => s.historyWorkflowData)
|
||||
const { handleBackupDraft } = useWorkflowRun()
|
||||
const { data: runList, isLoading: runListLoading } = useSWR((appDetail && !isChatMode && open) ? `/apps/${appDetail.id}/workflow-runs` : null, fetchWorkflowRunHistory)
|
||||
|
@ -4,6 +4,7 @@ import {
|
||||
useMemo,
|
||||
} from 'react'
|
||||
import { useNodes } from 'reactflow'
|
||||
import { useShallow } from 'zustand/react/shallow'
|
||||
import type { CommonNodeType } from '../types'
|
||||
import { Panel as NodePanel } from '../nodes'
|
||||
import { useStore } from '../store'
|
||||
@ -22,7 +23,12 @@ const Panel: FC = () => {
|
||||
const showInputsPanel = useStore(s => s.showInputsPanel)
|
||||
const workflowRunningData = useStore(s => s.workflowRunningData)
|
||||
const historyWorkflowData = useStore(s => s.historyWorkflowData)
|
||||
const { currentLogItem, setCurrentLogItem, showMessageLogModal, setShowMessageLogModal } = useAppStore()
|
||||
const { currentLogItem, setCurrentLogItem, showMessageLogModal, setShowMessageLogModal } = useAppStore(useShallow(state => ({
|
||||
currentLogItem: state.currentLogItem,
|
||||
setCurrentLogItem: state.setCurrentLogItem,
|
||||
showMessageLogModal: state.showMessageLogModal,
|
||||
setShowMessageLogModal: state.setShowMessageLogModal,
|
||||
})))
|
||||
const {
|
||||
showNodePanel,
|
||||
showDebugAndPreviewPanel,
|
||||
|
@ -25,7 +25,7 @@ const RunPanel: FC<RunProps> = ({ hideResult, activeTab = 'RESULT', runID, getRe
|
||||
const { t } = useTranslation()
|
||||
const { notify } = useContext(ToastContext)
|
||||
const [currentTab, setCurrentTab] = useState<string>(activeTab)
|
||||
const { appDetail } = useAppStore()
|
||||
const appDetail = useAppStore(state => state.appDetail)
|
||||
const [loading, setLoading] = useState<boolean>(true)
|
||||
const [runDetail, setRunDetail] = useState<WorkflowRunDetailResponse>()
|
||||
const [list, setList] = useState<NodeTracing[]>([])
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { useContext } from 'react'
|
||||
import {
|
||||
create,
|
||||
useStore as useZustandStore,
|
||||
} from 'zustand'
|
||||
import { createStore } from 'zustand/vanilla'
|
||||
import { debounce } from 'lodash-es'
|
||||
import type { Viewport } from 'reactflow'
|
||||
import type {
|
||||
@ -70,9 +70,9 @@ type Shape = {
|
||||
}
|
||||
|
||||
export const createWorkflowStore = () => {
|
||||
return create<Shape>(set => ({
|
||||
return createStore<Shape>(set => ({
|
||||
appId: '',
|
||||
workflowData: undefined,
|
||||
workflowRunningData: undefined,
|
||||
setWorkflowRunningData: workflowRunningData => set(() => ({ workflowRunningData })),
|
||||
historyWorkflowData: undefined,
|
||||
setHistoryWorkflowData: historyWorkflowData => set(() => ({ historyWorkflowData })),
|
||||
|
Loading…
x
Reference in New Issue
Block a user