diff --git a/README.md b/README.md
index c96df35f..3da80d62 100644
--- a/README.md
+++ b/README.md
@@ -722,6 +722,47 @@ struct CounterView: View {
+#### [latest(_:)](https://ra1028.github.io/swiftui-atom-properties/documentation/atoms/atom/latest(_:))
+
+| |Description|
+|:--------------|:----------|
+|Summary |Provides the latest value that matches the specified condition instead of the current value.|
+|Output |`T?`|
+|Compatible |All atom types.|
+|Use Case |Keep last valid value, Retain matching state|
+
+📖 Example
+
+```swift
+struct Item {
+ let id: Int
+ let isValid: Bool
+}
+
+struct ItemAtom: StateAtom, Hashable {
+ func defaultValue(context: Context) -> Item {
+ Item(id: 0, isValid: false)
+ }
+}
+
+struct ExampleView: View {
+ @Watch(ItemAtom())
+ var currentItem
+
+ @Watch(ItemAtom().latest(\.isValid))
+ var latestValidItem
+
+ var body: some View {
+ VStack {
+ Text("Current ID: \(currentItem.id)")
+ Text("Latest Valid ID: \(latestValidItem?.id ?? 0)")
+ }
+ }
+}
+```
+
+
+
#### [changes(of:)](https://ra1028.github.io/swiftui-atom-properties/documentation/atoms/atom/changes(of:))
| |Description|
diff --git a/Sources/Atoms/Atoms.docc/Atoms.md b/Sources/Atoms/Atoms.docc/Atoms.md
index 0ffbd6d8..93d28e40 100644
--- a/Sources/Atoms/Atoms.docc/Atoms.md
+++ b/Sources/Atoms/Atoms.docc/Atoms.md
@@ -29,6 +29,7 @@ Building state by compositing atoms automatically optimizes rendering based on i
### Modifiers
- ``Atom/previous``
+- ``Atom/latest(_:)``
- ``Atom/changes``
- ``Atom/changes(of:)``
- ``Atom/animation(_:)``
@@ -86,6 +87,7 @@ Building state by compositing atoms automatically optimizes rendering based on i
- ``AtomModifier``
- ``AsyncAtomModifier``
- ``PreviousModifier``
+- ``LatestModifier``
- ``ChangesModifier``
- ``ChangesOfModifier``
- ``TaskPhaseModifier``
diff --git a/Sources/Atoms/Modifier/LatestModifier.swift b/Sources/Atoms/Modifier/LatestModifier.swift
new file mode 100644
index 00000000..c2652653
--- /dev/null
+++ b/Sources/Atoms/Modifier/LatestModifier.swift
@@ -0,0 +1,125 @@
+public extension Atom {
+ /// Provides the latest value that matches the specified condition instead of the current value.
+ ///
+ /// ```swift
+ /// struct Item {
+ /// let id: Int
+ /// let isValid: Bool
+ /// }
+ ///
+ /// struct ItemAtom: StateAtom, Hashable {
+ /// func defaultValue(context: Context) -> Item {
+ /// Item(id: 0, isValid: false)
+ /// }
+ /// }
+ ///
+ /// struct ExampleView: View {
+ /// @Watch(ItemAtom())
+ /// var currentItem
+ ///
+ /// @Watch(ItemAtom().latest(\.isValid))
+ /// var latestValidItem
+ ///
+ /// var body: some View {
+ /// VStack {
+ /// Text("Current ID: \(currentItem.id)")
+ /// Text("Latest Valid ID: \(latestValidItem?.id ?? 0)")
+ /// }
+ /// }
+ /// }
+ /// ```
+ ///
+ #if hasFeature(InferSendableFromCaptures)
+ func latest(_ keyPath: any KeyPath & Sendable) -> ModifiedAtom> {
+ modifier(LatestModifier(keyPath: keyPath))
+ }
+ #else
+ func latest(_ keyPath: KeyPath) -> ModifiedAtom> {
+ modifier(LatestModifier(keyPath: keyPath))
+ }
+ #endif
+}
+
+/// A modifier that provides the latest value that matches the specified condition instead of the current value.
+///
+/// Use ``Atom/latest(_:)`` instead of using this modifier directly.
+public struct LatestModifier: AtomModifier {
+ /// A type of base value to be modified.
+ public typealias Base = Base
+
+ /// A type of value the modified atom produces.
+ public typealias Produced = Base?
+
+ #if hasFeature(InferSendableFromCaptures)
+ /// A type representing the stable identity of this modifier.
+ public struct Key: Hashable, Sendable {
+ private let keyPath: any KeyPath & Sendable
+
+ fileprivate init(keyPath: any KeyPath & Sendable) {
+ self.keyPath = keyPath
+ }
+ }
+
+ private let keyPath: any KeyPath & Sendable
+
+ internal init(keyPath: any KeyPath & Sendable) {
+ self.keyPath = keyPath
+ }
+
+ /// A unique value used to identify the modifier internally.
+ public var key: Key {
+ Key(keyPath: keyPath)
+ }
+ #else
+ public struct Key: Hashable, Sendable {
+ private let keyPath: UnsafeUncheckedSendable>
+
+ fileprivate init(keyPath: UnsafeUncheckedSendable>) {
+ self.keyPath = keyPath
+ }
+ }
+
+ private let _keyPath: UnsafeUncheckedSendable>
+ private var keyPath: KeyPath {
+ _keyPath.value
+ }
+
+ internal init(keyPath: KeyPath) {
+ _keyPath = UnsafeUncheckedSendable(keyPath)
+ }
+
+ /// A unique value used to identify the modifier internally.
+ public var key: Key {
+ Key(keyPath: _keyPath)
+ }
+ #endif
+
+ /// A producer that produces the value of this atom.
+ public func producer(atom: some Atom) -> AtomProducer {
+ AtomProducer { context in
+ context.transaction { context in
+ let value = context.watch(atom)
+ let storage = context.watch(StorageAtom())
+
+ if value[keyPath: keyPath] {
+ storage.latest = value
+ }
+
+ return storage.latest
+ }
+ }
+ }
+}
+
+private extension LatestModifier {
+ @MainActor
+ final class Storage {
+ var latest: Base?
+ }
+
+ struct StorageAtom: ValueAtom, Hashable {
+ func value(context: Context) -> Storage {
+ Storage()
+ }
+ }
+}
diff --git a/Tests/AtomsTests/Modifier/LatestModifierTests.swift b/Tests/AtomsTests/Modifier/LatestModifierTests.swift
new file mode 100644
index 00000000..099b4220
--- /dev/null
+++ b/Tests/AtomsTests/Modifier/LatestModifierTests.swift
@@ -0,0 +1,140 @@
+import XCTest
+
+@testable import Atoms
+
+final class LatestModifierTests: XCTestCase {
+ struct Item {
+ let id: Int
+ let isValid: Bool
+ }
+
+ @MainActor
+ func testLatest() {
+ let atom = TestStateAtom(defaultValue: Item(id: 1, isValid: false))
+ let context = AtomTestContext()
+
+ // Initially nil because isValid is false
+ XCTAssertNil(context.watch(atom.latest(\.isValid)))
+
+ // Update with valid item
+ context[atom] = Item(id: 2, isValid: true)
+
+ // Should return the valid item
+ XCTAssertEqual(context.watch(atom.latest(\.isValid))?.id, 2)
+
+ // Update with invalid item
+ context[atom] = Item(id: 3, isValid: false)
+
+ // Should still return the last valid item
+ XCTAssertEqual(context.watch(atom.latest(\.isValid))?.id, 2)
+
+ // Update with another valid item
+ context[atom] = Item(id: 4, isValid: true)
+
+ // Should return the new valid item
+ XCTAssertEqual(context.watch(atom.latest(\.isValid))?.id, 4)
+
+ // Update with invalid item again
+ context[atom] = Item(id: 5, isValid: false)
+
+ // Should still return the last valid item
+ XCTAssertEqual(context.watch(atom.latest(\.isValid))?.id, 4)
+ }
+
+ @MainActor
+ func testLatestWithMultipleWatchers() {
+ let atom = TestStateAtom(defaultValue: Item(id: 1, isValid: false))
+ let context = AtomTestContext()
+
+ // Watch both current and latest
+ XCTAssertEqual(context.watch(atom).id, 1)
+ XCTAssertNil(context.watch(atom.latest(\.isValid)))
+
+ // Update with valid item
+ context[atom] = Item(id: 2, isValid: true)
+
+ XCTAssertEqual(context.watch(atom).id, 2)
+ XCTAssertEqual(context.watch(atom.latest(\.isValid))?.id, 2)
+
+ // Update with invalid item
+ context[atom] = Item(id: 3, isValid: false)
+
+ XCTAssertEqual(context.watch(atom).id, 3)
+ XCTAssertEqual(context.watch(atom.latest(\.isValid))?.id, 2)
+ }
+
+ @MainActor
+ func testLatestUpdatesDownstream() {
+ let atom = TestStateAtom(defaultValue: Item(id: 1, isValid: false))
+ let context = AtomTestContext()
+ var updatedCount = 0
+
+ context.onUpdate = {
+ updatedCount += 1
+ }
+
+ // Initial watch
+ XCTAssertEqual(updatedCount, 0)
+ XCTAssertNil(context.watch(atom.latest(\.isValid)))
+
+ // Update with valid item - should trigger update
+ context[atom] = Item(id: 2, isValid: true)
+ XCTAssertEqual(updatedCount, 1)
+ XCTAssertEqual(context.watch(atom.latest(\.isValid))?.id, 2)
+
+ // Update with invalid item - should still trigger update
+ context[atom] = Item(id: 3, isValid: false)
+ XCTAssertEqual(updatedCount, 2)
+ XCTAssertEqual(context.watch(atom.latest(\.isValid))?.id, 2)
+
+ // Update with another valid item - should trigger update
+ context[atom] = Item(id: 4, isValid: true)
+ XCTAssertEqual(updatedCount, 3)
+ XCTAssertEqual(context.watch(atom.latest(\.isValid))?.id, 4)
+ }
+
+ @MainActor
+ func testKey() {
+ let modifier1 = LatestModifier- (keyPath: \.isValid)
+ let modifier2 = LatestModifier
- (keyPath: \.isValid)
+
+ XCTAssertEqual(modifier1.key, modifier2.key)
+ XCTAssertEqual(modifier1.key.hashValue, modifier2.key.hashValue)
+ }
+
+ @MainActor
+ func testLatestWithBoolValue() {
+ let atom = TestStateAtom(defaultValue: true)
+ let context = AtomTestContext()
+
+ // Initially should return the value if it's true
+ XCTAssertEqual(context.watch(atom.latest(\.self)), true)
+
+ // Update to false
+ context[atom] = false
+
+ // Should still return the last true value
+ XCTAssertEqual(context.watch(atom.latest(\.self)), true)
+
+ // Update to true again
+ context[atom] = true
+
+ // Should return the new true value
+ XCTAssertEqual(context.watch(atom.latest(\.self)), true)
+ }
+
+ @MainActor
+ func testLatestWithInitialValidValue() {
+ let atom = TestStateAtom(defaultValue: Item(id: 1, isValid: true))
+ let context = AtomTestContext()
+
+ // Should immediately return the initial valid value
+ XCTAssertEqual(context.watch(atom.latest(\.isValid))?.id, 1)
+
+ // Update with invalid item
+ context[atom] = Item(id: 2, isValid: false)
+
+ // Should still return the initial valid value
+ XCTAssertEqual(context.watch(atom.latest(\.isValid))?.id, 1)
+ }
+}