Skip to content

feat: optimistic example #293

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 5, 2024
Merged

feat: optimistic example #293

merged 1 commit into from
Oct 5, 2024

Conversation

ponderingdemocritus
Copy link
Contributor

@ponderingdemocritus ponderingdemocritus commented Oct 5, 2024

  • add optimistic example
  • improves readme

Summary by CodeRabbit

  • New Features

    • Introduced a custom React hook, useSystemCalls, for managing system-related functionalities.
    • Updated spawn action handling to streamline entity creation and modification.
  • Documentation

    • Enhanced SDK documentation with new sections on "Optimistic Client Rendering," "Key Features," "Understanding Queries," and "Advanced Usage."
    • Improved clarity and organization in the main README, including updates to example references.
  • Bug Fixes

    • Refined text and structure in documentation for better readability and coherence.

Copy link

coderabbitai bot commented Oct 5, 2024

Walkthrough

The changes in this pull request introduce a new custom React hook, useSystemCalls, which encapsulates functionalities for managing system calls related to entity spawning. The App.tsx file is updated to utilize this new hook, replacing direct calls to client actions with a more modular approach. Additionally, the SDK documentation is enhanced with new sections detailing optimistic client rendering and clarifying key features and usage examples. The readme.md file is also updated for improved clarity and organization.

Changes

File Path Change Summary
examples/example-vite-react-sdk/src/App.tsx - Added import for useSystemCalls hook.
- Destructured spawn from useSystemCalls and updated the onClick handler to call await spawn().
examples/example-vite-react-sdk/src/useSystemCalls.ts - Introduced useSystemCalls hook with spawn function for managing system calls and entity spawning.
- Implemented optimistic state updates and error handling.
packages/sdk/readme.md - Added new sections: "Optimistic Client Rendering," "Key Features," "Understanding Queries," and "Advanced Usage."
- Enhanced clarity and usability of documentation.
readme.md - Updated section header from "Examples" to "All Examples."
- Reformatted example references for consistency and improved readability.

Possibly related PRs

  • feat: subscription clauses #235: Updates to App.tsx with hooks that may relate to the new useSystemCalls hook, indicating potential overlap in state management and entity synchronization.
  • fix: entity sync #252: Modifications in App.tsx regarding action dispatching and management, potentially connecting to the main PR's changes.
  • fix: prettier #277: Significant changes in App.tsx related to database connection initialization, which may connect to the new state management structure.
  • feat: draft zustand state management system #280: Introduction of a Zustand-based state management system, aligning with enhancements from the useSystemCalls hook.
  • feat: state fix #284: Updates to the "recs" state, relevant to managing system calls and entity states introduced in the main PR.
  • feat: add some documentation details #290: Addition of new interfaces and enumerations that may relate to the new functionalities in the main PR.
  • feat: docs theme and build #292: Documentation updates regarding the SDK, potentially including references to new features and changes from the main PR.

🐇 In the meadow, hops a bright sprite,
With hooks and calls, we code through the night.
A spawn here, a state there, all in a dance,
Optimistic updates, give our code a chance!
Readme shines bright, with clarity anew,
In the world of Dojo, there's magic for you! ✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Outside diff range and nitpick comments (6)
readme.md (3)

156-162: LGTM: Improved formatting and consistency in example list

The list of examples has been reformatted for better consistency and readability. The paths to the examples have been correctly updated.

Consider adding a brief description (1-2 words) next to each example to give readers a quick idea of what each example demonstrates. For instance:

- [example-vite-react-sdk](./examples/example-vite-react-sdk/) - Basic React integration
- [example-vite-react-phaser-recs](./examples/example-vite-react-phaser-recs/) - Phaser game integration

This would help users quickly identify which example is most relevant to their needs.


Line range hint 164-264: Enhance the Contributing section

The contributing guidelines are comprehensive and well-structured. To further improve this section:

