Skip to content

Conversation

aleks3fs
Copy link

@aleks3fs aleks3fs commented Feb 6, 2025

There is an issue with running @chainlit/react-client, with latest React 19 and issue seems to be connected to usage of recoil.

In this PR I've

  • replaced recoil with zustand. I tried to combine logically connected parts of the state into stores.
  • bumped React to v19

It'd be nice to have this in the latest version, but I haven't been able to test everything.

@dosubot dosubot bot added size:XL This PR changes 500-999 lines, ignoring generated files. frontend Pertains to the frontend. labels Feb 6, 2025
@jbeckerdm
Copy link

I've just done the exact same thing before finding this PR https://github.com/jbeckerdm/chainlit/tree/zustand 😆

Looks great! This already allows custom frontends to update to React 19.
I think this would break chainlits own frontend, so we need to fix the usage of react-client in the chainlit frontend as well before this gets merged.

jbeckerdm added 4 commits May 9, 2025 14:03
 - Migrate from recoil to zustand
 - Bump react to v19

# Conflicts:
#	libs/react-client/package.json
#	libs/react-client/src/state.ts
#	libs/react-client/src/types/index.ts
#	libs/react-client/src/useChatSession.ts
@aleks3fs
Copy link
Author

If someone finds time to take this one over, since I might not have enough time, I'd appreciate it. Or if yours gets merged, I'm fine with both, as long as we get progress on compatibility with the latest version 😄

@jbeckerdm
Copy link

jbeckerdm commented May 12, 2025

I'm gladly taking this over.
In fact I forked your code, updated tsup to fix the build, and started using it with my custom frontend to test.
I don't know how a PR takeover works, since I cannot push into your fork branch. Can we swap it with my fork of your branch https://github.com/jbeckerdm/chainlit/tree/migrate-recoil-zustand, or would I work on yours?
Either way is fine by me.

@aleks3fs
Copy link
Author

Wonderful 🙏, I've sent you an invite for my fork, but do whatever is easier for you. I don't really care, as long as we get some progress on this 😄

@jbeckerdm
Copy link

Updated the source branch with my changes.

  • export the stores so they're usable outside the library
  • bring over the new mcp store, including local storage persistance (which comes included in zustand)
  • update tsup, since the old version had a DTS build error with zustand. Updating it fixes that.

@jbeckerdm
Copy link

To make the tests run, I also replaced every usage of react-client's state in the chainlit frontend and copilot lib.
They now build successfully, though I can't get the tests themselves to run locally just yet.

@jbeckerdm
Copy link

All chainlit E2E tests run successfully.
I think this can be reviewed, and we can decide on the final structure and splitting of the atoms into the different stores.

@willydouhard I'd like to ask you or other core chainlit maintainers for a first feedback on this, if possible.

This enables upgrading the chainlit frontend as well as anyone using it to upgrade to React 19, and also allows for more flexible store structures.
From our first testing with React 19 (and this zustand rewrite) in our 3000+ user chainlit app, we've also seen great performance improvements in the frontend.

@tegarmonster
Copy link

any update for this? :)

@FlawaCLV
Copy link

Any update? Any help needed?

@jbeckerdm
Copy link

@FlawaCLV @tegarmonster
First and foremost we need a reviewer, because I'd like to know if the implementation is good or needs improvements.
Given how the chainlit team announced that they'll stop maintaining chainlit however, I feel like noone really wants to look into this at this time.

@FlawaCLV
Copy link

@jbeckerdm thanks for the update! I missed the news that they wanted to stop maintaining the project. I understand now why this PR is stalling.

@tegarmonster
Copy link

@FlawaCLV @tegarmonster First and foremost we need a reviewer, because I'd like to know if the implementation is good or needs improvements. Given how the chainlit team announced that they'll stop maintaining chainlit however, I feel like noone really wants to look into this at this time.

ah I see, thanks for the information

@zomchak-code
Copy link

@jbeckerdm
Could you share a link to this announcement?

Given how the chainlit team announced that they'll stop maintaining chainlit however

@aleks3fs
Copy link
Author

@jbeckerdm Could you share a link to this announcement?

Given how the chainlit team announced that they'll stop maintaining chainlit however

It's on the main page of the repo, 1st part of the readme
https://github.com/Chainlit/chainlit/blob/main/backend/README.md?plain=1#L2

