μ΅κ·Ό λͺ λ μ¬μ΄ λ°μν νλ‘κ·Έλλ°(Reactive Programming)μ΄λΌλ κ°λ μ΄ μΉ νλ°νΈμλ κ°λ° λΆμΌμ λ§μ΄ μ€λ©°λ€μλ€. Vue.jsκ° λνμ μΌλ‘ λ°μν νλ μμν¬λ‘ μλ €μ ΈμμΌλ©°, μ΅κ·Όμλ Svelteκ° λ§μ΄ μΈκΈλκ³ μλ€. Angularλ λνμ μΈ λ°μν νλ‘κ·Έλλ° λΌμ΄λΈλ¬λ¦¬ RxJSλ₯Ό νΌμ΄ μμ‘΄μ±(Peer Dependency)μΌλ‘ λκ³ μμΌλ©°, μ΄λ₯Ό νμ©νμ¬ λ°μν νλ‘κ·Έλλ°μ΄ κ°λ₯νλλ‘ μ€κ³λμ΄μλ€.
κ·Έλ¦¬κ³ Reactλ₯Ό λΉΌλμΌλ©΄ μμνλ°, Reactλ μλ°ν λ§ν΄ λ°μν λΌμ΄λΈλ¬λ¦¬κ° μλλ€. λ€λ§ Reactμ ν¨κ» λ§μ΄ νμ©νκ³ μλ μν κ΄λ¦¬ λΌμ΄λΈλ¬λ¦¬ μ€ MobXκ° λ°μν νλ‘κ·Έλλ°μ΄ μ μ©λ λΌμ΄λΈλ¬λ¦¬λ‘ μ μλ €μ Έ μλ€. (Reactμ λ°μμ±(Reactivity)μ λν μ£Όμ λ μ΄λ² κΈμμ μ΄μΌκΈ°νκ³ μ νλ λ΄μ©μ λ²μ΄λκΈ° λλ¬Έμ κΉκ² μΈκΈνμ§ μλλ€.)
"ν μμμλ Reactκ° μμ ν 'λ°μν'μ΄ λλ € νμ§ μκΈ° λλ¬Έμ 'Schedule'λ‘ λΆλ €μΌ νλ€λ λλ΄μ ν©λλ€."(There is an internal joke in the team that React should have been called βScheduleβ because React does not want to be fully βreactiveβ.) -- https://reactjs.org/docs/design-principles.html#scheduling
λ°μν λΌμ΄λΈλ¬λ¦¬ μ€ μμ§ μΈκΈνμ§ μμ κ²μ΄ μμΌλ, λ°λ‘ μ€λ μ΄μΌκΈ°ν SolidJSμ΄λ€. μ΄ λΌμ΄λΈλ¬λ¦¬λ κ°λ°μ΄ μμλ μ§ 5λ μ΄ λμμ§λ§, 2021λ State of JS μ€λ¬ΈμμμΌ μ²μ μμ λͺ©λ‘μ λͺ¨μ΅μ λλ¬λλ€. κ·Έλ¦¬κ³ μ€λ¬Έμ μ°Έμ¬ν μ¬λλ€μ λ§μ‘±λ μμ μ€ 1μλ₯Ό λ¬μ±νλ€. νμλ SolidJS νΉμ§κ³Ό μ΄ λΌμ΄λΈλ¬λ¦¬κ° μΆκ΅¬νλ λ°μν λͺ¨λΈμ μ΄ν΄λ³΄λ©΄μ, λ°μν νλ‘κ·Έλλ°μ κ°λ μ λ€μ λμλ³΄κ² λμλ€.
μ΄λ² κΈμ ν΅ν΄ λ°μν νλ‘κ·Έλλ°μ κ°λ μ κ°λ³κ² μ΄ν΄λ³Έ ν ꡬν λ°©μμ ν ννμΈ 'ν¬λͺ ν λ°μν νλ‘κ·Έλλ°(Transparent Reactive Programming, TRP)'μ μμλ³Έλ€. κ·Έλ¦¬κ³ ν¬λͺ ν λ°μν νλ‘κ·Έλλ°μ κ°λ μ΄ μ μ©λ SolidJSμ λ°μν λͺ¨λΈκ³Ό SolidJSμ λ λλ§ νΉμ§μ κ°λ¨ν μκ°νλ€.
λ°μν νλ‘κ·Έλλ°μ μ€λͺ νκ³ μ νλ μλ£λ λ¬΄μ² λ§μ§λ§ μ½κ² μλΏλ μλ£λ κ·Έλ κ² λ§μ§ μμλ€. κ·Έλλ§ μ§§κ² μμ½νμλ©΄ μλμ κ°μ΄ ννν μ μμ κ²μ΄λ€.
"λ°μν νλ‘κ·Έλλ°μ λ°μ΄ν° μ€μ¬μ μ΄λ²€νΈ μ΄λ―Έν° μμ λ§λ€μ΄μ§ μ μΈμ νλ‘κ·Έλλ° ν¨λ¬λ€μμ΄λ€.(Reactive Programming is a declarative programming paradigm built on data-centric event emitters.)" -- Ryan Carniato(SolidJSμ μ μμ)
μ¬κΈ°μ "μ μΈμ νλ‘κ·Έλλ° ν¨λ¬λ€μ"κ³Ό "λ°μ΄ν° μ€μ¬μ μ΄λ²€νΈ μ΄λ―Έν°" λΌλ λ κ°μ§ ν¬μΈνΈκ° μλ€. κ°λ¨νκ² νλμ© μ§μ΄λ³΄λ©΄
μμ μμ½μ λ°λΌ λ°μν νλ‘κ·Έλλ°μ΄ μ μ©λ λνμ μΈ μλ₯Ό μ΄ν΄λ³΄μ. λ°λ‘ μ€νλ λμνΈμ΄λ€.
μΆμ²: What is Functional Reactive Programming (FRP)?
A2μ μ κ·Έμ "B2μ μ κ°κ³Ό C2μ μ ν©μ νννλ€"λΌλ μ μΈμ μΈ ννλ§ μμ±λμ΄μμ λΏμ΄λ€. μ°λ¦¬κ° μ΄λ»κ² B2 μ κ³Ό C2 μ μμ κ°μ κΊΌλ΄μ κ³μ°ν μ§ λ±μ λͺ μμ μΌλ‘ νννμ§ μμλ€. B2λ C2μ μ λ³κ²½μ¬νμ μλμΌλ‘ μ νλμ΄ A2μ κ°μ λ°μλ κ²μ΄λ€.
λ λμκ° 'μ΄λ²€νΈλ‘λΆν° μμνμ¬ μκ°μ λ°λΌ λ³νλ κ°μ κ΄κ³λ₯Ό μ μΈμ μΌλ‘ νννλ€' λ κ°λ μ ꡬνν λνμ μΈ κ΅¬νμ²΄κ° ReactiveX(Rx)μ΄λ€. Rxλ μ΄λ²€νΈλ₯Ό λΉλκΈ° μ€νΈλ¦ΌμΌλ‘ λ°κΎΈκ³ , λ€μν μ€νΌλ μ΄ν°λ₯Ό μ μ©νλ©° μ΄ μ€νΈλ¦ΌμΌλ‘ 무μμ νκ³ μ νλμ§ μ μΈμ μΌλ‘ νννλ€.
μΆμ²: The introduction to Reactive Programming you've been missing
μμ μ΄λ―Έμ§μ κ°μ΄ λλΈ ν΄λ¦ μ΄μμ μ΄λ²€νΈλ₯Ό μμ νλ νλ¦μ λͺ μ€μ μ½λλ‘, κ·Έλ¦¬κ³ μ μΈμ μΌλ‘ λ§λ€μ΄λΌ μ μλ€. κ·Έλ°λ° μ μ°λ¦¬κ° μ΄λ° λ°©μμ λ°μν νλ‘κ·Έλλ°μ μ νμκ° μμκΉ? λ°λ‘ UIλ₯Ό ꡬμ±νλλ° μ μ©νκΈ° λλ¬Έμ΄λ€.
μ°λ¦¬κ° μ¬μ©μμκ² μ 곡νλ UIλ μΈμ μΌμ΄λ μ§ μ μ μλ κ±°λν μ΄λ²€νΈ νΈλ¦¬κ±° λμΉλ λ€λ¦μλ€. λ€μν μνΈμμ©μ΄ μ€μκ°μΌλ‘ μΌμ΄λλ©΄μ κ·Έ μνΈμμ©μ κ²°κ³Όλ₯Ό νμνλ λΉμ¦λμ€ λ‘μ§μ μμ±ν λ, ν¨κ³Όμ μΌλ‘ μ΄λ²€νΈλ₯Ό μ²λ¦¬νλ μ½λλ₯Ό κ°λ μ± μκ² μ μ¬μ μμ μμ±νκΈ°λ μ½μ§ μμ μΌμ΄λ€. νμ§λ§ λ°μν νλ‘κ·Έλλ°μ ν΅ν΄ μ½λμ μΆμν λ¨κ³λ₯Ό λμ΄μ¬λ € ꡬν λ°©λ² κ·Έ μ체λ₯Ό κ³ λ―Όνλ κ²λ³΄λ€ λΉμ¦λμ€ λ‘μ§μ μ μΈμ μΌλ‘ νννλ κ²μ λ μ§μ€ν μ μκ² λλ€.
νμ§λ§ μ€νΈλ¦Ό κΈ°λ°μ λ°μν νλ‘κ·Έλλ°μ λ¬λ 컀λΈκ° λκ³ , λ¬Έμ κ° λ°μνμ λ λλ²κΉ μ΄ μ΄λ ΅λ€λ λ¨μ μ΄ μμ£Ό μΈκΈλμ΄μλ€. μ€νΈλ¦Ό κΈ°λ°μ λ°μν νλ‘κ·Έλ¨ μΈμ λ§μ΄ μλ €μ§ ννμ λ°μν νλ‘κ·Έλλ° λ°©μμ΄ λ°λ‘ μ΄λ²μ μ΄μΌκΈ°ν Transparent Reactive Programming(TRP)μ΄λ€.
'Transparent' λ ν¬λͺ ν, νΉμ λͺ μΎνμ΄λ λ»μΌλ‘ λ³λμ μ½λ λ³κ²½ μμ΄ λ°μν νλ‘κ·Έλλ°μ΄ μ΄λ£¨μ΄μ§λ κ²μ΄λΌλ μλ―Έλ€. μ€νΈλ¦Όκ³Ό μ€νΌλ μ΄ν° λμ μλμΌλ‘ μΆμ κ³μ°μ΄ κ°λ₯ν λ°μ΄ν°λ₯Ό κΈ°λ°μΌλ‘ μ΄λ£¨μ΄μ Έ μμΌλ©°, λ°μ΄ν°μ λ³κ²½ μ¬νμ μ ννμ¬ νμλ κ°μ νμ±νκ³ κΆκ·Ήμ μΌλ‘ λΆμ ν¨κ³Όλ μΌμΌν¨λ€.
μ΄λ° λ°©μμ μ°¨μ©ν λΌμ΄λΈλ¬λ¦¬ νΉμ νλ μμν¬λ‘ MobX, Vue.js, SolidJS, Svelte λ±μ΄ μλ€. TRPλ μ€νΈλ¦Ό κΈ°λ°μ λ°μν νλ‘κ·Έλλ°λ³΄λ€ λΉκ΅μ λ¨μνκ² λμνλ©΄μ, μ μ¬μ μΌλ‘ μ‘΄μ¬νλ λΆμ μμλ μ μ΄ν μ μλ€.
μ΄λ€ λ©΄μμ TRPλ λΉκ΅μ λ¨μνκ², κ·Έλ¦¬κ³ ν¬λͺ νκ² λμνλ€κ³ λ³Ό μ μμκΉ? TRPμ κΈ°λ³Έ κ΅¬μ± μμλ₯Ό μ΄ν΄λ³΄λ©° μ€λ§λ¦¬λ₯Ό μ°Ύμ보μ.
TRPμ Primitive(μΌλ°μ μΈ νλ‘κ·Έλλ° μΈμ΄μ μμ νμ κ³Ό μ μ¬νμ§λ§, λμΌν κ°λ μ μλλΌκ³ νλ¨νμ¬ μ΄ κΈμμλ κΈ°λ³Έ κ΅¬μ± μμλΌλ μ©μ΄λ₯Ό μ¬μ©νλ€.)λ ν¬κ² λ κ°μ§κ° μλ€. Observable(μ΅μ λ²λΈ), κ·Έλ¦¬κ³ Reaction(λ°μ)μ΄λ€.
λ¨Όμ μ΅μ λ²λΈμ κ΄μΈ‘ κ°λ₯ν κ°μΌλ‘μ κ·Έ κ°μ μ‘°ννλ Subscriber(ꡬλ
μ)λ₯Ό κ΄λ¦¬νκ³ , κ°μ΄ λ³κ²½λ λ λ³κ²½ μ¬νμ ꡬλ
μμκ² μ ννλ μν μ νλ€. λ€μν λΌμ΄λΈλ¬λ¦¬μμ Atom, Signal, Ref λ±μ κ°κΈ° λ€λ₯Έ μ©μ΄λ₯Ό μ¬μ©νμ§λ§ κ°λ
μ λμΌνλ€. μλ°μ€ν¬λ¦½νΈλ‘ μ΅μ λ²λΈμ ꡬνν λ ES6 Proxyλ₯Ό μ¬μ©νκ±°λ μ§μ Object.defineProperty
μ¬μ©νμ¬ κ°μ²΄μ μμ±μ μ€λ²λΌμ΄λνλ λ°©μμΌλ‘ ꡬννλ€. μμΈν ꡬν μ리λ μλμ κΈμ μ°Έκ³ νλΌ.
μλλ Proxy κΈ°λ°μ μ΅μ λ²λΈμ ꡬννλ μ½λ μΌλΆμ΄λ€. λνμ μΌλ‘ MobXλ λ²μ 5λΆν°, Vueλ λ²μ 3λΆν° Proxyλ₯Ό μ¬μ©νμ¬ μ΅μ λ²λΈμ ꡬννκ³ μλ€.
function observable(data) {
const handler = {
get: function(target, key, receiver) {
// ꡬλ
μλ₯Ό λ±λ‘νλ€.
// ...
return Reflect.get(target, key, receiver);
},
set: function(target, key, value, receiver) {
// κ°μ λ³κ²½μ ꡬλ
μμκ² μλ¦°λ€.
// ...
return Reflect.set(target, key, value, receiver);
}
};
return new Proxy(data, handler);
}
λ°μμ μ΅μ λ²λΈ κ°μ΄ λ³νλ λ νΉμ λμμ μννλ κ²μ΄λ©° λ κ°μ§ ννλ‘ λλλ€. μ΅μ λ²λΈ κ°μ κΈ°λ°μΌλ‘ νμλ κ°μ 리ν΄νλ Derivation(νμ, νΉμ Computed)κ³Ό, κ΄μ°°νκ³ μλ κ°μ΄ λ³κ²½λ λλ§λ€ μ¬μ΄λ μ΄ννΈλ₯Ό μ€ννλ Effect(μ΄ννΈ)μ΄λ€.
μ΄ννΈλ ν¨μλ₯Ό μΈμλ‘ λ°μ κ·Έ ν¨μ μμμ μ¬μ©λλ μ΅μ λ²λΈ κ°μ λ³νκ° λ°μν λλ§λ€ μΈμλ‘ λ°μ ν¨μλ₯Ό μ€ννλ κ²μ΄λ€. μ΅μ λ²λΈ κ°μ΄ μλ€ νλλΌλ κ·Έ κ°μ΄ λ³κ²½λ λλ§λ€ 무μμ ν΄μΌ ν μ§ λ§€λ² μ½λλ₯Ό μμ±ν΄μ£Όλ κ²μ΄ μλλΌ, λ³νκ° λ°μν λλ§λ€ μλμΌλ‘ μ€νλλ λΆμ ν¨κ³Όλ₯Ό ν΅ν΄ UIμ λμμ ν¨κ³Όμ μΌλ‘ κ΄λ¦¬ν μ μκ² λλ€. MobXμ autorun
, Vueμ watch
λ±μ΄ λνμ μΈ μμ΄λ€.
// observable κ°μ ν΅ν΄ document.titleμ λ³κ²½νλ μ.
const user = observable({ username: 'iamironman', fullname: 'Tony Stark' });
effect(() => {
// μ΄ννΈλ μ΅μ΄μ ν λ² μ€νλκ³ , μ΄ν user.fullname κ°μ΄ λ³νλ λλ§λ€ μλμΌλ‘ λ€μ νΈμΆλλ€.
document.title = user.fullname;
});
user.fullname = 'Riri Williams';
// νμ΄ν λ³κ²½λ¨
Reactμ μ΅μνλ€λ©΄ useEffect
ν
μ νμ©ν μ½λμ λΉμ·ν ννλ‘ λ³΄μΌ μ μλ€. useEffect ν
κ³Ό λ¬λ¦¬ TRPμ λ°μμ μ΄λ€ μ΅μ λ²λΈ κ°μ μΆμ νκ³ μλμ§ μλμΌλ‘ κ΄λ¦¬νλ€. μ΄λ₯Ό μν΄ μ΄ννΈλ λ§€λ² κ΄μ°° μ€μΈ μ΅μ λ²λΈ κ°μ΄ λ°λ λλ§λ€ μμ μ΄ μ΄λ€ κ°μ μμ‘΄νκ³ μλμ§ μ¬νκ°νλ κ³Όμ μ κ±°μΉλ€. μ΄ λμμ κΈ°λ°μΌλ‘ μ΅κ·Όμ λ°μν λΌμ΄λΈλ¬λ¦¬λ 'μλμΌλ‘ μμ‘΄μ±μ νμ
νλ(Automatic Dependency Detection)' λ¨κ³μ μ΄λ₯Ό μ μκ² λμλ€.
λ§μ§λ§μΌλ‘ νμμ κΈ°λ³Έμ μΌλ‘ μ΄ννΈμ λμΌν λμμ νμ§λ§ κ°μ 리ν΄νλ€λ νΉμ§μ΄ μλ€. κ±°κΈ°μ κ²°κ³Όκ°μ λ©λͺ¨μ΄μ μ΄μ
νμ¬ λΆνμν μΆκ° κ³μ°μ λ°©μ§νκ³ , μ€μ§μ μΌλ‘ μ‘°νλ λκΉμ§ μ΅μ λ²λΈ κ°μ νμμ΄ μΌμ΄λμ§ μλλ‘ μ§μ° νκ°λ₯Ό ν μλ μλ€. λνμ μΈ μλ‘ MobXμ computed
κ° μλ€.
// μ€νλ λμνΈλ₯Ό μμν΄λ³΄μ. C1μλ A1 * B1μ΄λΌλ ν¨μλ₯Ό μ§μ ν΄λμλ€.
const A1 = observable({ value: 1 });
const B1 = observable({ value: 15 });
// μ΅μ΄μ ν λ² νκ°λ λ€ κ΄μ°°νκ³ μλ κ°μ΄ λ³νλ λκΉμ§λ μΊμ±λ κ°μ 리ν΄νλ€.
const C1 = computed(() => A1.value * B1.value);
console.log(C1.get()); // 15
console.log(C1.get()); // 15
A1.value = 2;
console.log(C1.get()); // 30
SolidJSλ₯Ό λΉλ‘―ν λ€μν λΌμ΄λΈλ¬λ¦¬λ TRP κΈ°λ³Έ κ΅¬μ± μμλ₯Ό μ μ ν μ‘°ν©νμ¬ Fine-Grained Reactivity(μκ² λλμ΄μ§ λ°μμ±)λ₯Ό ꡬμΆνκ³ ν¨κ³Όμ μΌλ‘ κ°μ΄ λ³κ²½λ λΆλΆλ§ μ λ°μ΄νΈνλ κ²μ μΆκ΅¬νλ€. μ΅μ λ²λΈ κ°μ νλμ λ Έλλ‘ λ³΄κ³ , λ Έλ μ¬μ΄μ μ°κ²°μ μ΄μ΄νκ² κ΅¬μ±λ κ·Έλνλ₯Ό λ§λ€μ΄ νΉμ λΆλΆμ΄ λ³κ²½λλ©΄ μ°κ΄λ λ€λ₯Έ λ Έλλ λ°μνμ¬ λ€μ κ°μ΄ νκ°λλλ‘ κ΅¬μ±νλ κ²μ΄λ€.
μΆμ²: Becoming fully reactive: an in-depth explanation of MobX
SolidJSλ μμ μΈκΈν TRPμ κΈ°λ³Έ ꡬμ±μμλ‘ λ°μν λͺ¨λΈμ ꡬμΆνμλ€. μ΅μ λ²λΈμ μν μ νλ Signal, λΆμ ν¨κ³Όλ₯Ό μ²λ¦¬νλ Effect, νμ κ°μ λ€λ£¨λ Memoκ° μλ€. κ°κ° createSignal
, createEffect
, createMemo
λ₯Ό ν΅ν΄ λ§λ€μ΄λΈλ€. SolidJSμμ μ΅μ λ²λΈμ μ 곡νλ κΈ°λ³Έ APIμΈ createSignal
μ κ°λ¨ν ννλ‘ μ§μ ꡬνν΄λ³΄μ.
const runningContext = [];
function subscribe(running, subscriptions) {
subscriptions.add(running);
running.dependencies.add(subscriptions);
}
function createSignal(value) {
const subscriptions = new Set();
const read = () => {
const currentRunning = runningContext[runningContext.length - 1];
if (currentRunning) {
subscribe(currentRunning, subscriptions);
}
return value;
};
const write = (nextValue) => {
value = nextValue;
for (const sub of [...subscriptions]) {
sub.run();
}
};
return [read, write];
}
runningContext
λ νμ¬ μ€νμ€μΈ λ°μμ λ΄μλλ μ€ν μν μ νλ€. κ·Έλ¦¬κ³ κ°κ°μ Signalμ μμ μ΄ κ΄λ¦¬νλ ꡬλ
μ 리μ€νΈ(subscriptions
)κ° μλ€. μ΄ λ μλ£κ΅¬μ‘°κ° μλμΌλ‘ μμ‘΄μ±μ μΆμ νλ κΈ°λ₯μ κΈ°λ³Έμ΄ λλ€. μ΅μ λ²λΈ κ°μ λ³νμ λ°λΌ λ°μμ΄ μΌμ΄λ λ μκ·Έλ μμ μλ read
ν¨μκ° μ€νλλ κ²μ΄κ³ μ΄ λ ꡬλ
μ²λ¦¬κ° λλ κ²μ΄λ€.
μ¬κΈ°κΉμ§λ§ 보면 subscribe
ν¨μ μμμ νμ©λλ running
μ΄λΌλ μΈμκ° λ¬΄μμ μλ―Ένλμ§ νμ
νκΈ° μ΄λ ΅λ€. μ€μ λ‘ μ΅μ λ²λΈ κ°μ νμ©νκΈ° μν΄ createEffect
ν¨μλ λ§λ€μ΄λ³΄μ.
function cleanup(running) {
for (const dep of running.dependencies) {
dep.delete(running);
}
running.dependencies.clear();
}
function createEffect(fn) {
const run = () => {
cleanup(running);
runningContext.push(running);
try {
fn();
} finally {
context.pop();
}
};
const running = {
run,
depdendencies: new Set()
};
run();
}
λ°μμ΄ μ€νλ λ μμ μ΄ μ΄λ€ κ°μ μμ‘΄νμ¬ λ°μνκ³ μλμ§ κ΄λ¦¬νκΈ° μν dependencies
μμ±μ΄ λ°λ‘ μλ€. κ·Έλ¦¬κ³ μλ‘μ΄ λ°μν λλ§λ€ κΈ°μ‘΄μ λ±λ‘ν΄λ¨λ ꡬλ
μ μ²μνκ³ λ€μ ꡬλ
νλ κ³Όμ μ κ±°μΉλ€. λλΆμ λμ μΌλ‘ μ΅μ λ²λΈ κ°μ μμ‘΄μ±μ κ΄λ¦¬νλ κ²μ΄ κ°λ₯ν΄μ‘λ€.
νμ κ°μ 리ν΄νλ createMemo
λ κ°μ’
μ΅μ νλ₯Ό μν΄ λ 볡μ‘ν λ°©μμΌλ‘ ꡬνλμ΄μΌ νμ§λ§, κ°λ΅ν μμλ‘ createSignal
, createEffect
λ₯Ό νμ©νμ¬ λ§λ€ μ μλ€.
function createMemo(fn) {
const [computed, set] = createSignal();
createEffect(() => set(fn()));
return computed;
}
μ΄μ μμ μ¬λ£λ€μ μ΄μ©νμ¬ μ€νλ λμνΈμ μ μ¬ν μλ₯Ό λ§λ€μ΄λ³΄μ. νΉμ 쑰건μ λ°λΌ κ΄μ°°νλ μ μ λ°κΎΈμ΄μΌ ν λ μ΄λ€ λ°©μμΌλ‘ μ²λ¦¬λ κΉ?
const [A1, setA1] = createSignal(1);
const [B1, setB1] = createSignal(2);
const [showA1Only, setShowA1Only] = createSignal(false);
const C1 = createMemo(() => showA1Only() ? A1() : A1() + B1());
createEffect(() => console.log('C1: ' + C1()));
// C1: 3
setShowA1Only(true);
// C1: 1
setB1(10);
// μ무 μΌλ μΌμ΄λμ§ μμ
C1
μ ꡬλ
νκ³ μμΌλ©°, C1
μ κΈ°λ³Έμ μΌλ‘ showA1Only
λ₯Ό ꡬλ
νλ©΄μ μν©μ λ°λΌ A1
νΉμ A1
κ³Ό B1
λͺ¨λλ₯Ό ꡬλ
νλ€.C1
μ νΈμΆνκ³ κ·Έ κ³Όμ μμ createSignal
ν¨μ μμ μλ read
ν¨μκ° μ€νλλ μμΌλ‘ ꡬλ
μ΄ μ΄λ£¨μ΄μ§λ€. μ΄ κ³Όμ μμ showA1Only
λ ꡬλ
λκ³ , showA1Only
κ° false
μ΄λ―λ‘ A1
κ³Ό B1
μ λͺ¨λ ꡬλ
νμλ€.setShowA1Only
μ κ°μ λ³κ²½νλ©΄μ showA1Only
λ₯Ό ꡬλ
νλ C1
μ κ°μ΄ μ¬κ΅¬μ±λλ€. λ¨Όμ κΈ°μ‘΄μ ꡬλ
μ λͺ¨λ ν΄μ νκ³ λ€μ showA1Only
μ νμ¬ μ‘°κ±΄μ λΆν©νλ A1
κ°λ§ μλ‘ κ΅¬λ
νλ€. μ΄λ° λ°©μμΌλ‘ λμ μμ‘΄μ± κ΄λ¦¬κ° μ΄λ£¨μ΄μ§λ€.setShowA1Only
λ₯Ό false
λ‘ λ³κ²½νμ§ μλ ν μ무리 setB1
μ νΈμΆν΄λ μ΄ννΈκ° μ€νλμ§ μμ κ²μ΄λ€. μ΄λμμλ B1
μ ꡬλ
νκ³ μμ§ μκΈ° λλ¬Έμ΄λ€.μ΄λ κ² SolidJSμ λ°μν λͺ¨λΈμ λΉκ΅μ μ΄ν΄νκΈ° μ¬μ°λ©΄μλ λμ μΌλ‘ μμ‘΄μ± λ³νλ₯Ό κ΄λ¦¬ν μ μμ΄μ κ°λ ₯νκΈ°κΉμ§ νλ€. νμ§λ§ κ·Έ λμ μ΅μ λ²λΈ κ°μ μ‘°ννκ³ κ΄λ¦¬νλ μ½λλ₯Ό μμ±ν λ createEffect
νΉμ createMemo
μ νμ©ν΄μΌ μνλ κ²°κ³Όλ₯Ό μ»μ μ μμ κ²μ΄λ€.
λν SolidJSμ λ°μμ± λͺ¨λΈμ λ³νλ₯Ό λκΈ°μ μΌλ‘(Synchronously) μΆμ νλ€. μ΄ννΈ μμ setTimeout
λ±μ λΉλκΈ° μμ
μ μννλ μ½λκ° μλ€λ©΄ μ΅μ λ²λΈ κ°μ λ³νλ₯Ό μ λλ‘ μΆμ ν μ μλ€. λ¬Όλ‘ μ΄λ° λ¬Έμ λ₯Ό 보μνκΈ° μν APIκ° λ°λ‘ μ 곡λκ³ μλ€.
SolidJSλ JSX λ¬Έλ²μ μ 곡νκΈ΄ νμ§λ§ React, Vueμ λ€λ₯΄κ² Virtual DOM(κ°μ λ)μ μ¬μ©νμ§ μλλ€. λμ Svelteμ μ μ¬νκ² κ°λ°μκ° μμ±ν JSXμ λ°μν μμλ€μ κΈ°λ°μΌλ‘ μ»΄νμΌμ νκ³ , λ°νμμμλ μ¬μ©μμ μΈν°λμ μ λ°λΌ μ§μ λ³νκ° μΌμ΄λμΌ νλ λΆλΆμ DOMλ§ λ³κ²½νλ μ λ΅μ μ¬μ©νκ³ μλ€.
Reactμ μ»΄ν¬λνΈκ° μν λ³ν λ±μ λ°λΌ render
(ν¨μ μ»΄ν¬λνΈλ JSX λ¦¬ν΄ κ΅¬λ¬Έ)λ₯Ό κ³μ νΈμΆνλ κ²κ³Ό λ¬λ¦¬ SolidJSμ μ»΄ν¬λνΈλ ν λ² μ€νλλ©΄ λμΈ μμ±μμ κ°κΉλ€.
// μΈν°λ²μ λ°λΌ μΉ΄μ΄ν°κ° λ³κ²½λλ μ
import { createSignal, onCleanup } from "solid-js";
import { render } from "solid-js/web";
const CountingComponent = () => {
const [count, setCount] = createSignal(0);
const interval = setInterval(
() => setCount(c => c + 1),
1000
);
onCleanup(() => clearInterval(interval));
return <div>Count value is {count()}</div>;
};
render(() => <CountingComponent />, document.getElementById("app"));
ReactλΌλ©΄ count
κ° λ³νλ λλ§λ€ μ»΄ν¬λνΈκ° λ€μ νΈμΆλκ³ λ¦¬ν΄λλ κ°μ λμ λ³νλ₯Ό λΉκ΅νμ¬ λΈλΌμ°μ μμ 그리λ μμ
μ μνν κ²μ΄λ€. κ·Έλ¬λ©΄ μ»΄ν¬λνΈκ° νΈμΆλλ λμ μΈν°λ²μ κ΄λ¦¬νκΈ° μν΄ useEffect
λ±μ ν
μ μ¬μ©νμ¬ κ΄λ¦¬ν΄ μ£Όμ΄μΌ νλ€.
DOMμ μ§μ λ³κ²½νλ λ§νΌ μ΅μ νλ₯Ό μν΄ λ€λ₯Έ μ»΄ν¬λνΈμ μ λ¬λλ propsλ νλ‘μ κ°μ²΄λ‘ κ°μΈμ§ λ€ μ΅λν κ°μ΄ νμν μκ°κΉμ§ 미루μλ€κ° μ§μ° νκ°λλ€. λ°λΌμ React μ»΄ν¬λνΈμμ propsλ₯Ό κ°μ Έλ€ μΈ λ νλ κ²μ²λΌ ꡬ쑰 λΆν΄ ν λΉνλ κ²½μ° μ»΄ν¬λνΈκ° μ λλ‘ λ°μνμ§ μλλ€κ³ νλ€.
const Parent = () => {
const [greeting, setGreeting] = createSignal("Hello");
return (
<section>
<Label greeting={greeting()}>
<div>John</div>
</Label>
</section>
);
};
// greeting, childrenμ λ³νμ λ°μνλ€.
// ({greeting, children}) => {...} κ°μ μμΌλ‘ μ μΈνλ©΄ λ°μνμ§ μλλ€.
const Label = (props) => (
<>
<div>{props.greeting}</div>
{props.children}
</>
);
μ€νΈλ¦Ό κΈ°λ°μ λ°μν νλ‘κ·Έλλ°λ³΄λ€ μ‘°κΈ λ μΉμνκ² λ€κ°μ€λ TRPλ₯Ό ν΅ν΄ μ΄λ»κ² μμ¦ λ°μν λΌμ΄λΈλ¬λ¦¬λ€μ΄ λ°μν μμ€ν μ ꡬννλμ§ μ‘°κΈ λ μμΈν μμλ³Ό μ μμκ³ , κ·Έ μμ μ€ νλλ‘ SolidJSλ₯Ό μ΄ν΄λ³΄μλ€.
μλ‘μ΄ λΌμ΄λΈλ¬λ¦¬(νΉμ νλ μμν¬)μ νμ μμμ κ°λ°μλ 'λ΄κ° λ§λλ(νΉμ λ§λ€κ³ μ νλ) νλ‘κ·Έλ¨μ μ©λμ λ§λμ§', 'μΌλ§λ ν¨μ¨μ μΌλ‘ νλ‘κ·Έλ¨μ μμ±ν μ μλμ§' λ±μ λͺ νν κΈ°μ€μ κ°μ§κ³ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ΄ν΄λ³΄μμΌ ν κ²μ΄λ€. λ€μΌλ‘ λΌμ΄λΈλ¬λ¦¬μ κ·Όλ³Έ μ리λ λμμΈ μ² νμ νμ ν μ μλ€λ©΄ λμ± μ’μ μ νμ ν μ μμ κ²μ΄λ€.
SolidJSλ κ·Έ μ리μ ꡬμ±μ μμΈνκ² λ¬Έμνν΄λμλ€. μ΄λ² μν΄λ¦¬λ₯Ό μμ±νκΈ° μν΄ μλ£λ₯Ό μ‘°μ¬νκ³ μ 리νλ κ³Όμ μμ μ μμμ μ견μ ν¬κ² κ°ννκΈ°λ νλ€. ν λ² SolidJSμ 곡μ λ¬Έμλ₯Ό νμ΄λ³΄λ©΄μ μμ¦ νλ°νΈμλ μμμ λ°μν ν¨λ¬λ€μμ μ΄λ€ λ°©ν₯μΌλ‘ νλ¬κ°κ³ μλμ§, μ°κ΄λ κ°λ° νΈλ λκ° λ¬΄μμ΄ μμμ§ μ΄ν΄λ³΄λ©΄ κ½€ μ μ΅ν νμ΅μ΄ λ κ²μ΄λ€.