diff --git a/README.md b/README.md
index a4161973..c96df35f 100644
--- a/README.md
+++ b/README.md
@@ -683,6 +683,45 @@ struct ContactView: View {
Modifiers can be applied to an atom to produce a different versions of the original atom to make it more coding friendly or to reduce view re-computation for performance optimization.
+#### [previous](https://ra1028.github.io/swiftui-atom-properties/documentation/atoms/atom/previous)
+
+| |Description|
+|:--------------|:----------|
+|Summary |Provides the previous value of the atom instead of the current value.|
+|Output |`T?`|
+|Compatible |All atom types.|
+|Use Case |Track value changes, Compare previous and current values|
+
+📖 Example
+
+```swift
+struct CounterAtom: StateAtom, Hashable {
+ func defaultValue(context: Context) -> Int {
+ 0
+ }
+}
+
+struct CounterView: View {
+ @WatchState(CounterAtom())
+ var currentValue
+
+ @Watch(CounterAtom().previous)
+ var previousValue
+
+ var body: some View {
+ VStack {
+ Text("Current: \(currentValue)")
+ Text("Previous: \(previousValue ?? 0)")
+ Button("Increment") {
+ currentValue += 1
+ }
+ }
+ }
+}
+```
+
+
+
#### [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 e8643a34..0ffbd6d8 100644
--- a/Sources/Atoms/Atoms.docc/Atoms.md
+++ b/Sources/Atoms/Atoms.docc/Atoms.md
@@ -28,6 +28,7 @@ Building state by compositing atoms automatically optimizes rendering based on i
### Modifiers
+- ``Atom/previous``
- ``Atom/changes``
- ``Atom/changes(of:)``
- ``Atom/animation(_:)``
@@ -84,6 +85,7 @@ Building state by compositing atoms automatically optimizes rendering based on i
- ``AtomStore``
- ``AtomModifier``
- ``AsyncAtomModifier``
+- ``PreviousModifier``
- ``ChangesModifier``
- ``ChangesOfModifier``
- ``TaskPhaseModifier``
diff --git a/Sources/Atoms/Modifier/PreviousModifier.swift b/Sources/Atoms/Modifier/PreviousModifier.swift
new file mode 100644
index 00000000..f64d9c16
--- /dev/null
+++ b/Sources/Atoms/Modifier/PreviousModifier.swift
@@ -0,0 +1,75 @@
+public extension Atom {
+ /// Provides the previous value of the atom instead of the current value.
+ ///
+ /// ```swift
+ /// struct CounterAtom: StateAtom, Hashable {
+ /// func defaultValue(context: Context) -> Int {
+ /// 0
+ /// }
+ /// }
+ ///
+ /// struct ExampleView: View {
+ /// @Watch(CounterAtom())
+ /// var currentValue
+ ///
+ /// @Watch(CounterAtom().previous)
+ /// var previousValue
+ ///
+ /// var body: some View {
+ /// VStack {
+ /// Text("Current: \(currentValue)")
+ /// Text("Previous: \(previousValue ?? 0)")
+ /// }
+ /// }
+ /// }
+ /// ```
+ ///
+ var previous: ModifiedAtom> {
+ modifier(PreviousModifier())
+ }
+}
+
+/// A modifier that provides the previous value of the atom instead of the current value.
+///
+/// Use ``Atom/previous`` instead of using this modifier directly.
+public struct PreviousModifier: 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?
+
+ /// A type representing the stable identity of this atom associated with an instance.
+ public struct Key: Hashable, Sendable {}
+
+ /// A unique value used to identify the modifier internally.
+ public var key: Key {
+ Key()
+ }
+
+ /// 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())
+ let previous = storage.previous
+ storage.previous = value
+ return previous
+ }
+ }
+ }
+}
+
+private extension PreviousModifier {
+ @MainActor
+ final class Storage {
+ var previous: Base?
+ }
+
+ struct StorageAtom: ValueAtom, Hashable {
+ func value(context: Context) -> Storage {
+ Storage()
+ }
+ }
+}
diff --git a/Tests/AtomsTests/Modifier/PreviousModifierTests.swift b/Tests/AtomsTests/Modifier/PreviousModifierTests.swift
new file mode 100644
index 00000000..e2e4bf4b
--- /dev/null
+++ b/Tests/AtomsTests/Modifier/PreviousModifierTests.swift
@@ -0,0 +1,87 @@
+import XCTest
+
+@testable import Atoms
+
+final class PreviousModifierTests: XCTestCase {
+ @MainActor
+ func testPrevious() {
+ let atom = TestStateAtom(defaultValue: "initial")
+ let context = AtomTestContext()
+
+ XCTAssertNil(context.watch(atom.previous))
+
+ // Update the atom value
+ context[atom] = "second"
+
+ // Now previous should return the initial value
+ XCTAssertEqual(context.watch(atom.previous), "initial")
+
+ // Update again
+ context[atom] = "third"
+
+ // Previous should now return "second"
+ XCTAssertEqual(context.watch(atom.previous), "second")
+
+ // Another update
+ context[atom] = "fourth"
+
+ // Previous should now return "third"
+ XCTAssertEqual(context.watch(atom.previous), "third")
+ }
+
+ @MainActor
+ func testPreviousWithMultipleWatchers() {
+ let atom = TestStateAtom(defaultValue: 100)
+ let context = AtomTestContext()
+
+ // Watch both current and previous
+ XCTAssertEqual(context.watch(atom), 100)
+ XCTAssertNil(context.watch(atom.previous))
+
+ // Update the value
+ context[atom] = 200
+
+ // Check both watchers
+ XCTAssertEqual(context.watch(atom), 200)
+ XCTAssertEqual(context.watch(atom.previous), 100)
+
+ // Update again
+ context[atom] = 300
+
+ XCTAssertEqual(context.watch(atom), 300)
+ XCTAssertEqual(context.watch(atom.previous), 200)
+ }
+
+ @MainActor
+ func testPreviousUpdatesDownstream() {
+ let atom = TestStateAtom(defaultValue: 0)
+ let context = AtomTestContext()
+ var updatedCount = 0
+
+ context.onUpdate = {
+ updatedCount += 1
+ }
+
+ // Initial watch
+ XCTAssertEqual(updatedCount, 0)
+ XCTAssertNil(context.watch(atom.previous))
+
+ // First update
+ context[atom] = 1
+ XCTAssertEqual(updatedCount, 1)
+ XCTAssertEqual(context.watch(atom.previous), 0)
+
+ // Second update
+ context[atom] = 2
+ XCTAssertEqual(updatedCount, 2)
+ XCTAssertEqual(context.watch(atom.previous), 1)
+ }
+
+ @MainActor
+ func testKey() {
+ let modifier = PreviousModifier()
+
+ XCTAssertEqual(modifier.key, modifier.key)
+ XCTAssertEqual(modifier.key.hashValue, modifier.key.hashValue)
+ }
+}