@jbeckerdm jbeckerdm force-pushed the migrate-recoil-zustand branch from 3f4b422 to 7c70fa7 Compare June 18, 2025 15:24
@jbeckerdm jbeckerdm force-pushed the migrate-recoil-zustand branch from 7c70fa7 to cbc21ee Compare June 18, 2025 15:26
@jbeckerdm
Copy link

chatSettingsDefaultValue isn't properly populated yet,
but perhaps we can define it in some other way (or well fix the issue).

If anyone wants to look into that, feel free!

@hayescode
Copy link
Contributor

I am 1 of 2 users who received maintainer access. My strong suit is backend though and I'm not sure if the other maintainer has frontend experience. Can some of you review this and document any breaking changes/workarounds? This seems like a great PR but given the creator has left we're all in a tough spot. I don't want to further delay the huge backlog of improvements any further (just pushed 25% of outstanding PRs) but this is a big change that deserves more community feedback especially since this isn't my area.

@jbeckerdm
Copy link

@hayescode I'm essentially the new maintainer of this PR.
I'm trying to fix a very specific bug with the chat settings not loading (as in, the backend doesn't send the chat_settings websocket event to the frontend), which currently occurs in a test branch where I use this new code on our custom frontend/backend. It worked just fine with the newest chainlit react client and react 18, but now this hard to find bug occurs about half the time, and only in our CI test environment, not locally.
Since we didn't touch our backend in that branch, I suspect it's some edge case in this PR's code, so it's important to find it for this PR to get merged as well.

@jbeckerdm
Copy link

But I encourage anyone to test this PR in their own way and review the code! I'll make sure to work through the feedback.

@asvishnyakov
Copy link
Member

asvishnyakov commented Jul 3, 2025

@jbeckerdm Hi Jannis.

I'm the other maintainer, and while React isn’t the primary framework of choice used by me or my company, I do have frontend experience and a background in building frameworks.

I really appreciate your work, and in my opinion, the upgrade to React 19 looks good. However, switching from one state management library to another is a breaking change - especially since you’re modifying the shared react-client library. This library is used by developers who can't or don't want to use the full Chainlit frontend. Making such a change could create a cascade of compatibility issues in their projects, which I’d like to avoid.

Regarding performance: it’s great if switching to zustand brings improvements. I submitted a similar performance-focused PR on the backend side, and it wasn’t accepted right away and for good reason. I think we need more measurable evidence before making changes like this, such as writing performance benchmarks or tests.

So, I’d like to propose the following plan:

  1. Split out the React 19 upgrade into a separate PR. Or, if you don’t have the time, I can take care of it later.
  2. Create an issue in the Chainlit repo describing the bug you're experiencing, including as many details as possible. If we’re able to reproduce the issue and determine that switching to zustand is the only viable fix, or if we gather clear performance data showing a benefit, we can revisit this PR and move forward with it.

Thanks again for your contribution!

@aleks3fs
Copy link
Author

aleks3fs commented Jul 4, 2025

@jbeckerdm Hi Jannis.

I'm the other maintainer, and while React isn’t the primary framework of choice used by me or my company, I do have frontend experience and a background in building frameworks.

I really appreciate your work, and in my opinion, the upgrade to React 19 looks good. However, switching from one state management library to another is a breaking change - especially since you’re modifying the shared react-client library. This library is used by developers who can't or don't want to use the full Chainlit frontend. Making such a change could create a cascade of compatibility issues in their projects, which I’d like to avoid.

Regarding performance: it’s great if switching to zustand brings improvements. I submitted a similar performance-focused PR on the backend side, and it wasn’t accepted right away and for good reason. I think we need more measurable evidence before making changes like this, such as writing performance benchmarks or tests.

So, I’d like to propose the following plan:

  1. Split out the React 19 upgrade into a separate PR. Or, if you don’t have the time, I can take care of it later.
  2. Create an issue in the Chainlit repo describing the bug you're experiencing, including as many details as possible. If we’re able to reproduce the issue and determine that switching to zustand is the only viable fix, or if we gather clear performance data showing a benefit, we can revisit this PR and move forward with it.

Thanks again for your contribution!

Hey,

