DEV Community

Cover image for 5 Things AI Can't Do, Even in Zustand
DevUnionX
DevUnionX

Posted on

5 Things AI Can't Do, Even in Zustand

This report analyzes in depth technical and conceptual limitations AI assistants can encounter when using Zustand. We addressed the topic under five main headings: store architecture and normalization, complex async flows and side effects, middleware and listener ordering nuances, performance with subscriptions and memoization traps, and migration/update and ecosystem compatibility. Each section includes technical explanations, real error modes where AI gets stuck, GitHub case studies, and code examples.

For instance under Store Architecture heading, how Zustand's persist middleware works and functions added to state cannot be automatically saved were emphasized. AI generally includes a function like login in persist without considering this serialization limitation, and application cannot find this function when reloaded getting error. In Middleware section, noted that order of middlewares like persist, querystring, and immer affects behavior. AI assistants mix up middleware order leading to data merging or priority problems. In comparative table, Zustand code generated by AI and code written by human hand get evaluated in terms of correctness, accessibility, maintainability, package size, and runtime safety. Flow diagram models developer and AI collaboration, showing decision points to check at each stage. From outputs, clearly understood that human supervision is critical in situations AI can easily skip.

For this study, first Zustand's official documentation and README were examined. Then GitHub issues and discussion topics about middleware order, persist problems, subscriptions and related blog posts were evaluated. For instance dev.to article about state persist addressed persistent store's rehydration problems. Literature and case studies examining AI code assistant errors like LinearB research were also utilized. In light of obtained data, five topics were determined and technical details specific to each, code examples, real case study examples, and solution recommendations were developed. Throughout report relevant information was supported with sources.

In Zustand, store structure is flexible but correct modeling of state is important. Though no official normalization tool like in RTK, certain parts of state can be saved to localStorage with persist middleware. For example import create from zustand and persist from zustand/middleware. Const useStore equals create with persist and set function containing user object with name and email, token null, login async function with user and token parameters setting user and token, with name auth-store.

In this code, persist middleware's purpose is making specified slice persistent. But AI assistants can manage side effects in this structure incorrectly. For instance while primitive types like user and token serialize well, login function cannot be stored in JSON. Developer had observed login function disappearing from state when page refreshed. This is expected situation because JSON.stringify only supports primitive types. AI code generally cannot notice this serialization limit, adds login function inside persist expecting it works, but in real life function doesn't get preserved.

AI failure modes: AI thinks store content as simple data trying to serialize complex objects or functions. In this case code AI created saves items that cannot be converted to JSON and cannot access later. For instance a date like new Date or class instance doesn't give value you expect after persist. Additionally using non-normalized large array or object structures also causes repetitive updates. AI generally keeps state organization flat and doesn't separate data dependencies like related objects.

Developer strategies: keep store design simple and use values serializable to JSON. Avoid storing functions and class instances inside state. When using persist, use only pure data like primitive types and pure objects. Manually review store structure AI created. If carries function or complex object, extract these outside state. Manage events inside action instead of functions like login. Manually fix normalization AI skipped, divide state into parts when needed or use separate slices. For instance keeping user information in separate slice and persisting it prevents confusion of functions. Ultimately state model should be planned, AI outputs should be subjected to manual normalization when needed.

Zustand supports async/await directly, doesn't need middleware like redux-thunk. For instance fetchTodos function can be defined directly inside store. However in complex side effect scenarios, AI assistant limitations emerge. Especially in situations requiring multiple async steps or error management, AI can lean toward simple solutions. For instance in scenario refreshing user's token, AI focuses on just adding async to login function and returning expected value. In real life if refresh fails, need to catch error. AI code generally doesn't put try/catch structure correctly. When error happens, application crashes due to uncaught promise. Additionally AI generally does step-by-step async tasks with .then/.catch chain instead of await and forgets returning error. This produces code not suitable for async thunk based state management.

Real example showing user authentication process. AI can produce code like this. Const useAuthStore equals create with set function containing loading false, error null, authenticate async function with credentials parameter. Set loading true. Try with const response equals await api.login credentials, set loading false and user response.user. Catch err with set loading false and error err.message. If AI forgot a problem like set loading false and error err.message, loading can stay true forever or error contains wrong value. In real QA scenario, AI output generally doesn't contain such finally blocks.