Consider adding a subsection about coding standards and pull request guidelines. This could include:

  1. Code style guidelines (e.g., use of linters, formatting tools)
  2. Commit message format
  3. Pull request template
  4. Code review process

This addition would help maintain consistency in contributions and streamline the review process.


Line range hint 1-264: LGTM: Overall improvements to README structure and content

The changes to the README file have significantly improved its structure, clarity, and usability. The updates to example references and paths are consistent throughout the document, and the contributing section provides comprehensive guidance for developers.

To further enhance the document:

  1. Consider adding a "Quick Links" section at the top of the README with links to important resources like documentation, community channels, and the main Dojo repository.
  2. You might want to include a brief section on "Compatibility" or "Requirements" to inform users about the necessary environment or dependencies for using Dojo.js.

These additions would make it even easier for new users to get started with the project.

packages/sdk/readme.md (1)

347-419: Excellent addition of the "Optimistic Client Rendering" section!

This new section effectively explains the concept of optimistic updates and provides a detailed, well-commented code example. It aligns perfectly with the PR objective of adding an optimistic example to the project.

The use of immer for efficient state updates is a great practice. The step-by-step explanation and the code example will be very helpful for developers implementing this feature.

Consider adding a brief explanation of why optimistic rendering is beneficial (e.g., improved perceived performance, better user experience) to further emphasize its importance.

examples/example-vite-react-sdk/src/App.tsx (2)

9-9: LGTM. Consider adding documentation for the new hook.

The addition of the useSystemCalls hook is a good step towards better organization of system-related calls. This aligns well with React best practices for custom hooks.

To improve maintainability, consider adding JSDoc comments for the useSystemCalls hook in its implementation file, explaining its purpose and usage.


Line range hint 1-314: Overall good refactoring, but clarification needed on optimistic updates.

The changes in this file improve the organization of system calls by introducing and using the useSystemCalls hook. This is a positive step towards better code structure and potentially easier management of side effects.

However, the PR objectives mention adding an optimistic example, which is not immediately apparent in these changes. Could you provide more information on how the optimistic updates are implemented? Are they handled within the useSystemCalls hook, or is there additional code not shown in this diff that implements this feature?

Consider documenting the optimistic update strategy, either in comments within the useSystemCalls hook or in a separate documentation file, to make the implementation clear for other developers.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 94f15c6 and 2fe9c64.

📒 Files selected for processing (4)
  • examples/example-vite-react-sdk/src/App.tsx (3 hunks)
  • examples/example-vite-react-sdk/src/useSystemCalls.ts (1 hunks)
  • packages/sdk/readme.md (1 hunks)
  • readme.md (3 hunks)
🧰 Additional context used
🪛 Biome
examples/example-vite-react-sdk/src/useSystemCalls.ts

[error] 33-34: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)

🔇 Additional comments (7)
readme.md (2)

23-23: LGTM: Improved clarity in Table of Contents

The renaming of "Examples" to "All Examples" in the Table of Contents enhances clarity and consistency with the corresponding section title later in the document.


73-74: LGTM: Updated example references

The paths to the example projects have been correctly updated, ensuring that the links are accurate and consistent with the project structure.

packages/sdk/readme.md (3)

Line range hint 14-21: Great addition of the "Key Features" section!

This new section provides a clear and concise overview of the SDK's main features. It effectively highlights the key benefits for potential users, which aligns well with the overall documentation improvements mentioned in the PR objectives.


Line range hint 421-460: Great update to the "Advanced Usage" section!

The addition of a more complex query example effectively demonstrates how to create 'AND' with 'OR' statements in queries. This example will be valuable for users who need to construct sophisticated queries.

The code is well-formatted and easy to understand, which aligns with the overall improvement of the documentation mentioned in the PR objectives.


Line range hint 1-460: Excellent improvements to the SDK documentation!