while performance boost is cool, the base idea of this PR was to enable upgrade to React 19. Latest version of recoil doesn't support react 19, and that is because recoil is deprecated. It was always an experimental library, so it was bound to happen.

It's really easy to dismiss performance improvement, if there isn't a bottleneck, but this one not it, at least not at its core.

Basically, if chainlit doesn't change from recoil to something else, then we cannot upgraade chainlit's react to 19, which means that any developer using chainlit's lib won't be able to do it either.

@asvishnyakov
Copy link
Member

@aleks3fs Thank you for the explanation! I didn't see the deprecation message anywhere until I opened their repo. In that case, I think we don't have many options left, so I'll review this PR.

@jbeckerdm
Copy link

jbeckerdm commented Jul 7, 2025

The aforementioned bug with chat_settings not loading has turned out to be a side effect of our custom frontend's connection logic, and is NOT related to this PR.
Which means that the PR is ready to be reviewed.

@neel004
Copy link

neel004 commented Jul 13, 2025

Hey @asvishnyakov, Great to have you on board as maintainer.
At the moment, the current Chainlit version makes it impossible for us to upgrade our React to 19. I noticed that this pull request might addresses this issue, I believe merging it would greatly benefit users who rely on React 19 compatibility.

May I kindly request your attention to reviewing and, if appropriate, merging this change at your earliest convenience? Your assistance would be greatly appreciated.
and @aleks3fs @jbeckerdm thanks for this pr

@asvishnyakov asvishnyakov self-requested a review July 15, 2025 04:01
@neel004
Copy link

neel004 commented Jul 28, 2025

Just popping in to check if there’s any chance this PR could get a review soon. We’re kinda stuck on React 19 support without these changes, so merging this would really help out!

Let me know if there’s anything you need from my end, or if there’s something holding things up.

Thanks so much for keeping things moving — really appreciate all the work everyone’s putting in!

@hayescode
Copy link
Contributor

CI needs to be updated to work with this

@asvishnyakov
Copy link
Member

@hayescode I'm working on that here and in few other PRs, let's wait until you return at Wednesday, I think it should be ready

authConfig?: IAuthConfig;
user?: IUser | null;

threadHistory?: ThreadHistory;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While thread history is available only to authenticated users, I don't think it should be part of AuthState. It should be a separate state instead, as including it violates SRP.

(state: T | ((state: T) => T), replace: true): void;
}

export const stateOrSetter = <T, K extends keyof T>(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this helper, if set already support this?
image


import { stateOrSetter } from './utils';

// import { subscribeWithSelector } from 'zustand/middleware/subscribeWithSelector';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove a comment (did you forget something?)

"name": "@chainlit/react-client",
"description": "Websocket client to connect to your chainlit app.",
"version": "0.2.4",
"version": "0.3.0",
Copy link
Member

@asvishnyakov asvishnyakov Aug 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't change version, we do it only at release time

Comment on lines +112 to +117
const chatSettingsValue = get().chatSettingsInputs.reduce(
(form: { [key: string]: any }, input: any) => (
(form[input.id] = input.initial), form
),
{}
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we eliminate code duplication?

@asvishnyakov
Copy link
Member

So actually, after careful review, here are my two biggest concerns:

  1. After merging this PR, we’ll be using React 19 in libs/react-client and React 18 in the frontend itself. This is highly risky in my opinion, especially since we’re not building or testing the frontend and libs against different React versions.

  2. I made a few mistakes during merge and minor refactoring, and surprisingly the build didn’t fail - even though I removed a variable that was still in use, which led to a runtime error. Only the E2E tests caught it. I’d like to address this issue first.

@hayescode FYI

@asvishnyakov asvishnyakov added the keep-for-a-while Don’t mark as stale. This label should be used only for confirmed bugs or other important things label Aug 5, 2025
@asvishnyakov asvishnyakov added this to the 2.8.0 milestone Aug 15, 2025
@mb-dbridge
Copy link

Hello! I can see this is still open with a 2.8.0 milestone while 2.8.1 has been released.
I'm wondering if there's any plan on re-prioritising this, or if there are any other plans?
Thanks for any update you could provide.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
frontend Pertains to the frontend. keep-for-a-while Don’t mark as stale. This label should be used only for confirmed bugs or other important things size:XL This PR changes 500-999 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants