Giter VIP home page Giter VIP logo

grdbquery's People

Contributors

groue avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

grdbquery's Issues

`mirrorAppearanceState` and initially hidden views

I have a View within a TabView, and I'm using .mirrorAppearanceState on the View. Initially the View's tab is not selected and thus the View is not visible.

The problem is that the View will now keep auto updating in the background until the respective tab is selected for the first time. onDisappear is not called because the View never appeared in the first place.

Is there a way to reload/refresh?

Hey,

I'm currently trying to reload a @Query as my database is changed on another Process (NotificationService Extension to be exact).
I'm using a DarwinNotificationCenter as described here to notify my view.

The problem that I have now, is that I can't reload the @Query at least I don't know how to do it.
As it's not a State variable I cannot modify it. Is there maybe a builtin way in @Query or GRDB itself, which I don't know of to trigger a refresh?

Question: How would you use GRDBQuery on large data

Hey,

I'm currently working on a Chat App and using GRDBQuery for data loading from GRDB.

How would you use GRDBQuery for loading chat message?
Currently I'm fetching all messages which starts to cause large loading times and memory usage as it's all getting fetched at once.

The messages are displayed in a ScrollView which embeds a LazyVStack.

How would I use GRDBQuery for fetching just the messages currently needed, but keep the immediate loading GRDBQuery offers.

Is that possible?

More SwiftUI-Like syntax for the requests

I was wondering today whether you could move the syntax a bit closer to what's common in SwiftUI (e.g. with button styles). In the README/demo you have the following code:

    @Query(PlayerRequest())
    private var player: Player?

I thought it would be nice to write it like this:

    @Query(.player)
    private var player: Player?

To make this work, you need to add the following extension:

extension Queryable where Self == PlayerRequest {
    static var player: Self { PlayerRequest() }
}

(Of course, you can do this for the other requests as well).

It took me a while...

But I eventually figured out I had to add GRDBQuery as a package dependency to get the demos and test to build :)

@Query support DatabasePool as DatabaseContext?

GRDB docs indicate that DatabasePool and DatabaseQueue can be used the same way, but
this does not extend to GRDBQuery.

It seems if Query could work with a pool the same way GRDB does in its api it would work as is
Maybe I'm missing something as the docs say to only ever open one connection to 1 file be it pool or queue, which if so really makes it seem like Query needs to work with pools too.
I understood it as a pool allowed multiple access to the same file from different locations.

SwiftUI views using EnvironmentStateObject receive multiple init calls

(Disclaimer: I'm fairly new to SwiftUI and GRDBQuery)

I've noticed that my SwiftUI views that use @EnvironmentStateObject to inject their view models are having init called multiple times. I'm not sure if this is intended behaviour or not, but it places some restrictions on what can be done in the makeObject block if it gets called multiple times.

Here's an example:

struct MyView: View {
    @EnvironmentStateObject private var viewModel: MyViewModel
    
    init() {
        print("MyView.init")
        
        _viewModel = EnvironmentStateObject {
            MyViewModel(dependencies: $0.dependencies)
        }

    var body: some View {
        Button {
            viewModel.doStuff()
        } label: {
            Text(viewModel.status)
        }
    }
}
final class MyViewModel: ObservableObject {
    @Published var status: String = "Idle"

    private var stuffUseCase: StuffUseCase

    init(dependencies: MyDependencies) {
        print("MyViewModel.init")
        self.stuffUseCase = dependencies.getStuffUseCase()
    }

    func doStuff() {
        self.status = "Working"
        DispatchQueue.global().async {
            self.stuffUseCase.doStuff()
            self.status = "Done"
        }
    }
}

When my app starts, the logs show the following before any navigation or interaction:

MyView.init
MyViewModel.init
MyView.init
MyViewModel.init

Is this to be expected?

[Bug?] SwiftUI warning in new betas

Hey,

the new Xcode and iOS 16 beta now show a warning which reads as following:

Publishing changes from within view updates is not allowed, this will cause undefined behavior.

The highlighted line in code is this one:

request = newRequest

I'm not sure if this is just a bug in the new beta, because I haven't had that warning before, or if they changed something in SwiftUI.

I've seen a similar issue when googling the warning on mongodb's realm GitHub:
realm/realm-swift#7908

and some posting on the apple developer forum so it is definitely not a problem which only affects GRDBQuery.

Access list of queried database models in NavigationSplitView detail pane

I am using a NavigationSplitView with 3 columns on macOS.

The NavigationSplitView is built like this:

struct ContentView: View {
    @EnvironmentObject private var navigationState: NavigationState

    var body: some View {
        NavigationSplitView {
            Sidebar()
        } content: {
            content
        } detail: {
            detail
        }
    }
    
    private var content: some View {
        ZStack {
            if let selectedPredicate = navigationState.selectedPredicate {
                BookmarkList(predicate: selectedPredicate)
                    .id(selectedPredicate.id)
                    #if os(macOS)
                    .frame(minWidth: 280)
                    #endif
            } else {
                PlaceholderView(text: "Please select a row")
            }
        }
    }
    
    private var detail: some View {
        ZStack {
            if let selectedBookmark = navigationState.selectedBookmark {
                BookmarkDetailView(id: selectedBookmark.id)
                    .id(selectedBookmark.id)
            } else {
                PlaceholderView(text: "Select a bookmark")
            }
        }
    }
}

In the content column of this split view a list of bookmarks is rendered. These bookmarks are fetched via @Query. In the detail pane a toolbar is drawn with two buttons (show previous bookmark and show next bookmark). Unfortunately I am not quite sure how to implement those actions since in my detail pane only the selected bookmark is known but not the list of all available/possibly filtered bookmarks. I think I would need to know the list of available bookmarks in BookmarkDetailView. Would it be a viable solution to fetch the bookmarks again in BookmarkDetailView or am I missing something obvious? I also attached a screenshot here to make things more clear.

Bildschirmfoto 2023-04-12 um 14 18 44

Here is my current solution but as written above I would like to make sure that I am not doing something stupid here by refetching the bookmarks from the db and whether there is an obvious better solution:

var bookmarks: [Bookmark] {
        do {
            return try appDatabase.reader.read { db in
                switch navigationState.selectedPredicate {
                    case .all:
                        return try Bookmark.all().fetchAll(db)
                    case .unread:
                        return try Bookmark.filter(Column("isArchived") == false).fetchAll(db)
                    case .archived:
                        return try Bookmark.filter(Column("isArchived") == true).fetchAll(db)
                    case .starred:
                        return try Bookmark.filter(Column("isStarred") == true).fetchAll(db)
                    case .none:
                        return []
                        
                }
            }
        } catch {
            return []
        }
    }
    
    var bookmarkIndex: Int? {
        bookmarks.firstIndex(of: bookmark)
    }
    
    var hasPreviousBookmark: Bool {
        guard let bookmarkIndex else { return false }
        return bookmarkIndex > 0
    }
    
    var hasNextBookmark: Bool {
        guard let bookmarkIndex else { return false }
        return bookmarkIndex < bookmarks.count - 1
    }
    
    private var previousButton: some View {
        Button {
            guard let bookmarkIndex, let previousBookmark = bookmarks[safe: bookmarkIndex - 1] else {
                return
            }
            self.navigationState.selectedBookmark = previousBookmark
        } label: {
            Image(systemName: "chevron.up")
        }
        .keyboardShortcut("p", modifiers: [])
        .disabled(!hasPreviousBookmark)
    }
    
    private var nextButton: some View {
        Button {
            guard let bookmarkIndex, let nextBookmark = bookmarks[safe: bookmarkIndex + 1] else {
                return
            }
            self.navigationState.selectedBookmark = nextBookmark
        } label: {
            Image(systemName: "chevron.down")
        }
        .keyboardShortcut("n", modifiers: [])
        .disabled(!hasNextBookmark)
    }

I know this is probably not an issue with the library per-se. But since all the issues posted here are answered super quick, competent and with a clear solution I wondered if you could help me as well with this one.

Kind regards,
David

@Query use for searchable suggestedTokens

I was trying to use @query to feed the suggestedTokens parameter for a searchable list. Here is an example of what I was trying to accomplish:

import SwiftUI
import GRDB
import GRDBQuery
import Combine

public struct Tag : Hashable, Codable, Identifiable, Equatable {
    private(set) public var id: Int64?
    public var tag: String
}

extension Tag: TableRecord, FetchableRecord, MutablePersistableRecord {
    enum Columns {
        static let id = Column(CodingKeys.id)
        static let tag = Column(CodingKeys.tag)
    }
    
    public mutating func didInsert(_ inserted: InsertionSuccess) {
        id = inserted.rowID
    }
}

public struct TagQuery: Queryable {

    public static var defaultValue: [Tag] { [] }

    public func publisher(in repository: Repository) -> AnyPublisher<[Tag], Error>  {

        ValueObservation.tracking { db in
            return try Tag.fetchAll(db)
        }
        .publisher(in: repository.reader, scheduling: .immediate)
        .eraseToAnyPublisher()

    }
}

struct Test: View {
    var data : [String] = ["A", "B", "C"]

    @Binding var searchTerm : String

    @State private var tokens: [Tag] = []

    @Query(TagQuery())
    private var suggestedTokens: [Tag]
    
    var body: some View {
        List {
            ForEach(data, id: \.self) { data in
                Text(data)
            }
        }
        .searchable(text: $searchTerm, tokens: $tokens, suggestedTokens: $suggestedTokens) {token in
            Text(token.tag)
        }
    }
}

it fails to compile with this error:

Cannot convert value of type 'Query<TagQuery>.Wrapper' to expected argument type 'Binding<[Token]>'

Is there a way to use @query to feed the suggestedTokens list?

Using associations in SwiftUI View

I have a has many relationship setup, but not understanding how to access the data within a SwiftUI View.

extension Race: TableRecord {
    static var sessions = hasMany(Session.self, using: ForeignKey(["race_id"]))
    var sessions: QueryInterfaceRequest<Session> {
        return request(for: Race.sessions)
    }
}

In my View I have

@Query(RaceRequest(ordering: .byStart)) private var races: [Race]

Then within the ForEach of races, I want to do a ForEach of sessions but am totally lost

Strategies for Queryable structs that need a dynamic value in SwiftUI

In the demo application dealing with the Player model, consider if you had a model called Team, which has many Player identifiers associated to it.

In such a case, you might have a view where you can toggle the Team you're viewing. To get at the data, I'd construct such a Query type like this to drive it:

struct TeamQueryableRequest: Queryable {
    var teamId: Int64
    static var defaultValue: [Team] { [] }
    
    func publisher(in appDatabase: AppDatabase) -> AnyPublisher<[Team], Error> {
        ValueObservation
            .tracking(fetchValue(_:))
            .publisher(
                in: appDatabase.databaseReader,
                scheduling: .immediate)
            .eraseToAnyPublisher()
    }
    
    func fetchValue(_ db: Database) throws -> [Release] {
        return try Team(id: teamId).fetchAll(db)
    }
}

If you just present the View to see a Team in a one-off manner such as a modal sheet, such as in the demo application, then it is acceptable to pass the id in the initializer:

struct TeamView: View {    
    @Query< TeamQueryableRequest >
    private var teams: [Team]
        
    init(id: Int64) {
        _ teams = Query(TeamQueryableRequest(teamId: id))
    }
}

The issue I am having is this: That view is always displayed (this is a Mac app I'm dealing with, where the view hierarchy is much more flattened than iOS) and the id changes dynamically as the user toggles which Team they are viewing from an EnvironmentObject that is passed around, i.e.:

class Store: ObservableObject {
    @Published var selectedTeamId: Int64 = 0
}

Due to Swift's strict initializer rules, I'm unable to do something like this:

struct TeamView: View {    
    @EnvironmentObject var store: Store
    @Query< TeamQueryableRequest >
    private var teams: [Team]
       
    init(id: Int64) {
        _ teams = Query(TeamQueryableRequest(teamId: store.selectedTeamId)) ~~~Compiler Error~~~
    }
}

TL;DR: How do I leverage Query when it relies on data that can't be used until after initialization?

Is there a good way to handle this, it feels like I'm making it too difficult. Thank you for any advice, and happy to expand if I need to.

OptionalQueryable & ListQueryable helper protocols

I've used GRDBQuery on several projects now, it's a good package.

I endup pasting the following two helpers into all of my projects. I noticed that GRDBQuery doesn't depend on GRDB, so I can't directly open a pull request to share these. Writing about them here in case some one might find them useful, or might find a way to include them in either GRDB or GRDBQuery.

import GRDB
import GRDBQuery
import Combine

protocol OptionalQueryable: Queryable {
  associatedtype V
  func fetch(_ db: Database) throws -> V?
}

extension OptionalQueryable where DatabaseContext == DatabaseWriter, ValuePublisher == AnyPublisher<V?, Error> {

  static var defaultValue: V? { nil }

  func publisher(in database: DatabaseWriter) -> AnyPublisher<V?, Error> {
    ValueObservation
      .tracking(regions: [.fullDatabase], fetch: fetch)
      .publisher(in: database, scheduling: .immediate)
      .eraseToAnyPublisher()
  }
}

protocol ListQueryable: Queryable {
  associatedtype V
  func fetch(_ db: Database) throws -> [V]
}

extension ListQueryable {

  static var defaultValue: [V] { [] }

  func publisher(in database: DatabaseWriter) -> AnyPublisher<[V], Error> {
    ValueObservation
      .tracking(fetch)
      .publisher(in: database, scheduling: .immediate)
      .eraseToAnyPublisher()
  }
}

Example

Where MyRecord conforms to Codable and FetchableRecord, and where MyRecord.CodingKeys conforms to ColumnExpression.

extension MyRecord {
  struct FetchByID: OptionalQueryable {

    let id: MyRecord.ID

    func fetch(_ db: Database) throws -> MyRecord? {
      try MyRecord
        .filter(MyRecord.CodingKeys.id == id)
        .fetchOne(db)
    }
  }
}

Testing

Also, with these helpers, it's easy to write tests around the query.

final class MyQueryTest: XCTestCase {

  func testMyQuery() throws {

    let result = try AppDatabase.fixture().read { db in
      try MyQuery().fetch(db)
    }

    XCTAssertEqual(result.count, 3)
  }
}

Where AppDatabase.fixture() is a DatabaseQueue with the migrations run and some fixtures added.

Detail pane in a NavigationSplitView not updating when selecting different sidebar item

Hi, I'm new to GRDB and GRDBQuery. I'm making an app using SwiftUI. The app has a list of items on a sidebar and details of the clicked item on the detail pane. But, I'm having a problem. When I click on a different item in the sidebar, the details don't change.

Here is the relevant code:

struct AppView: View {
    @Environment(\.appDatabase) private var appDatabase
    @Query(TeamRequest()) private var teams: [Team]
    @State private var selectedTeam: Team?

    var body: some View {
        NavigationSplitView(sidebar: {
            List(selection: $selectedTeam) {
                ForEach(teams) { team in
                    NavigationLink(value: team) {
                        Text(team.name)
                    }
                }
            }
        }) {
            if let selectedTeam = selectedTeam {
                PlayerList(team: selectedTeam)
            } else {
                Text("No team selected")
            }
        }
    }
}
struct PlayerList: View {
    @Environment(\.appDatabase) private var appDatabase
    @Query<PlayerRequest> private var players: [Player]
    private let team: Team

    init(team: Team) {
        self.team = team
        _players = Query(PlayerRequest(team: team))
    }

    var body: some View {
        List {
            ForEach(players) { player in
                Text(player.name)
            }
        }
        .navigationTitle(team.name)
    }
}

Can you help me understand what's wrong or how to fix it? Thank you for your time.

screen-recording.mp4

Can multiple @Queries bind to one single source?

Say there is a @State private var search: String = "" plus two @Queries in a view:

@Query(RequestA(search: "")) private var resultA: A;
@Query(RequestB(search: "")) private var resultB: B;

These queries need to be synced with the $search binding.

Besides the (imperative) .onChange(search) {...}, is there a better (descriptive) way? Do I need to introduce an extra layer of view to construct the queries?

Thank you ❤️

Package fails to build on Xcode 14.3 beta.

When opening the package in Xcode 14.3 beta (14E5197f), the build fails with error 'StateObject' is only available in [macOS 11.0 | iOS 14.0] or newer.
Culprits are EnvironmentStateObject.swift line 253 and Query.swift line 172.

This StackOverflow thread seems to indicate that in runtime, accessing StateObject in iOS 13 would cause a exception to be raised, but I have not tested it myself.

Apple documentation says it is available in iOS 14.0+, macOS 11.0+, tvOS 14.0+, watchOS 7.0+, so maybe we could get a new version cut with those versions as minimum in the Package file?

Thanks!
🙇

Cannot open "Documentation.docc" as a "Swift Package Folder" because it is already open as a "Folder"

I'm running command to create release build and I get weird error, I wonder if you know what this could be?

Command: xcodebuild -scheme Gem -project ../wallet/ios/Gem.xcodeproj -destination

Logs:

2023-05-02 06:46:08.528 xcodebuild[13353:50500] [MT] IDEFileReferenceDebug: [Load] <IDESwiftPackageCore.IDESwiftPackageSpecialFolderFileReference, 0x6000024bb100: name:Documentation.docc path:group:Documentation.docc> Failed to load container at path: /Users/runner/Library/Developer/Xcode/DerivedData/Gem-dfmqdzwzfjnhdngoouvpgqvecrml/SourcePackages/checkouts/GRDB.swift/GRDB/Documentation.docc, Error: Error Domain=com.apple.dt.IDEContainerErrorDomain Code=6 "Cannot open "Documentation.docc" as a "Swift Package Folder" because it is already open as a "Folder"." UserInfo={NSLocalizedDescription=Cannot open "Documentation.docc" as a "Swift Package Folder" because it is already open as a "Folder".}
2023-05-02 06:46:08.534 xcodebuild[13353:50500] [MT] IDEFileReferenceDebug: [Load] <IDESwiftPackageCore.IDESwiftPackageSpecialFolderFileReference, 0x600002468200: name:Documentation.docc path:group:Documentation.docc> Failed to load container at path: /Users/runner/Library/Developer/Xcode/DerivedData/Gem-dfmqdzwzfjnhdngoouvpgqvecrml/SourcePackages/checkouts/GRDBQuery/Sources/GRDBQuery/Documentation.docc, Error: Error Domain=com.apple.dt.IDEContainerErrorDomain Code=6 "Cannot open "Documentation.docc" as a "Swift Package Folder" because it is already open as a "Folder"." UserInfo={NSLocalizedDescription=Cannot open "Documentation.docc" as a "Swift Package Folder" because it is already open as a "Folder".}

Intended Dataflow for Mutations using GRDBQuery

In the demo project, the Player model is edited via transform in the updateScore function. For a more involved situation, say - we wanted to edit Player's name, I'm trying to grasp the relationship between Query and mutations. I have it working in the demo app with this refactor to PlayerFormView:

struct PlayerFormView: View {
    @Environment(\.dbQueue) var dbQueue
    
    @State private var player: Player = Player.placeholder
    
    init(player:Player) {
        _player = State(initialValue: player)
    }
    
    var body: some View {
        VStack {
            TextEditor(text: $player.name)
            Stepper(
                "Score: \(player.score)",
                onIncrement: { player.score += 10 },
                onDecrement: { player.score = max(0, player.score - 10) })
            Spacer()
        }
        .onChange(of: player) { newValue in
            update()
        }
    }
    
    private func update() {
        do {
            _ = try dbQueue.write { db in
                try player.save(db)
            }
        } catch PersistenceError.recordNotFound {
            // Oops, player does not exist.
            // Ignore this error: `PlayerPresenceView` will dismiss.
            //
            // You can comment out this specific handling of
            // `PersistenceError.recordNotFound`, run the preview, change the
            // score, and see what happens.
        } catch {
            fatalError("\(error)")
        }
    }
}

The changes are basically swapping var player: Player for a @State version and calling save instead of updateChanges. This is driven by making Player conform to Equatable and then leveraging onChange to know when to save. Two questions:

  1. Does this seem reasonable? Or is there are better suited way to architect this kind of mutation?
  2. I assume that Query is not meant for mutations, but rather observing changes. Is this correct? That is to say, we couldn't use the @Query<PlayerPresenceRequest> for a binding as well (I know this one is used to look for the status, but assume it simply vended a Player type).

Update
I guess another drawback with this is, if there is another window open - the @Binding var player doesn't seem to update in the windows which are not in the foreground (the nav bar does, but the PlayerFormView doesn't). This could also be an implementation error on my part:

Simulator Screen Shot - iPad mini (6th generation) - 2022-02-18 at 19 03 55

Possibility to use this without the environment

I really like the idea of this propertyWrapper! I was wondering though if it would be possible to use the wrapper without having an environment, but reusing a DatabaseQueue directly from a parameter?

My views already hold an object in which the database context lives, so I was wondering if I can initialize a property annotated with @Query in the init block. This saves me some lines and it won't create a default in memory database.

Like this (just some pseudo code):

@Query
var players: [Player]

private let objectWithDatabase: MyObject

init(objectWithDatabase: MyObject) { 
    self.objectWithDatabase = objectWithDatabase
    self.players = .init(database: objectWithDatabase.db, ...)
}

Thanks!

How to install?

(Sorry for the noob question)

I'm using Cocoapods in my app. Adding pod 'GRDBQuery' to the Podfile doesn't work. Should I import this project as a git submodule? What's the recommended way to get GRDBQuery added to an existing project/app?

Database queried twice with @Query

Given a request:

struct PlayerRequest: Queryable {
    static var defaultValue: Player? { nil }
    var id: Int
    func publisher(in reader: DatabaseReader)
    -> AnyPublisher<Player?, Error> {
        ValueObservation
            .tracking(Player.fetchOne(id: id))
            .publisher(in: reader)
            .eraseToAnyPublisher()
    }
}

Let’s have a root view:

struct PlayerRoot: View {
    @Query(PlayerRequest(id: 0))
    private var player: Player?
    var body: some View {
        Text("Foo")
    }
}

The Player.fetchOne static function is invoked twice.

How can I avoid the 2nd unnecessary query?

Thanks!

No animation on change

Hello thanks for this tiny lib around combine support in GRDB (and clever I might add)

I am currently trying to migrate a personal app from CoreData to GRDB, and I am finally enjoying querying data in my app so thanks for this 😄

But I am stumbling across a problem I don't quite know how to solve...

How can we animate change to @Query property with some kind of withAnimation {} to be automatically reflected inside the UI ?
I naively tried to surround model.save(db) with withAnimation {} but as you might have guessed it doesn't work since updated value are coming from ValueObservation, I also tried around ValueObservation but it's the same

Happy to move this to a discussion if that's not the correct place and just a mistake on my side

QueryDemo won't build

I downloaded the package and opened QueryDemo but I'm getting a compile error (Xcode 13.2)

image

Updating from 0.8.0 to 0.9.0 causes SwiftUI animations to lag.

Before After
RPReplay_Final1722004164.MP4
RPReplay_Final1722004253.MP4

What I did:

  1. Update from 0.8.0 to 0.9.0.
  2. Queryable to ValueObservationQueryable
  3. func fetchValue(_ db: Database) throws to func fetch(_ db: Database) throws
  4. .environment(\.appDatabase, AppDatabase.shared) to .appDatabase(.shared)

Basically, things I need to do according to the migration guide.

@Query property not being restored by SwiftUI when view is updated

Given a view with a @Query wrapped property:

struct PlayerView: View {
    @Query<PlayerRequest>
    private var player: Player?

    init(id: Int) {
        self._ player = Query(PlayerRequest(id: id))
    }
}

Let’s put it into our app:

struct ContentView: View {
    @State private var id: Int = 0
    var body: some View {
        PlayerView(id: id)
        Button("Change Player") {
            self.id += 1
        }
    }
}

When id gets updated, just like @State, SwiftUI restores the previously cached @Query and overwrites the value we set in the initializer (basically described here).

This means the PlayerView never gets updated. I can introduce an explicit identity to force the update:

PlayerView(id: id)
.id(id)

Is there a better approach? Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.