Developer strategies: catch errors correctly in every async function. Using try/catch/finally blocks, close loading state in every situation. In mandatory cases additionally trigger with useEffect or onMount. Manually add try/catch or set calls missing in async function from AI. For complex scenarios like unusual side effects and rollbacks, consider using additional helpers from zustand/middleware like subscribe-with-selector. Additionally combination with solutions like React-Query instead of global API calls reduces AI's error-making area.

Zustand combines middleware chain with compose method. For example const useSearchStore equals create with persist wrapping querystring wrapping immer with set function, query params config, and name search. In above code, persist, querystring, immer get applied in order. When order changes, behavior also changes. Developer had observed querystring arrow persist arrow immer order gives different results compared to persist arrow querystring arrow immer order. But AI assistant generally neglects putting middlewares in correct order or does reverse. This leads to errors in state merging and priority ordering. For instance if persist comes first, localStorage gets used first, whereas if querystring comes first, URL parameters gain priority. Wrong ordering can cause unexpected default behaviors.

For listeners also ordering is important. If a subscribe or addListener function will be called from inside middleware or React hook, structure needs preserving. Otherwise can have repetitive calls or memory leaks. For instance if you create subscriber outside store and don't clean, new listener gets added at every page redirect and memory increases.

Developer strategies: check order of all middlewares used. Adjust recommended combination like persist querystring immer by looking at examples in documentation. In store definitions from AI, pay attention to middleware callback function. If static array written, fix it. In subscriptions, use subscribe inside useEffect and do unsubscribe on component unmount. When you see missing unsubscribe in AI codes, definitely add it. Additionally when working with external triggers like URL parameters or storage, check usage examples in each middleware's docs. Briefly side-effect ordering should be manually validated.

Zustand gives useStore hook for selectors where you take desired state slice and subscribe component. However AI assistants generally overlook memoization side. For instance const count equals useStore with state arrow state.counter.value, when used like this, component re-renders only when counter.value changes. But AI sometimes can write like this. Const state equals useStore with state arrow state, or const count equals useStore with state arrow state.counter. This usage causes component to render even when another field in state changes. Thus application slows down unnecessarily. For performance, zustand/shallow or customized equality functions can be used.

When using subscriptions or store.subscribe, also should be careful. For instance a listener triggers at every state update. Especially in large and frequently changing states, callback running at every change slows application. Code written by AI generally contains anonymous functions listening to every change. AI assistant might not specify selected state pieces. For performance, using subscribe with selector and callback is recommended. Also in useEffect plus subscribe usage inside React components, if unsubscribe not called, memory problems happen.

Developer strategies: when using useStore, always select only state fields you need. If possible apply shallow or custom equality function. Review subscriber codes from AI. If anonymous function listening to all state exists, customize this. For example subscribe correctly with const unsub equals useStore.subscribe with state arrow state.token and token arrow console.log Token changed token. Cleanup with unsub. This will trigger only when token changes. Additionally for large state, consider making immutable updates with libraries like immer. But sometimes in AI code, wrong set usage catches eye like set nested with spread. When nesting deepens, prefer using produce with immer. Thus you use clean approach instead of complex update codes AI created.

The following table presents general comparison in Zustand context between AI generation and human generation. Correctness medium containing function serialization, subscriber cleanup, and middleware order errors versus High with persist/rehydration and subscriptions managed correctly and tests done. Accessibility weak with code comments and structure explanations generally missing and state changes can be overlooked versus Good using explanatory slice and selector names and clear error handling.

Maintainability low with short auto-generated codes mostly undocumented in inline usages versus High with comprehensive documentation and examples and well-designed hooks. Package Size low because Zustand is small library so no noticeable difference, Zustand around 1.8KB versus Low again lightweight but extra middlewares can be manually added. Runtime Safety medium with runtime problems like subscription mismanagement and function persistence errors possible versus High with antipatterns tested and warnings tracked in React build process.

The mermaid flowchart shows workflow between developer and AI. In first step, checked whether functions exist in store content. If functions exist, moved to external sources needing serialization. Then middleware ordering and async functions inspected. Finally appropriateness of subscriptions and performance strategies evaluated. After each check when found incomplete, necessary corrections made. This process aims to detect and address error-prone points in Zustand code AI created.

Flowchart shows: Requirements including store model, middleware/listing, async needs. Get Zustand code from AI. Decision whether functions in state. If yes extract these functions outside serialization and return. If no decision whether middleware order correct. If incomplete return. If complete decision whether async operations checked. If incomplete return. If complete decision whether subscribe and performance adjusted. If incomplete return. If complete code review and test approval.

Top comments (0)