The changes made to this README file significantly enhance its clarity and comprehensiveness. The addition of the "Key Features" section, the detailed explanation of "Optimistic Client Rendering" with a practical example, and the improved "Advanced Usage" section with complex query examples all contribute to making the documentation more valuable for SDK users.

These improvements align perfectly with the PR objectives of adding an optimistic example and enhancing the README. Great job on making the Dojo SDK documentation more user-friendly and informative!

examples/example-vite-react-sdk/src/App.tsx (2)

167-167: LGTM. Clarify the implementation of optimistic updates.

The modification to use the spawn function from useSystemCalls is consistent with the earlier changes and correctly handles the asynchronous nature of the call.

However, the PR objectives mention adding an optimistic example, which is not immediately apparent in this change. Could you clarify how the optimistic updates are implemented?

To help verify this, let's check the implementation of the spawn function:

#!/bin/bash
# Description: Check the implementation of the spawn function

# Test: Look for the definition of spawn function within useSystemCalls
rg --type typescript 'function useSystemCalls' -A 20 | rg 'spawn.*='

21-22: Good refactoring. Verify the implementation of useSystemCalls.

Extracting the spawn function from useSystemCalls is a good refactoring step. It centralizes system calls and potentially allows for easier management of side effects or optimistic updates.

To ensure the correctness of this change, let's verify the implementation of useSystemCalls:

Comment on lines +54 to +56
// Confirm the transaction if successful
state.confirmTransaction(transactionId);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Confirm transaction only on successful spawn

Currently, state.confirmTransaction(transactionId); is called in the finally block, which means it executes regardless of whether the spawn action succeeded or failed. This could lead to confirming a transaction that was reverted due to an error.

Move state.confirmTransaction(transactionId); to after the successful completion of the spawn action.

Suggestion:

            }
-       } catch (error) {
+           // Confirm the transaction if successful
+           state.confirmTransaction(transactionId);
+       } catch (error) {
            // Revert the optimistic update if an error occurs
            state.revertOptimisticUpdate(transactionId);
            console.error("Error executing spawn:", error);
            throw error;
-       } finally {
-           // Confirm the transaction if successful
-           state.confirmTransaction(transactionId);
        }

Committable suggestion was skipped due to low confidence.

Comment on lines +33 to +34
(draft.entities[entityId].models.dojo_starter.Moves!.remaining =
remainingMoves)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid assignment within an expression

Assigning a value within an expression can be confusing and may lead to unintended side effects. It's generally recommended to separate assignments from expressions for better readability.

Refactor the code to separate the assignment from the expression.

Suggestion:

state.applyOptimisticUpdate(
    transactionId,
-    (draft) =>
-        (draft.entities[entityId].models.dojo_starter.Moves!.remaining =
-            remainingMoves)
+    (draft) => {
+        draft.entities[entityId].models.dojo_starter.Moves!.remaining = remainingMoves;
+    }
);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
(draft.entities[entityId].models.dojo_starter.Moves!.remaining =
remainingMoves)
state.applyOptimisticUpdate(
transactionId,
(draft) => {
draft.entities[entityId].models.dojo_starter.Moves!.remaining = remainingMoves;
}
);
🧰 Tools
🪛 Biome

[error] 33-34: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)

} = useDojo();

const generateEntityId = () => {
return getEntityIdFromKeys([BigInt(account?.address)]);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Handle potential 'undefined' account in generateEntityId

In the generateEntityId function, calling BigInt(account?.address) may throw an error if account or account.address is undefined, since BigInt(undefined) will result in a TypeError.

Consider adding a check to ensure that account and account.address are defined before converting to BigInt.

Suggestion:

const generateEntityId = () => {
+    if (!account?.address) {
+        throw new Error('Account address is undefined');
+    }
    return getEntityIdFromKeys([BigInt(account.address)]);
};
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return getEntityIdFromKeys([BigInt(account?.address)]);
if (!account?.address) {
throw new Error('Account address is undefined');
}
return getEntityIdFromKeys([BigInt(account.address)]);

Comment on lines +18 to +57
const spawn = async () => {
// Generate a unique entity ID
const entityId = generateEntityId();

// Generate a unique transaction ID
const transactionId = uuidv4();

// The value to update the Moves model with
const remainingMoves = 100;

// Apply an optimistic update to the state
// this uses immer drafts to update the state
state.applyOptimisticUpdate(
transactionId,
(draft) =>
(draft.entities[entityId].models.dojo_starter.Moves!.remaining =
remainingMoves)
);

try {
// Execute the spawn action from the client
await client.actions.spawn({ account });

// Wait for the entity to be updated with the new state
await state.waitForEntityChange(entityId, (entity) => {
return (
entity?.models?.dojo_starter?.Moves?.remaining ===
remainingMoves
);
});
} catch (error) {
// Revert the optimistic update if an error occurs
state.revertOptimisticUpdate(transactionId);
console.error("Error executing spawn:", error);
throw error;
} finally {
// Confirm the transaction if successful
state.confirmTransaction(transactionId);
}
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ensure account is defined before proceeding in spawn

Within the spawn function, if account is undefined, calls to generateEntityId() and client.actions.spawn({ account }) may fail, leading to runtime errors.

Add a check at the beginning of the spawn function to ensure account is defined.

Suggestion:

const spawn = async () => {
+    if (!account) {
+        throw new Error('Account is undefined');
+    }
    // Generate a unique entity ID
    const entityId = generateEntityId();
    // ...
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const spawn = async () => {
// Generate a unique entity ID
const entityId = generateEntityId();
// Generate a unique transaction ID
const transactionId = uuidv4();
// The value to update the Moves model with
const remainingMoves = 100;
// Apply an optimistic update to the state
// this uses immer drafts to update the state
state.applyOptimisticUpdate(
transactionId,
(draft) =>
(draft.entities[entityId].models.dojo_starter.Moves!.remaining =
remainingMoves)
);
try {
// Execute the spawn action from the client
await client.actions.spawn({ account });
// Wait for the entity to be updated with the new state
await state.waitForEntityChange(entityId, (entity) => {
return (
entity?.models?.dojo_starter?.Moves?.remaining ===
remainingMoves
);
});
} catch (error) {
// Revert the optimistic update if an error occurs
state.revertOptimisticUpdate(transactionId);
console.error("Error executing spawn:", error);
throw error;
} finally {
// Confirm the transaction if successful
state.confirmTransaction(transactionId);
}
};
const spawn = async () => {
if (!account) {
throw new Error('Account is undefined');
}
// Generate a unique entity ID
const entityId = generateEntityId();
// Generate a unique transaction ID
const transactionId = uuidv4();
// The value to update the Moves model with
const remainingMoves = 100;
// Apply an optimistic update to the state
// this uses immer drafts to update the state
state.applyOptimisticUpdate(
transactionId,
(draft) =>
(draft.entities[entityId].models.dojo_starter.Moves!.remaining =
remainingMoves)
);
try {
// Execute the spawn action from the client
await client.actions.spawn({ account });
// Wait for the entity to be updated with the new state
await state.waitForEntityChange(entityId, (entity) => {
return (
entity?.models?.dojo_starter?.Moves?.remaining ===
remainingMoves
);
});
} catch (error) {
// Revert the optimistic update if an error occurs
state.revertOptimisticUpdate(transactionId);
console.error("Error executing spawn:", error);
throw error;
} finally {
// Confirm the transaction if successful
state.confirmTransaction(transactionId);
}
};
🧰 Tools
🪛 Biome

[error] 33-34: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)

@ponderingdemocritus ponderingdemocritus merged commit 31cad93 into main Oct 5, 2024
3 checks passed
@ponderingdemocritus ponderingdemocritus deleted the fix/readme-1 branch October 5, 2024 08:01
@coderabbitai coderabbitai bot mentioned this pull request Oct 7, 2024
This was referenced Oct 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant