zustand를 써보려고 했는데 완벽한 래퍼 라이브러리가 없다보니 사용하기 매우 불편하다.
그래서 래퍼를 만들려고 했는데 타입스크립트의 타입추론을 코틀린에서 구현할 수 없어서 포기했다.
그래서 코루틴을 쓰려고 했는데 이게 Kotlin/JS 에서도 정상으로 작동할 지 확인하기 귀찮다.
그래서 object를 이용해서 구현하려 한다.
리액트 Context를 사용하면 자식 컴포넌트들에도 같은 컨텍스트를 제공할 수 있으므로 이걸 사용합시다.
package utils
import react.*
data class StateContextData<TState>(
var state: TState,
var setState: StateSetter<TState>
)
abstract class StateContextHolder<TState>(private val key: String) {
private lateinit var context: Context<StateContextData<TState>>
fun useProvider(initialState: TState): FC<PropsWithChildren> {
val (state, setState) = useState(initialState)
val stateContext = StateContextData(state, setState)
context = createContext(stateContext)
return FC { props ->
context.Provider {
value = stateContext
+props.children
}
}
}
fun useSelector(): TState {
return useContext(context).state
}
fun <U> useSelector(selector: (TState) -> U): U {
return useContext(context).state.let(selector)
}
fun useSetState(): StateSetter<TState> {
return useContext(context).setState
}
}
그래서 어떤 식으로 쓸까 예시로는 카운터가 최고지
package states
import utils.StateContextHolder
data class CounterState(val count: Int)
object CounterStateContextHolder : StateContextHolder<CounterState>("Counter")
import react.FC
import react.create
import react.dom.client.createRoot
import react.dom.html.ReactHTML.button
import react.dom.html.ReactHTML.h1
import states.CounterState
import states.CounterStateContextHolder
import web.dom.document
fun main() {
val root = document.getElementById("root")!!
createRoot(root).render(App.create())
}
val App = FC {
val counterStateContextProvider = CounterStateContextHolder.useProvider(CounterState(0))
counterStateContextProvider {
CountViewer()
Buttons()
}
}
val CountViewer = FC {
val count = CounterStateContextHolder.useSelector { it.count }
h1 {
+"Count : $count"
}
}
val Buttons = FC {
val setState = CounterStateContextHolder.useSetState()
button {
onClick = {
setState { state ->
state.copy(count = state.count + 1)
}
}
+"Increase"
}
button {
onClick = {
setState { state ->
state.copy(count = state.count - 1)
}
}
+"Decrease"
}
}
이렇게 하니 잘 작동한다.
끗
답글 남기기