📕 中文文档
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.
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.
- 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.
- 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'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
}
}You can use atomFamily/selectorFamily to execute the async tasks with customized parameter.
Async task
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)
}
}
}
}You also 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()
}-
State
-
Utils & Hooks
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.
- [performance]Remove unused recoil value in the store.
- [feature]Make UIKit compatible
-
Facebook Recoil (Recoil.js)
-
Recoil for Android
-
Hooks


