lobe-chat
lobe-chat copied to clipboard
🐛 fix: mobile end returns to the previous page error
💻 变更类型 | Change Type
- [ ] ✨ feat
- [x] 🐛 fix
- [ ] ♻️ refactor
- [ ] 💄 style
- [ ] 🔨 chore
- [ ] 📝 docs
🔀 变更说明 | Description of Change
Close #880
📝 补充信息 | Additional Information
移动端没有必要用 url 存储内容,因为 PWA 后就看不到 url 了,而且还会导致 history 堆栈异常
@mushan0x0 is attempting to deploy a commit to the LobeHub Team on Vercel.
A member of the Team first needs to authorize it.
👍 @mushan0x0
Thank you for raising your pull request and contributing to our Community
Please make sure you have followed our contributing guidelines. We will review it as soon as possible.
If you encounter any problems, please feel free to connect with us.
非常感谢您提出拉取请求并为我们的社区做出贡献,请确保您已经遵循了我们的贡献指南,我们会尽快审查它。
如果您遇到任何问题,请随时与我们联系。
Codecov Report
Attention: 17 lines in your changes are missing coverage. Please review.
Comparison is base (
13f03cd) 86.08% compared to head (a00b751) 85.97%. Report is 1 commits behind head on main.
Additional details and impacted files
@@ Coverage Diff @@
## main #886 +/- ##
==========================================
- Coverage 86.08% 85.97% -0.11%
==========================================
Files 170 172 +2
Lines 7687 7742 +55
Branches 813 822 +9
==========================================
+ Hits 6617 6656 +39
- Misses 1070 1086 +16
:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.
修改前
https://github.com/lobehub/lobe-chat/assets/29084441/2ae6689e-f731-4599-abf6-650975a3dd5a
修改后
https://github.com/lobehub/lobe-chat/assets/29084441/1950fc8c-2d72-40e1-bdc0-2eb7a64578e7
用这个方案解感觉不是特别好。如果这样的话,移动端的一些分享状态会丢失。
比如通过链接来打开: https://chat-preview.lobehub.com/market?agent=deployment-agent
本来应该是能拉起相应助手弹窗的,按这个方案就没法正常打开。
我感觉思路上应该仍然使用url state。然后看看两个方向
-
- 不记录 history 栈
-
- 优化返回按钮逻辑,不使用history返回,而是直接用页面跳转实现。
第二个方向是我觉得可能更合适的方案,因为如果是通过链接点直接进去的页面,例如 https://chat-preview.lobehub.com/settings/tts ,现在点返回按钮是直接返回到了浏览器启动页。
Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑🤝🧑👫🧑🏿🤝🧑🏻👩🏾🤝👨🏿👬🏿
It doesn't feel particularly good to use this solution. If this is the case, some sharing status on the mobile terminal will be lost.
For example, open it through the link: https://chat-preview.lobehub.com/market?agent=deployment-agent
It should be able to bring up the corresponding assistant pop-up window, but according to this plan, it cannot be opened normally.
I feel that the idea should still be to use url state. Then look in both directions
-
- Do not record the history stack
-
- Optimize the return button logic, do not use history to return, but directly use page jump to implement it.
The second direction is a solution that I think may be more appropriate, because if it is a page that is entered directly through a link point, such as https://chat-preview.lobehub.com/settings/tts, now clicking the return button will return directly to the browsing Server startup page.
方案 1 实现不了,这个 bug 实际不完全是堆栈导致的,因为返回后链接是对的,只是界面没有改变,刷新一下就正常了 方案 2 这个其实不是返回按钮的问题,LobeChat 左上角的返回按钮点击是正常的,不正常的是浏览器的返回按钮和移动端的侧边返回手势
用这个方案解感觉不是特别好。如果这样的话,移动端的一些分享状态会丢失。 比如通过链接来打开: https://chat-preview.lobehub.com/market?agent=deployment-agent
这个问题实际可以改一下代码,只处理 hash 的情况就行了,需要分享状态的记录就用 search 模式
Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑🤝🧑👫🧑🏿🤝🧑🏻👩🏾🤝👨🏿👬🏿
Option 1 cannot be implemented. This bug is not actually caused by the stack, because the link is correct after returning, but the interface has not changed. Refresh it and it will be normal. Option 2 This is actually not a problem with the back button. Clicking the back button in the upper left corner of LobeChat is normal. What is abnormal is the browser's back button and the side back gesture on the mobile terminal.
It doesn’t feel particularly good to use this solution. If this is the case, some sharing status on the mobile terminal will be lost. For example, open it through the link: https://chat-preview.lobehub.com/market?agent=deployment-agent
For this problem, you can actually change the code to only handle the hash situation. If you need to share status records, use the search mode.
修改后的效果
https://github.com/lobehub/lobe-chat/assets/29084441/c9eca37b-3310-4ef1-9b4f-8802e5f0d2bd
不完全是分享的场景, 本质还是需要存在url状态,在刷新当前页面状态或者打开新页面时能否复原。
比如类似 https://chat-preview.lobehub.com/chat/mobile#session=inbox&topic=dyZjAmAe
这样的页面,在对应浏览器下打开应该也会是正常的。
https://github.com/lobehub/lobe-chat/assets/28616219/9e8f5054-2b1f-440a-b3cd-9041ed799cad
LobeChat 左上角的返回按钮点击是正常的
好像用户反馈的是需要点击两次按钮才能返回上一页?
Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑🤝🧑👫🧑🏿🤝🧑🏻👩🏾🤝👨🏿👬🏿
It is normal to click the return button in the upper left corner of LobeChat
It seems that users have reported that they need to click the button twice to return to the previous page?
上面那个修改后的怎么会闪一下?
Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑🤝🧑👫🧑🏿🤝🧑🏻👩🏾🤝👨🏿👬🏿
Why does the modified one above flash?
感觉是否替换为 localStorage 得从更加完善的产品视角来看看,比如之前有用户提到希望下次进来看到的就是上一个助手的会话,那这种需求从产品角度来看就适合使用localstorage 来记录上一次的激活助手和主题。
但这个 bug 我看下来更多的应该是 url storage 下state 变更导致 url history堆栈记录了重复的值? 可能从这个角度出发修问题更加合适一些?比如看看是不是在url state 一致时就不修改url state? 我记得我之前的实现好像没有做diff检测的。
Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑🤝🧑👫🧑🏿🤝🧑🏻👩🏾🤝👨🏿👬🏿
I feel that whether to replace it with localStorage needs to be looked at from a more complete product perspective. For example, some users mentioned that they hope to see the previous assistant session next time they come in. From a product perspective, localstorage is suitable for this kind of needs. Record the last activated assistant and theme.
But this bug seems to me more likely to be that the state change under url storage causes the url history stack to record duplicate values? Maybe it’s more appropriate to fix the problem from this perspective? For example, see if the url state is not modified when the url state is consistent? I remember that my previous implementation didn't seem to do diff detection.
返回按钮是正常的,有问题的是侧滑返回手势,和点击浏览器返回上一页的问题,要触发好几次才会返回到聊天列表。
做了 diff 检查也是这样的,最主要原因是 url 的路径和状态没有做区分,比如 #session=xxx 是 /chat/mobile 路径才会用到的状态,但是在 /chat 路径的时候也被设置了,导致了没有必要的 hash 改变。
#session=inbox&topic=dyZjAmAe 这种使用方式在移动端基本上也不会出现,一般使用都是用 PWA 了,用链接的情况除了上面分享 agent 还有可能,别的基本上不会使用带状态的链接了。
闪一下的原因应该是聊天记录是异步请求的。
Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑🤝🧑👫🧑🏿🤝🧑🏻👩🏾🤝👨🏿👬🏿
The back button is normal. The problem is the side swipe back gesture and the problem of clicking the browser to return to the previous page. It takes several triggers to return to the chat list.
This is also the case after doing a diff check. The main reason is that the path and status of the url are not distinguished. For example, #session=xxx is a state that is only used in the /chat/mobile path, but in the /chat path was also set, resulting in unnecessary hash changes.
#session=inbox&topic=dyZjAmAe This situation will not occur on the mobile terminal. Generally, PWA is used. In addition to the above sharing agent, it is possible to use links. In other cases, stateful links are basically not used. .
The reason for the flashing is probably that the chat record is requested asynchronously.
做了 diff 检查也是这样的,最主要原因是 url 的路径和状态没有做区分,比如 #session=xxx 是 /chat/mobile 路径才会用到的状态,但是在 /chat 路径的时候也被设置了,导致了没有必要的 hash 改变。
这么看这个 middleware 的实现还是有缺陷,可能路由状态持久化的方案还是得按页面来处理,不能用全局 store 来管。
Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑🤝🧑👫🧑🏿🤝🧑🏻👩🏾🤝👨🏿👬🏿
This is also the case after doing a diff check. The main reason is that the path and status of the URL are not distinguished. For example, #session=xxx is a status that is only used in the /chat/mobile path, but it is also set in the /chat path. , resulting in unnecessary hash changes.
From this point of view, the implementation of this middleware is still flawed. Maybe the routing state persistence solution still has to be handled on a page-by-page basis and cannot be managed by the global store.
#session=inbox&topic=dyZjAmAe 这种使用方式在移动端基本上也不会出现,一般使用都是用 PWA 了,用链接的情况除了上面分享 agent 还有可能,别的基本上不会使用带状态的链接了。
其实我上半年做的一版工程方案里,有通过用url 分享会话的,大致是这样的 url
https://xxxx/share?messages=G0UAEJwHdgO90JXYBwLOfIRKr63yFunbI5_0_9paDJotOFDDlwDPxbBjlVIyyt4fEhg3nEC7pynUi2WzQ
现在 lobe-chat 里也保留了这部分实现,只不过之前考虑分享会话风险就没实装成功能,但这个在哪个端倒是都有使用场景。
闪一下的原因应该是聊天记录是异步请求的。
你看下我的录屏。异步请求这个我有做 loading 态的,你可能要看下为什么换成现在的实现方案之后这个 loading 态丢了。
Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑🤝🧑👫🧑🏿🤝🧑🏻👩🏾🤝👨🏿👬🏿
The reason for the flashing is probably that the chat record is requested asynchronously.
Check out my screen recording. I have a loading state for asynchronous requests. You may want to take a look at why the loading state was lost after switching to the current implementation.
感觉讨论下来根本解法可能是两种之一?
-
针对 middleware 补充一个url state 的页面限定范围?比如某些 url state 只在对应url上挂载,其他url不挂载。这样还能解决现在pc端也有在其他页面出现 url 状态的问题
-
在移动端下使用 localStorage 持久化sessionId topicId,好处是 pwa 场景下可能使用体验会更好。但如果用户是使用网页访问的话部分场景体验会差一点。
Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑🤝🧑👫🧑🏿🤝🧑🏻👩🏾🤝👨🏿👬🏿
It feels like the fundamental solution after discussion may be one of two?
-
Supplement a page limit range of url state for middleware? For example, some URL states are only mounted on the corresponding URL, and other URLs are not mounted. This can also solve the problem that some PC users have on other pages now.
-
Use localStorage to persist sessionId topicId on the mobile terminal. The advantage is that the user experience may be better in the pwa scenario. But if the user accesses it through a web page, the experience in some scenarios will be worse.
- 针对 middleware 补充一个url state 的页面限定范围?比如某些 url state 只在对应url上挂载,其他url不挂载。这样还能解决现在pc端也有在其他页面出现 url 状态的问题
这样还是有问题,比如切换不同话题还是会导致会有多次返回无效,我觉得这是 zustand 的 storage 不会跟状态双向绑定导致的,这应该是一个设计缺陷 😅,对比 zustand 和 ahook 的官方例子:
https://github.com/lobehub/lobe-chat/assets/29084441/6f5da613-c00e-442f-9e15-cc40043d21d0
https://github.com/lobehub/lobe-chat/assets/29084441/d9eb75cd-c925-47c8-953d-612364c96d96
你看下我的录屏。异步请求这个我有做 loading 态的,你可能要看下为什么换成现在的实现方案之后这个 loading 态丢了。
修改前也是这样,但是真机上表现是正常的
这样还是有问题,比如切换不同话题还是会导致会有多次返回无效,我觉得这是 zustand 的 storage 不会跟状态双向绑定导致的,这应该是一个设计缺陷 😅
可能是因为 zustand/persist 这个中间件没考虑 url 这种使用场景。它原本是给 localStorage 用的,我在它的功能基础上做的扩展,变成了 urlState。 在原本 persist 的情况下,如果你直接改 localStorage 的话,也是不会同步状态到前端应用上的,毕竟这个行为太不常见了。
所以这个 persist 没有默认实现相应的监听逻辑,我研究下有没有可能把 url 变化的监听逻辑加上。
Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑🤝🧑👫🧑🏿🤝🧑🏻👩🏾🤝👨🏿👬🏿
There are still problems with this. For example, switching between different topics will still result in multiple invalid returns. I think this is caused by zustand’s storage not being bidirectionally bound to the state. This should be a design flaw 😅
It may be because the zustand/persist middleware does not consider the usage scenario of url. It was originally used for localStorage. I extended it based on its functions and turned it into urlState. In the original persist case, if you directly change localStorage, the status will not be synchronized to the front-end application. After all, this behavior is too uncommon, so this persist does not implement the corresponding monitoring logic by default. I will study whether it is possible to add monitoring logic for url changes.
在移动端下使用 localStorage 持久化sessionId topicId,好处是 pwa 场景下可能使用体验会更好。但如果用户是使用网页访问的话部分场景体验会差一点。
如果要走这个逻辑的话,我的建议是不要改 middleware 的逻辑,直接在外层配置改。
const persistOptions: PersistOptions<ChatStore> = {
name: 'LobeChat_Chat',
// 手动控制 Hydration ,避免 ssr 报错
skipHydration: true,
storage: createHyperStorage({
localStorage: false,
url: {
mode: 'hash',
selectors: [{ activeTopicId: 'topic' }],
},
}),
version: 0,
};
在这里加个 mobile的判断,如果是 mobile ,用 localStorage,如果是pc,用 url。
Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑🤝🧑👫🧑🏿🤝🧑🏻👩🏾🤝👨🏿👬🏿
Use localStorage to persist sessionId topicId on the mobile terminal. The advantage is that the user experience may be better in the pwa scenario. But if the user accesses it through a web page, the experience in some scenarios will be worse.
If you want to follow this logic, my suggestion is not to change the middleware logic, but directly change the outer configuration.
const persistOptions: PersistOptions<ChatStore> = {
name: 'LobeChat_Chat',
// Manually control Hydration to avoid ssr errors
skipHydration: true,
storage: createHyperStorage({
localStorage: false,
url: {
mode: 'hash',
selectors: [{ activeTopicId: 'topic' }],
},
}),
version: 0,
};
Add a mobile judgment here. If it is mobile, use localStorage. If it is pc, use url.