RecoilSwift
RecoilSwift copied to clipboard
A New, Functional, Modern Reactive State Management Library for UIKit and SwiftUI (The iOS implementation of Recoil)
RecoilSwift
:closed_book: 中文文档
RecoilSwift is a lightweight & reactive swift state management library. RecoilSwift is a SwiftUI implementation of recoil.js which powered by Facebook.
RecoilSwift is an alternate option to replace of the Redux(reswift/tca)
or MVVM
.
What is recoil
State Management Data Flow
In recoil, there are mainly two concepts: atom
and selector
. atom
is the primitive data(sync/async), selector
is derived data(sync/async).
generally we put the business logic & UI login into selector.
- Recoil state is atomic, you can easily to compose and reuse state
- Recoil state is reactive. current selector will be recomputed when any of upstream state changed
- Recoil is shared, you can easy to reuse it in different component。
The tree pillar is really important. this is why recoil
let you code more concise and more reusable.
Requirements
- iOS 13+
- Xcode 13.2+
NOTE: Currently this library only support for SwiftUI
In recent release, we re-implement this library with react hooks pattern which making the usage of this lib is more similar with official way.
Installation
- In Xcode, open your project and navigate to File → Swift Packages → Add Package Dependency...
- Paste the repository URL (
https://github.com/hollyoops/RecoilSwift.git
) and click Next. - For Rules, select Branch (with branch set to
master
). - Click Finish.
RecoilSwift is available through CocoaPods. To install it, simply add the following line to your Podfile:
pod 'RecoilSwift'
Basic Usage
Create Atom / Selector:
// Create a Atom
let allBooksState = atom { [Book]() }
// Create readonly Selector
let currentBooksSelector = selector { get -> [Book] in
let books = get(allBooksState)
if let category = get(selectedCategoryState) {
return books.filter { $0.category == category }
}
return books
}
// Create parameterized selector
let someSelector = selectorFamily { (id: String, get: Getter) -> AnyPublisher<[String], Error> in
// Do some logic in here with id
}
Use Atom / Selector in SwiftUI
Because the useRecoilXXX
series API is based on Hooks. so it should follow all the rule of hooks
struct YourView: RecoilView { // You have to implement the RecoilView protocol
var hookBody: some View {
let currentBooks = useRecoilValue(currentBooksSelector)
let allBooks = useRecoilState(allBooksStates)
let loadable = useRecoilValueLoadable(fetchRemoteDataByID(someID))
// Your UI Code
}
}
Advance Usage
You can use atomFamily/selectorFamily
to execute the async tasks with customized parameter.
Async task above iOS 15
let fetchRemoteDataById = atomFamily { (id: String, get: Getter) async -> [String] in
let posts = await fetchAllData()
return posts[id]
}
// In some function
func someView() -> some View {
HookScope { // when your view is not implement with RecoilView, you have to use `HookScope`
let id = useRecoilValue(selectedCategoryState)
let loadable = useRecoilValueLoadable(fetchRemoteDataById(id))
// This body will be render after task completed
return VStack {
// while loading
if loadable.isLoading {
ProgressView()
}
// when error
if let err = loadable.errors.first {
errorView(err)
}
// when data fulfill
if let names = loadable.data {
dataView(allBook: names, onRetry: loadable.load)
}
}
}
}
Below iOS 15 you can use Combine to run async tasks...
let fetchRemoteDataById = selectorFamily { (id: String, get: Getter) -> AnyPublisher<[String], Error> in
Deferred {
Future { promise in
// Do some logic in here with id
}
}.eraseToAnyPublisher()
}
Documentation
- Core concepts
- Atoms
- Selectors
- Loadable
- Hooks
API Reference
-
State
- atom()
-
selector()
- Readonly selector
- Writeable selectors
- Async selectors
-
Utils & Hooks
- useRecoilValue()
- useRecoilState()
- useRecoilCallback()
- useRecoilValueLoadable()
- atomFamily()
- selectorFamily()
Example
This is a easy demo, but we highly recommend you to check out the Example
code. You'll see sharing states between different components is super easy. and the code become quite concise.
TODOs
- [ ] [performance]Remove unused recoil value in the store.
- [ ] [feature]Make UIKit compatible
Reference:
-
Facebook Recoil (Recoil.js)
-
Recoil for Android
-
Hooks