์ด๊ฒ์ ์ ์ฌ์ ์ผ๋ก props/state๋ฅผ ์ ๋ ฅ์ผ๋ก ์ฌ์ฉํ์ฌ ์ ์ญ ์ ์ฅ์/๋คํธ์ํฌ/๋ฆฌ์์ค์์ ์ํ ๋น์ ์ฅ(์ ์ฌ์ ์ผ๋ก ๋ฉ๋ชจํ๋จ) ๋ฐ์ดํฐ์ ๊ฐ๋ก ๋ฐ์ดํฐ ๋ก๋๋ฅผ ์ํ ์ผ๊ธ API์ ๋๋ค.
type RecordOfObservables = { [key:string]: Observable<mixed> };
class Foo {
observe(): RecordOfObservables {
return {
myContent: xhr(this.props.url)
};
}
render() {
var myContent : ?string = this.data.myContent;
return <div>{myContent}</div>;
}
}
๊ด์ฐฐ()์ componentWillMount/componentWillUpdate ์ดํ์ ์คํ๋์ง๋ง ๋ ๋๋ง ์ ์ ์คํ๋ฉ๋๋ค.
๋ ์ฝ๋์ ๊ฐ ํค/๊ฐ์ ๋ํด. ๊ฐ์์ Observable์ ๊ตฌ๋ ํฉ๋๋ค.
subscription = observable.subscribe({ onNext: handleNext });
onNext๊ฐ ๊ตฌ๋ ์์ ๋๊ธฐ์ ์ผ๋ก ํธ์ถ๋๋๋ก ํ์ฉํฉ๋๋ค. ๊ทธ๋ ๋ค๋ฉด ๋ค์์ ์ค์ ํฉ๋๋ค.
this.data[key] = nextValue;
๊ทธ๋ ์ง ์์ผ๋ฉด ์ด๊ธฐ ๋ ๋๋ง์ ๋ํด ์ ์๋์ง ์์ ์ํ๋ก ๋ก๋๋ค. (์๋ง๋ null๋ก ์ค์ ํ ๊น์?)
๊ทธ๋ฐ ๋ค์ ๋ ๋๋ง์ด ํ์์ ๊ฐ์ด ์งํ๋ฉ๋๋ค.
onNext๊ฐ ํธ์ถ๋ ๋๋ง๋ค ์ฐ๋ฆฌ๋ ์ด ๊ตฌ์ฑ ์์์ ๋ํ forcedUpdate๋ฅผ ํจ๊ณผ์ ์ผ๋ก ํธ๋ฆฌ๊ฑฐํ๋ ์๋ก์ด "this.data[key]"๋ฅผ ์์ฝํฉ๋๋ค. ์ด๊ฒ์ด ์ ์ผํ ๋ณ๊ฒฝ ์ฌํญ์ด๋ฉด ๊ด์ฐฐ์ด ๋ค์ ์คํ๋์ง ์์ต๋๋ค(componentWillUpdate -> render -> componentDidUpdate).
props/state๊ฐ ๋ณ๊ฒฝ๋ ๊ฒฝ์ฐ(์: recieveProps ๋๋ setState์์ ์ ๋ฐ์ดํธ) ๊ด์ฐฐ()์ด ์ฌ์คํ๋ฉ๋๋ค(์กฐ์ ์ค์).
์ด ์์ ์์ ์ฐ๋ฆฌ๋ ์ ๋ ์ฝ๋๋ฅผ ๋ฐ๋ณตํ๊ณ ๋ชจ๋ ์ Observable์ ๊ตฌ๋ ํฉ๋๋ค.
๊ทธ๋ฐ ๋ค์ ์ด์ Observable์ ๊ตฌ๋ ์ ์ทจ์ํฉ๋๋ค.
subscription.dispose();
์ด ์์๋ ๋ฐ์ดํฐ ๊ณต๊ธ์๊ฐ ์บ์์ ์ฐธ์กฐ ๊ณ์ฐ์ ์ํํ ์ ์๋๋ก ํ๊ธฐ ๋๋ฌธ์ ์ค์ํฉ๋๋ค. ์ฆ, ์๋ฌด๋ ๋ฃ์ง ์๋ ํ ๋ฐ์ดํฐ๋ฅผ ์บ์ํ ์ ์์ต๋๋ค. ์ฆ์ ๊ตฌ๋ ์ ์ทจ์ํ๋ฉด ๋์ผํ ๋ฐ์ดํฐ๋ฅผ ๋ค์ ๊ตฌ๋ ํ๊ธฐ ์ ์ ์ฐธ์กฐ ํ์๊ฐ 0์ผ๋ก ์ค์ด๋ญ๋๋ค.
๊ตฌ์ฑ ์์๊ฐ ๋ง์ดํธ ํด์ ๋๋ฉด ๋ชจ๋ ํ์ฑ ๊ตฌ๋ ์์ ์๋์ผ๋ก ๊ตฌ๋ ์ด ์ทจ์๋ฉ๋๋ค.
์ ๊ตฌ๋ ์ด ์ฆ์ onNext๋ฅผ ํธ์ถํ์ง ์์ผ๋ฉด ์ด์ ๊ฐ์ ๊ณ์ ์ฌ์ฉํฉ๋๋ค.
๋ฐ๋ผ์ ์์ ์ this.props.url
๊ฐ ๋ณ๊ฒฝ๋๊ณ ์ URL์ ๊ตฌ๋
ํ๋ ๊ฒฝ์ฐ myContent๋ ๋ค์ URL์ด ์์ ํ ๋ก๋๋ ๋๊น์ง ์ด์ URL์ ๋ด์ฉ์ ๊ณ์ ํ์ํฉ๋๋ค.
์ด๊ฒ์ <img />
ํ๊ทธ์ ๋์ผํ ์๋ฏธ๋ฅผ ๊ฐ์ต๋๋ค. ์ด๊ฒ์ด ํผ๋์ค๋ฝ๊ณ ๋ถ์ผ์น๋ก ์ด์ด์ง ์ ์์ง๋ง ์๋นํ ์ ์์ ์ธ ๊ธฐ๋ณธ๊ฐ์ด๋ฉฐ ๋ฐ๋ ๊ธฐ๋ณธ๊ฐ์ ์ฌ์ฉํ๋ ๊ฒ๋ณด๋ค ์คํผ๋๋ฅผ ํ์ํ๋๋ก ํ๋ ๊ฒ์ด ๋ ์ฝ๋ค๋ ๊ฒ์ ๋ณด์์ต๋๋ค.
๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ ์บ์๋ ๋ฐ์ดํฐ๊ฐ ์๋ ๊ฒฝ์ฐ "null" ๊ฐ์ ์ฆ์ ๋ณด๋ด๋ ๊ฒ์ ๋๋ค. ๋ ๋ค๋ฅธ ๋์์ Observable์ด ๊ฒฐ๊ณผ์ URL(๋๋ ID)๊ณผ ์ฝํ ์ธ ๋ฅผ ๋ชจ๋ ์ ๊ณตํ๋ ๊ฒ์ ๋๋ค.
class Foo {
observe() {
return {
user: loadUser(this.props.userID)
};
}
render() {
if (this.data.user.id !== this.props.userID) {
// Ensure that we never show inconsistent userID / user.name combinations.
return <Spinner />;
}
return <div>Hello, {this.data.user.name} [{this.props.userID}]!</div>;
}
}
Observable์ RxJS ๊ณ์ฝ์ด ๋ ์ผ๋ฐ์ ์ด๊ณ ๋๊ธฐ ์คํ์ ํ์ฉํ๊ธฐ ๋๋ฌธ์ ์ฌ์ฉํด์ผ ํ์ง๋ง @jhusain ์ ์ ์์ด ๋ ์ผ๋ฐ์ ์ผ๋ก ์ฌ์ฉ๋๋ฉด ๋์ ํด๋น ๊ณ์ฝ์ผ๋ก ์ ํํฉ๋๋ค.
var subscription = observable.subscribe({ onNext, onError, onCompleted });
subscription.dispose();
ํ์ํ ๊ฒฝ์ฐ ์ด๋ฌํ ์ด๋ฒคํธ์ ์๋ตํ๋ ์๋ช ์ฃผ๊ธฐ ํํฌ๋ฅผ ๋ ์ถ๊ฐํ ์ ์์ต๋๋ค.
์ฐธ๊ณ : ์ด ๊ฐ๋ ์ ์ฌ์ฉํ๋ฉด ์ ๋ฐ์ดํฐ๊ฐ ์ํ์ฒ๋ผ "๋์"์ฒ๋ผ ์๋ํ ์ ์์ต๋๋ค. ์ด๊ฒ์ ์ฐ๋ฆฌ๊ฐ ์ด๋ฌํ ๊ฒ๋ค์ ๋ํ ๊ฐ๋ ์ํ๋ฅผ ๊ณผ๋ถํํ ํ์๊ฐ ์๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค. ๋์ค์ ๋ค์ ๊ตฌ๋ ํ๊ธฐ ์ํด์๋ง ๋ฐ์ดํฐ๋ฅผ ๋ฒ๋ฆฌ๋ ๊ฒ๊ณผ ๊ฐ์ ์ต์ ํ๋ฅผ ํ์ฉํฉ๋๋ค. ๋ณต์ ๊ฐ๋ฅํฉ๋๋ค.
undefined
๋ onNext
๋ฅผ ํตํด ์ต์ ๋ฒ๋ธ์ด ์ฒซ ๋ฒ์งธ ๊ฐ์ ์ ๊ณตํ ๋๊น์ง data
์ ํ ๋นํ๋ ๊ฐ์ฅ ์์ ํ ๊ฐ์ผ ๊ฒ์
๋๋ค. ์๋ฅผ ๋ค์ด Relay์์ null
(๋ฐ์ดํฐ๊ฐ ์กด์ฌํ์ง ์์) ๋ฐ undefined
(์์ง ๊ฐ์ ธ์ค์ง ์์)์ ๋ค๋ฅธ ์๋ฏธ๋ฅผ ํ ๋นํ๋ฏ๋ก ์ด์์ ์ธ ๊ธฐ๋ณธ ๋ฐ์ดํฐ ๊ฐ์ undefined
์
๋๋ค. ๋์์ ์๋ฅผ ๋ค์ด getInitialData
์ ๊ฐ์ ์๋ก์ด ๋ฐฉ๋ฒ์ ์ ๊ณตํ๋ ๊ฒ์ด์ง๋ง ์ด๊ฒ์ด ๋ถํ์ํ๊ฑฐ๋ ๊ณผ์์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
์ด๊ฒ์ ๊ฝค ํฅ๋ฏธ๋กญ์ง๋ง ์ ์ ํ์ดํ์ ๊ด์ ์์ ๋๋ ํค/๊ฐ ์์คํ
์ ๊ทธ๋ค์ง ๋ง์กฑํ์ง ์์ต๋๋ค. ๊ทธ ์ ํ์ ํํํ๊ธฐ๊ฐ ๊ฑฐ์ ๋ถ๊ฐ๋ฅํฉ๋๋ค.
observe
๊ฐ ๋จ์ผ ๊ด์ฐฐ ๊ฐ๋ฅ ํญ๋ชฉ์ ๋ฐํํ๊ณ this.data
๋ก ํ์ธ๋ ๊ฐ์ ์ค์ /๋ณํฉํ์ง ์๋ ์ด์ ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
class Foo {
observe() {
return (
loadUser(this.props.userID)
.map(user => { user })
}
render() {
if (this.data.user.id !== this.props.userID) {
// Ensure that we never show inconsistent userID / user.name combinations.
return <Spinner />;
}
return <div>Hello, {this.data.user.name} [{this.props.userID}]!</div>;
}
}
๊ทธ๋ฆฌ๊ณ ๋ค์ค ๊ฐ์ ธ์ค๊ธฐ์ ๊ฒฝ์ฐ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
class Foo {
observe() {
return (
combineLatest(
loadUser(this.props.userID),
loadSomethingElse(this.props.somethingElseId),
(user, somethingElse) => ({ user, somethingElse})
)
}
render() {
..
}
}
์ด๊ฒ์ ์๋ง๋ ์กฐ๊ธ ๋ ์ฅํฉํ์ง๋ง ๋ฉ์ง ์ ์ ์ ํ์ ๊ฐ์ง ์ ์์ต๋๋ค.
interface Comp<T> {
observe(): Observable<T>;
data: T;
}
๋ํ props/state๊ฐ ๋ณ๊ฒฝ๋ ๋ observe
๋ฅผ ๋ค์ ์คํํ๋ ๋์ 'props' 'state'์ ์ต์ ๋ฒ๋ธ๋ก ์ก์ธ์คํ ์ ์์ต๋๋ค.
class Foo {
observe(propsStream) {
return (
propsStream
.flatMap(({ userID }) => loadUser(userId))
.map(user => { user })
);
}
render() {
if (this.data.user.id !== this.props.userID) {
// Ensure that we never show inconsistent userID / user.name combinations.
return <Spinner />;
}
return <div>Hello, {this.data.user.name} [{this.props.userID}]!</div>;
}
}
๊ทธ ์ด์ ๋ (์ฌ๋ฌ) Observable์ ๊ตฌ๋ ํ ์ ์๋๋ก RxJS๋ฅผ ์ดํดํ๊ณ ๊ฒฐํฉ์๋ฅผ ์ฌ์ฉํ๋๋ก ์๊ตฌํ์ง ์๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ด๋ฌํ ๋ฐฉ์์ผ๋ก ๋ ๊ฐ์ Observable์ ๊ฒฐํฉํ๋ ๊ฒ์ ๋งค์ฐ ํผ๋์ค๋ฝ์ต๋๋ค. ์ฌ์ค, ์ต์ํ ๋ฐ์ดํฐ ์์ค์ ๊ฒฝ์ฐ ๊ตฌ๋ API๋ฅผ ๊ตฌํํ์ง๋ง Observable์ ํ๋กํ ํ์ ์ ๊ฒฐํฉ์๋ ํฌํจํ์ง ์์ ๊ฒ์ ๋๋ค. ํ์ ์ฌํญ์ ์๋์ง๋ง ํ์ํ ๊ฒฝ์ฐ ๊ฒฐํฉ์๋ฅผ ์์ ๋กญ๊ฒ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๊ทธ๋ฌ๋ ๊ฐ๋จํ Flux ์คํ ์ด๋ฅผ ๊ตฌ๋ ํ๊ธฐ ์ํด ๊ตฌ๋ ํ ํ์๋ ์์ต๋๋ค.
Flow๋ ์๋ง๋ ์ ์ฝ ์กฐ๊ฑด์ ์ฌ์ฉํ์ฌ ์ด ์ ์ ์ ํ์ ์ฒ๋ฆฌํ ์ ์์ ๊ฒ์ด๋ผ๊ณ ์๊ฐํ์ง๋ง, ํ์ธํ๊ธฐ ์ํด ํด๋น ์ฌ๋๋ค์๊ฒ ํ์ธํ๊ฒ ์ต๋๋ค. ๋ฐ์ดํฐ ์์ฑ์ ์ ๋ ฅํ๊ณ ๊ด์ฐฐ ์ ํ์ ์์ํ๋ ๊ฒ์ผ๋ก ์ถฉ๋ถํ ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
class Foo extends React.Component {
data : { user : User, content : string };
observe() /* implied as { user : Observable<User>, content : Observable<string> } */ {
}
}
์ด ๋ณ๊ฒฝ์ ์ ํ๋ฆฌ์ผ์ด์ ์ํ๋ฅผ ์ค๋ช ํ๋ ๋ฐฉ๋ฒ์ผ๋ก Observables์ ์ฌ์ธํ๋ ๊ฒ์ ๊ดํ ๊ฒ์ด ์๋๋๋ค. ์ด๊ฒ์ ์ด์ ์ ํ๋ ๊ฒ์ฒ๋ผ ์ด๊ฒ ์์ ๊ตฌํ๋ ์ ์์ต๋๋ค. ์ด ๋ฉ์๋๋ ๋ฉฑ๋ฑ์ฑ์ด๊ธฐ ๋๋ฌธ์ ๋ช ์์ ์ผ๋ก ์์ฉ ํ๋ก๊ทธ๋จ ์ํ์ ๊ดํ ๊ฒ์ด ์๋๋๋ค. ํ๋ ์์ํฌ๋ ํ์์ ๋ฐ๋ผ ๊ตฌ๋ ์ ์ทจ์ํ๊ณ ๋ค์ ๊ตฌ๋ ํ ์ ์์ต๋๋ค.
cc @ericvicenti
์ ์ด๋ typescript์ ๊ฒฝ์ฐ data
์ ์ ํ์ ๊ธฐ๋ฐ์ผ๋ก observe
์ ๋ฐํ ์ ํ์ ์ ํํ๋ ๋ฐฉ๋ฒ์ ์ ์ด๋ https://github.com/ ๊ณผ ๊ฐ์ ๋๊น์ง๋ ์์ต๋๋ค.
๋๋ ์ด๊ฒ์ React DnD์ ๋ค์ ๋ฒ์ ์ ์ฌ์ฉํ๊ณ ์ถ์ง๋ง ๋ถ๋ช
ํ ์ด๊ฒ์ React 0.14๋ฅผ ๊ธฐ๋ค๋ ค์ผ ํฉ๋๋ค.
ref
์ธ์คํด์ค์ this.data
๋ฅผ ์ค์ ํ๋ ๊ณ ์ฐจ ๊ตฌ์ฑ ์์๋ก ๋น๋ถ๊ฐ ์ด๊ฒ์ "ํด๋ฆฌํ"ํ ์ ์๋์ง ๊ถ๊ธํฉ๋๋ค. ๊ทธ๋๋ ๋๋ฌด ๋ฏธ์น ๊ฒ ๊ฐ์ต๋๋ค.
์ฝ์์ ์งํค๋ ๊ฒ์ด ๊ฐ๋ฅํ ๊น์? ๊ทธ๋ฐ ๋ค์ ์ฒซ ๋ฒ์งธ ๋ ๋๋ง ์ ์ ์ ์ฒด ๊ตฌ์ฑ ์์ ํธ๋ฆฌ์ ๋ํ ๋ฐ์ดํฐ๋ฅผ ํ์ธํ๊ธฐ ์ํด ์ฝ์ ํธ๋ฆฌ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค! ์ด๊ฒ์ ์๋ฒ ์ธก React์ ๋งค์ฐ ์ ์ฉํฉ๋๋ค.
์ด๊ฒ์ ์ผ๋ฅ API๋ก ๋ง๋ค๋ฉด ์ด๋ค ์ด์ ์ด ์์ต๋๊น? ๋ณธ์ง์ ์ผ๋ก "๊ณ ์ฐจ ๊ตฌ์ฑ ์์"๋ฅผ ์ฌ์ฉํ์ฌ ์ํํ ์ ์์ต๋๋ค.
์ด๊ฒ์ ์ผ๋ฅ API๋ก ๋ง๋ค๋ฉด ์ด๋ค ์ด์ ์ด ์์ต๋๊น? ๋ณธ์ง์ ์ผ๋ก "๊ณ ์ฐจ ๊ตฌ์ฑ ์์"๋ฅผ ์ฌ์ฉํ์ฌ ์ํํ ์ ์์ต๋๋ค.
5๊ฐ์ HOC๋ก ๋ํํ์ฌ 5๊ฐ์ ๊ตฌ๋
์ ์ป๋ ๊ฒ์ ์ด๋ณด์์๊ฒ ๋ค์ ๋ค๋ฃจ๊ธฐ ์ด๋ ต๊ณ ์ดํดํ๊ธฐ ์ด๋ ต์ต๋๋ค. componentWillReceiveProps
๋ฅผ ์ดํดํ๋ ๊ฒ๋ ์ฝ์ง ์์ต๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ๋ ๋ค ํด๊ฒฐ๋ฉ๋๋ค.
๋๋ ์ฐ์ ์ฐ๋ฆฌ์ ์๋ก์ด ๊ด์ฐฐ ๊ฐ๋ฅํ ๋๊ตฐ์ฃผ๋ฅผ ํ์ํฉ๋๋ค.
์ด๊ฒ์ด https://github.com/chenglou/react-state-stream ์ React์ ๋ฐ๋๋ผ API์ ๋ ๊ฐ๊น๊ฒ ๋ง๋๋ ๋ฐ ๋์์ด ๋ ์ ์๋์ง ๊ถ๊ธํฉ๋๋ค.
ํ๋์ HOC๊ฐ ํ์ํ์ง ์์ต๋๊น? Medium ๊ฒ์๋ฌผ ์ ์์์ stores
๋ฅผ ๋ฐ๋ณตํ๊ณ ๊ฐ๊ฐ์ ๊ตฌ๋
ํฉ๋๋ค.
stores.forEach(store =>
store.addChangeListener(this.handleStoresChanged)
);
@aaronshaf ํ์คํ ์ฌ์ฉ ์ฌ๋ก์ ๋ฐ๋ผ @sebmarkbage๊ฐ ๋งํ๋ ๊ฒ์ ๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
์ด์ ์ด๊ฒ์ ๊ฐ์ง๊ณ ๋๊ธฐ ์ํด ์ผ์ข ์ ํด๋ฆฌํ์ ์ข์ํ ๊ฒ์ ๋๋ค. ์์ง ์์ด๋์ด๋ฅผ ์์ ํ ์ดํดํ์ง ๋ชปํ์ต๋๋ค. ํฅํ ์ ๋ฐ์ดํธ ์ฒ๋ฆฌ์ ๊ด๋ จ๋ ๋ฉ์ปค๋์ฆ์ ๋ฌด์์ ๋๊น? ๋๋ ๊ทธ๊ฒ์ ์ดํดํ๋ ๋ฐ ๋ ๋ง์ ์๊ฐ์ ํ ์ ํ ๊ฒ์ ๋๋ค. ๊ฐ๋จํ mixin์ผ๋ก ๊ฐ๋ฅํด์ผ ํ๋ค๊ณ ์๊ฐํฉ๋๋ค.
( @vjeux ๋ ๋ด๊ฐ ์ฐจ์๋ฒจ์
๋ด ์์
์ ํ๋ณดํ๋ ค๋ ๊ฒ์ ์๋์ง๋ง ์ด ํํฌ๋ React Nexus ์ getNexusBindings
ํํฌ์ ๋งค์ฐ ์ ์ฌํ๋ค๊ณ ์๊ฐํฉ๋๋ค. ์๋ช
์ฃผ๊ธฐ ํํฌ(props์ ๋ฐ๋ผ ๋ฌ๋ผ์ง ์ ์์)๋ฅผ ํตํด ๊ตฌ์ฑ ์์ ์์ค์์ ๋ฐ์ดํฐ deps๋ฅผ ์ ์ธํฉ๋๋ค.
API๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
class UserDetails {
getNexusBindings(props) {
return {
// binding to data in the datacenter
posts: [this.getNexus().remote, `users/${this.props.userId}/posts`],
// binding to data in the local flux
mySession: [this.getNexus().local, `session`],
}
}
}
๋ฐ์ธ๋ฉ์ componentDidMount
๋ฐ componentWillReceiveProps
๋์ ์ ์ฉ/์
๋ฐ์ดํธ๋ฉ๋๋ค. ํ์์ ๊ฒฝ์ฐ ๋ค์ ๋ฐ์ธ๋ฉ์ ์ด์ ๋ฐ์ธ๋ฉ๊ณผ ๋ค๋ฆ
๋๋ค. ์ ๊ฑฐ๋ ๋ฐ์ธ๋ฉ์ ๊ตฌ๋
์ทจ์๋๊ณ ์ถ๊ฐ๋ ๋ฐ์ธ๋ฉ์ ๊ตฌ๋
๋ฉ๋๋ค. ๊ธฐ๋ณธ ๊ฐ์ ธ์ค๊ธฐ/์
๋ฐ์ดํธ ๋ฉ์ปค๋์ฆ์ Nexus Flux ๊ตฌํ์ ์ค๋ช
๋์ด ์์ต๋๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก ๋์ผํ API๋ฅผ ์ฌ์ฉํ์ฌ ๋ก์ปฌ ๋ฐ์ดํฐ(๊ธฐ์กด ๋ก์ปฌ ์ ์ฅ์) ๋๋ ์๊ฒฉ ๋ฐ์ดํฐ(GET์ ์ฌ์ฉํ์ฌ ๊ฐ์ ธ์ค๊ณ Websockets/polyfill์ ํตํด ํจ์น ์์ )๋ฅผ ๊ตฌ๋
ํ ์ ์์ต๋๋ค. ์ค์ ๋ก ๋ค๋ฅธ ์ฐฝ(postWindow ์ฌ์ฉ) ๋๋ WebWorker/ServiceWorker์์ ๋ฐ์ดํฐ๋ฅผ ๊ตฌ๋
ํ ์ ์์ง๋ง ์ด์ ๋ํ ์ง์ ์ผ๋ก ์ ์ฉํ ์ฌ์ฉ ์ฌ๋ก๋ฅผ ์ฐพ์ง ๋ชปํ์ต๋๋ค.
๊ฐ๋จํ ๋งํด์ Flux ์ถ์ํ๋ฅผ ์ฌ์ฉํ์ฌ ๊ตฌ์ฑ ์์ ์์ค์์ ๋ฐ์ดํฐ deps๋ฅผ ๋๊ธฐ์์ผ๋ก ์ค๋ช ํ๊ณ ํํฌ๋ ์ข ์์ฑ์ด ์๋์ผ๋ก ๊ตฌ๋ ๋๊ณ ์ ๋ฐ์ดํธ ์ ์ฃผ์ ๋๊ณ ๊ตฌ๋ ์ทจ์๋๋๋ก ํฉ๋๋ค.
๊ทธ๋ฌ๋ ์ฌ๊ธฐ์๋ ๋ฉ์ง ๊ธฐ๋ฅ๋ ํจ๊ป ์ ๊ณต๋ฉ๋๋ค. ์ ํํ ๋์ผํ ์๋ช ์ฃผ๊ธฐ ๊ธฐ๋ฅ์ ํ์ฉํ์ฌ ์๋ฒ ์ธก ๋ ๋๋ง ์๊ฐ์ ๋ฐ์ดํฐ ํ๋ฆฌํ์น๋ฅผ ์ํํฉ๋๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก React Nexus๋ ๋ฃจํธ์์ ์์ํ์ฌ ๊ฑฐ๊ธฐ์์ ์ฌ๊ท์ ์ผ๋ก ๋ฐ์ธ๋ฉ์ ๋ฏธ๋ฆฌ ๊ฐ์ ธ์ค๊ณ ๊ตฌ์ฑ ์์๋ฅผ ๋ ๋๋งํ๊ณ ๋ชจ๋ ๊ตฌ์ฑ ์์๊ฐ ๋ ๋๋ง๋ ๋๊น์ง ํ์ ํญ๋ชฉ์ ๊ณ์ ์งํํฉ๋๋ค.
@aaronshaf @gaearon ์ผ๋ฑ์ ์ผ๋ก ๋ง๋๋ ์ด์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
1) props ๋ค์์คํ์ด์ค๋ฅผ ์ก์๋จน์ง ์์ต๋๋ค. ์๋ฅผ ๋ค์ด ๊ณ ์ฐจ ์ปดํฌ๋ํธ๋ ๋ค๋ฅธ ์ฉ๋๋ก ์ฌ์ฉํ ์ ์๋ data
์ ๊ฐ์ ์ด๋ฆ์ props ๊ฐ์ฒด์์ ์๊ตฌํ ํ์๊ฐ ์์ต๋๋ค. ์ฌ๋ฌ ๊ฐ์ ๊ณ ์ฐจ ๊ตฌ์ฑ ์์๋ฅผ ์ฐ๊ฒฐํ๋ฉด ๋ ๋ง์ ์ด๋ฆ์ ๊ณ์ ์ฌ์ฉํ๋ฏ๋ก ์ด์ ์ด๋ฌํ ์ด๋ฆ์ ๊ณ ์ ํ๊ฒ ์ ์งํ๋ ๋ฐฉ๋ฒ์ ์ฐพ์์ผ ํฉ๋๋ค. ์ด๋ฏธ ์์ฑ๋์์ ์ ์๋ ํญ๋ชฉ์ ์์ฑํ๊ณ ์๋๋ฐ ์ด์ ์ด๋ฆ ์ถฉ๋์ด ๋ฐ์ํ๋ฉด ์ด๋ป๊ฒ ๋ฉ๋๊น?
๊ฒ๋ค๊ฐ, ๊ณ ์ฐจ ๊ตฌ์ฑ ์์์ ๋ํ ๋ชจ๋ฒ ์ฌ๋ก๋ ๋ํ๋ ๊ตฌ์ฑ ์์์ ๊ณ์ฝ์ ๋ณ๊ฒฝํ์ง ์๋ ๊ฒ์ด์ด์ผ ํ๋ค๊ณ ์๊ฐํฉ๋๋ค. ์ฆ, ๊ฐ๋ ์ ์ผ๋ก ์์๊ณผ ๋์ผํ ์ํ์ด์ด์ผ ํฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์๋น์๊ฐ ์์ ํ ๊ฒ๊ณผ ์์ ํ ๋ค๋ฅธ props ์ธํธ๋ฅผ ์ ๊ณตํ ๋ ์ฌ์ฉํ๊ณ ๋๋ฒ๊ทธํ๋ ๊ฒ์ด ํผ๋์ค๋ฝ์ต๋๋ค.
2) ๋ง์ง๋ง ๊ฐ์ ์ ์ฅํ๊ธฐ ์ํด state
๋ฅผ ์ฌ์ฉํ ํ์๊ฐ ์์ต๋๋ค. data
๊ฐ๋
์ ์์ ํ ๋ฉ๋ชจ์ด์ ์ด์
์ด๋ผ๋ ์ ์์ props
์ ์ ์ฌํฉ๋๋ค. ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ์ํด์ผ ํ๋ ๊ฒฝ์ฐ ์ธ์ ๋ ์ง ์์ ๋กญ๊ฒ ๋ฒ๋ฆด ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ๋ฌดํ ์คํฌ๋กค์์ ๋ณด์ด์ง ์๋ ํ์ ํธ๋ฆฌ๋ฅผ ์๋์ผ๋ก ์ ๋ฆฌํ ์ ์์ต๋๋ค.
@RickWong ์, Observable์ ํ์ ์งํฉ์ด๊ธฐ ๋๋ฌธ์ Promise๋ฅผ ์ง์ํ๋ ๊ฒ์ ๋งค์ฐ ๊ฐ๋จํฉ๋๋ค. ์ฐ๋ฆฌ๋ ์๊ฒฌ์ด ์๋ ๊ฒ์ฒ๋ผ ๊ทธ๋ ๊ฒ ํด์ผ ํ ๊ฒ์ ๋๋ค. ๊ทธ๋ฌ๋ ๋๋ ์ฌ์ ํ ๊ทธ๊ฒ๋ค์ ์ฌ์ฉํ์ง ์๋ ๊ฒ์ด ์ข์ต๋๋ค. ๋ค์๊ณผ ๊ฐ์ ์ด์ ๋ก Observable๋ณด๋ค ์ด๋ฑํ๋ค๋ ๊ฒ์ ์์์ต๋๋ค.
A) ํ๋ ์์ํฌ์์ ์๋์ผ๋ก ์ทจ์ํ ์ ์์ต๋๋ค. ์ฐ๋ฆฌ๊ฐ ํ ์ ์๋ ์ต์ ์ ๋ฆ์ ํด๊ฒฐ์ ๋ฌด์ํ๋ ๊ฒ์ ๋๋ค. ๊ทธ ๋์ Promise๋ ์ ์ฌ์ ์ผ๋ก ๊ณ ๊ฐ์ ๋ฆฌ์์ค๋ฅผ ๋ณด์ ํ๊ณ ์์ต๋๋ค. ์ฅ๊ธฐ ์คํ ํ์ด๋จธ/๋คํธ์ํฌ ์์ฒญ์ subscribe/cancel/subscribe/cancel...๊ณผ ๊ฐ์ ๋์กํ ์ํฉ์ ๋น ์ง๊ธฐ ์ฝ๊ณ Promises๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฃจํธ์์ ์ทจ์๋์ง ์์ผ๋ฏ๋ก ๊ทธ๋ฅ ๊ธฐ๋ค๋ ค์ผ ํฉ๋๋ค. ๋ฆฌ์์ค๋ฅผ ์๋ฃํ๊ฑฐ๋ ์๊ฐ ์ด๊ณผํฉ๋๋ค. ์ด๋ facebook.com๊ณผ ๊ฐ์ ๋ํ ๋ฐ์คํฌํฑ ํ์ด์ง์ ์ฑ๋ฅ์ด๋ ๋ฉ๋ชจ๋ฆฌ๊ฐ ์ ํ๋ ํ๊ฒฝ(์: ๋ฐ์ ๋ค์ดํฐ๋ธ)์ ๋๊ธฐ ์๊ฐ์ด ์ค์ํ ์ฑ์ ์ฑ๋ฅ์ ํด๋ก์ธ ์ ์์ต๋๋ค.
B) ๋น์ ์ ์ค์ง ํ๋์ ๊ฐ์น๋ง์ ์ป๋ ๊ฒ์ ์์ ์ ๊ฐ๋๊ณ ์์ต๋๋ค. ์๊ฐ์ด ์ง๋จ์ ๋ฐ๋ผ ํด๋น ๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ๋๋ฉด ๋ณด๊ธฐ๋ฅผ ๋ฌดํจํํ ์ ์์ผ๋ฉฐ ๊ฒฐ๊ณผ์ ์ผ๋ก ์ผ๊ด์ฑ์ด ์๋ ์ํ๊ฐ ๋ฉ๋๋ค. ๋ฐ์ํ์ง ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๊ด์ฐฎ์ ์ ์๋ ๋จ์ผ ์๋ฒ ์ธก ๋ ๋๋ง์ ๊ฒฝ์ฐ ํด๋ผ์ด์ธํธ์์ ์ด์์ ์ผ๋ก๋ ์ ๋ฐ์ดํฐ๋ฅผ UI๋ก ์คํธ๋ฆฌ๋ฐํ๊ณ ์ค๋๋ ๋ฐ์ดํฐ๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด ์๋์ผ๋ก ์ ๋ฐ์ดํธํ ์ ์๋ ๋ฐฉ์์ผ๋ก ์ค๊ณํด์ผ ํฉ๋๋ค.
๋ฐ๋ผ์ Observable์ ํ์ํ ๊ฒฝ์ฐ ์ด๋ฌํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์ฌ์ฉ์๋ฅผ ์ ๊ทธ์ง ์๊ธฐ ๋๋ฌธ์ ๋น๋ํ ์ ์๋ ์ฐ์ํ API๋ผ๋ ๊ฒ์ ์์์ต๋๋ค.
@elierotenberg ์ฐธ์ฌ ํด์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค! ์ค์ ๋ก ๋งค์ฐ ์ ์ฌํด ๋ณด์ ๋๋ค. ๊ฐ์ ์ข ๋ฅ์ ํํ. ๋ด ์ ์์ ์ ํ์ด ์์ต๋๊น? ์ฆ, React Nexus์ ๋๋ฝ๋ ๊ฒ์ด ์๋๋ฐ ์ด ์์ ๋น๋ํ ์ ์๋ ๊ฒ์ด ์์ต๋๊น? ์ค์ํ ์ฌ์ฉ ์ฌ๋ก์์ ์ค์ค๋ก๋ฅผ ์ ๊ทธ์ง ์๋๋ค๋ฉด ์ข์ ๊ฒ์ ๋๋ค. :)
์๋ฒ ๋ ๋๋ง ๊ด์ ์์ Observable/Promise๊ฐ ๋น๋๊ธฐ์ ์ผ๋ก ๊ฐ์ ธ์ฌ ์ ์๋ ๋ฐ์ดํฐ๋ก ํด๊ฒฐ๋ ๋๊น์ง ์ต์ข renderToString์ ์ฐ๊ธฐํ ์ ์๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์์ง ํ์ด์ง์ ์ด๋ค ๊ตฌ์ฑ ์์๊ฐ ์๋์ง ์์ง ๋ชปํ ์ฑ React ์ธ๋ถ์์ ๋ชจ๋ ๋น๋๊ธฐ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ๋ฅผ ์ํํด์ผ ํ๋ ์์น์ ์์ต๋๋ค.
๋๋ react-nexus๊ฐ ๋ ๋ ํธ๋ฆฌ๋ฅผ ๊ณ์ ๋ด๋ ค๊ฐ๊ธฐ ์ ์ ์ปดํฌ๋ํธ ๋ด์์ ๋น๋๊ธฐ ๋ก๋ฉ์ ํ์ฉํ๋ค๊ณ ๋ฏฟ์ต๋๋ค.
์, react-nexus๋ ๋ค์์ ๋ช
์์ ์ผ๋ก ๊ตฌ๋ถํฉ๋๋ค.
1) getNexusBindings
๋ก ์ ์ธ ๋ฐ์ธ๋ฉ
2) ๊ตฌ๋
/์
๋ฐ์ดํธ๋ฅผ applyNexusBindings
๋ฐ์ธ๋ฉ
3) ํ๋ฆฌํ์นญ์ prefetchNexusBindings
๋ก ๋ฐ์ธ๋ฉ(๋น๋๊ธฐ์์ด๋ฉฐ "์ด๊ธฐ"(์ด๊ฒ์ด ์๋ฏธํ๋ ๊ฒ์ด ๋ฌด์์ด๋ ) ๊ฐ์ด ์ค๋น๋๋ฉด ํด๊ฒฐ๋จ)
ReactNexus.prefetchApp(ReactElement)
๋ Promise(String html, Object serializableData)
๋ฐํํฉ๋๋ค. ์ด ํํฌ๋ React ํธ๋ฆฌ์ ๊ตฌ์ฑ์ ๋ชจ๋ฐฉํ๊ณ ( instantiateReactComponent
) ๊ตฌ์ฑ ์์๋ฅผ ์ฌ๊ท์ ์ผ๋ก ๊ตฌ์ฑ/ํ๋ฆฌํ์น/๋ ๋๋งํฉ๋๋ค. ์ ์ฒด ๊ตฌ์ฑ ์์ ํธ๋ฆฌ๊ฐ '์ค๋น'๋๋ฉด ๋ชจ๋ ๋ฐ์ดํฐ๊ฐ ์ค๋น๋์์์ ์๋ฉด์ ๋ง์นจ๋ด React.renderToString
ํธ์ถํฉ๋๋ค(๋ชจ๋๋ก ์ค๋ฅ). ํด๊ฒฐ๋๋ฉด ์ด Promise์ ๊ฐ์ ์๋ฒ ์๋ต์ ์ฝ์
ํ ์ ์์ต๋๋ค. ํด๋ผ์ด์ธํธ์์ ์ผ๋ฐ React.render()
์๋ช
์ฃผ๊ธฐ๋ ํ์์ ๊ฐ์ด ์๋ํฉ๋๋ค.
๋๊ตฐ๊ฐ๊ฐ ์ด๋ฐ ์ข
๋ฅ์ API๋ฅผ ๊ฐ์ง๊ณ ๋๊ณ ์ถ๋ค๋ฉด observe
์ ๋ํด ๊ณ ์ฐจ ๊ตฌ์ฑ ์์๋ก ์ ๋ง ๋ฉ์ฒญํ ํด๋ฆฌํ์ ๋ง๋ค์์ต๋๋ค.
import React, { Component } from 'react';
export default function polyfillObserve(ComposedComponent, observe) {
const Enhancer = class extends Component {
constructor(props, context) {
super(props, context);
this.subscriptions = {};
this.state = { data: {} };
this.resubscribe(props, context);
}
componentWillReceiveProps(props, context) {
this.resubscribe(props, context);
}
componentWillUnmount() {
this.unsubscribe();
}
resubscribe(props, context) {
const newObservables = observe(props, context);
const newSubscriptions = {};
for (let key in newObservables) {
newSubscriptions[key] = newObservables[key].subscribe({
onNext: (value) => {
this.state.data[key] = value;
this.setState({ data: this.state.data });
},
onError: () => {},
onCompleted: () => {}
});
}
this.unsubscribe();
this.subscriptions = newSubscriptions;
}
unsubscribe() {
for (let key in this.subscriptions) {
if (this.subscriptions.hasOwnProperty(key)) {
this.subscriptions[key].dispose();
}
}
this.subscriptions = {};
}
render() {
return <ComposedComponent {...this.props} data={this.state.data} />;
}
};
Enhancer.propTypes = ComposedComponent.propTypes;
Enhancer.contextTypes = ComposedComponent.contextTypes;
return Enhancer;
}
์ฉ๋ฒ:
// can't put this on component but this is good enough for playing
function observe(props, context) {
return {
yourStuff: observeYourStuff(props)
};
}
class YourComponent extends Component {
render() {
// Note: this.props.data, not this.data
return <div>{this.props.data.yourStuff}</div>;
}
}
export default polyfillObserve(YourComponent, observe);
Observable์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ตฌํ์ ์ ์ธํ๊ณ ๊ตฌ์ฒด์ ์ด๊ณ ํฉ์๋ ๊ฒ์ ๋๊น? ๊ณ์ฝ์ด๋ ๋ฌด์์ ๋๊น? ๋ฒ ์ด์ปจ์ด๋ Rxjs๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ๋ ๊ตฌํํ ์ ์์ ๋งํผ ๊ฐ๋จํฉ๋๊น? ๋ฐ์ดํฐ๋ฅผ ์ฌ์ด๋๋ก๋ฉํ๊ธฐ ์ํ ์ผ๋ฅ API๋งํผ ํ๋ฅญํ์ง๋ง, ์ผ๋ฐ js๋ฅผ ํฅํ React์ ๊พธ์คํ ์์ง์์ ๊ฐ์ํ ๋ React๊ฐ ์ง์ ๋์ง ์์/๋งค์ฐ ์ด๊ธฐ ์ง์ ํ๋ฆฌ๋ฏธํฐ๋ธ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ๋ API๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ ์ด์ํด ๋ณด์ ๋๋ค. ์ด์ ๊ฐ์ ๊ฒ์ด ์ฐ๋ฆฌ๋ฅผ ํน์ ์ฌ์ฉ์ ํ ์ง ๊ตฌํ์ ์ฐ๊ฒฐํฉ๋๊น?
์ ์ณ๋๊ณ ์คํธ๋ฆผ์ด ์๋ ์ด์ ๋ ๋ฌด์์ ๋๊น? ๊ฒฝ์ฃผ์๋ ๋ง์ด ์์ง๋ง ์์งํ ๊ถ๊ธํฉ๋๋ค. ์ด๋ฏธ ์น ์คํธ๋ฆผ์ ๋ํ ์์ ์ด ์๋ฃ๋์์ผ๋ฉฐ ๋ฌผ๋ก ๋ ธ๋๊ฐ ์์ต๋๋ค.
๊ณ ๋ คํด์ผ ํ ๋ ๋ค๋ฅธ ๋ ๊ฐ์ง: https://github.com/cujojs/most ๋ฐ https://github.com/caolan/highland
@jquense Observable์ ECMAScript 7(+)์ ์ถ๊ฐํ๋ ์ ์์ ๋ํ ํ์ฑ ์์ ์ด ์์ผ๋ฏ๋ก ์ด์์ ์ผ๋ก๋ ์ผ๋ฐ JS๊ฐ ๋ฉ๋๋ค. https://github.com/jhusain/asyncgenerator (ํ์ฌ ๊ตฌ์์ ๋๋ค.)
์ฐ๋ฆฌ๋ RxJS์ ์์กดํ์ง ์์ ๊ฒ์ ๋๋ค. API๋ RxJS๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ์ค์ค๋ก ๊ตฌํํ๊ธฐ ์ฝ์ต๋๋ค. RxJS๋ ํ์ฑ ECMAScript ์ ์์ ๊ฐ์ฅ ๊ฐ๊น์ต๋๋ค.
most.js๋ ๊ฐ๋ฅํ ๊ฒ ๊ฐ์ต๋๋ค.
Bacon.js์ API๋ ๊ฐ์ ๊ตฌ๋ถํ๊ธฐ ์ํด Bacon.Event
ํ์
์ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ Bacon์ ์์กดํ์ง ์๊ณ ๋ ์ฌ์ฉํ๊ธฐ ์ด๋ ค์ด ๊ฒ ๊ฐ์ต๋๋ค.
Stream API๋ ๋๋ฌด ๋์ ์์ค์ด๋ฉฐ ์ด ์ฌ์ฉ ์ฌ๋ก์์ ๋ฉ๋ฆฌ ๋จ์ด์ ธ ์์ต๋๋ค.
"await before render" ์ต์ ์ด ์์ต๋๊น? ์ ๋ง์ ํด๋ผ์ด์ธํธ์์๋ ๋ ๋๋งํ๊ธฐ ์ ์ ๋ชจ๋ Observable์ ๊ธฐ๋ค๋ฆด ํ์๊ฐ ์์ง๋ง ์๋ฒ์์๋ ๊ฐ ๊ตฌ์ฑ ์์์ render()๊ฐ ํด๊ฒฐ๋ ๋๊น์ง ๊ธฐ๋ค๋ ค์ผ ํ๋ค๋ ๋ป์ ๋๋ค. ๋ถ๋ถ์ด ์๋ ์ ์ฒด .
[parent] await observe(). full render(). -> [foreach child] await observe(). full render().
๋ชจ๋ ํ์์์ ์ด๊ฒ์ด ์๋ฒ ์ธก React์์ ๋๋ฝ๋ ๊ฐ์ฅ ์ค์ํ ์๋ช ์ฃผ๊ธฐ ํํฌ์์ ๋ฐ๊ฒฌํ์ต๋๋ค.
์ด ํ ๋ก ์ ์ด์ด ๋ค์ ๊ฒ์๋ฌผ์์ React Nexus๊ฐ ํ๋ ์ผ์ ์์ฝํ๋ ค๊ณ ํ์ต๋๋ค.
React Nexus๋ก ์ ๋๋ก ๋ Ismorphic ์ฑ
ํต์ฌ ํ๋ฆฌํ์นญ ๋ฃจํด์ ๋ค์ด์ด๊ทธ๋จ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
์ฐ๋ฆฌ๋ RxJS์ ์์กดํ์ง ์์ ๊ฒ์ ๋๋ค. API๋ RxJS๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ์ค์ค๋ก ๊ตฌํํ๊ธฐ ์ฝ์ต๋๋ค. RxJS๋ ํ์ฑ ECMAScript ์ ์์ ๊ฐ์ฅ ๊ฐ๊น์ต๋๋ค.
:+1: ์ด๊ฒ์ ๋ด๊ฐ ๋ฌด์์ ํ๊ณ ์๋์ง ์์ง ๋ชปํ๋ ํ ์ค์ค๋ก ๊ตฌํํ๋ ๊ฒ์ด ๊ทน๋๋ก ์ด๋ ค์ด ์ฝ์์ ๋ํด ์๊ฐํ๋ฉด์ ๊ฐ์ฅ ํฐ ๊ด์ฌ์ฌ์
๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์ํ๊ณ์ ํน์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ํ ์์์ ์๊ตฌ ์ฌํญ์ผ๋ก ๋๋ฉ๋๋ค. ์ ์ ์ ์ผ๋ก... Promise ์ธ๊ณ์ ์ข์ ์ ์ค ํ๋๋ A+ ํ
์คํธ ์ค์ํธ์ด๋ฏ๋ก ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ ์ฒด์ ๊ฑธ์ณ์๋ผ๋ .then
์ ๊ณตํต ๊ธฐ๋ฅ์ ๋ํ ๋ณด์ฆ์ด ์ต์ํ ์์์ต๋๋ค. ํ์คํ.
๋น์ ์ด ๋ฌด์์ ํ๊ณ ์๋์ง ์์ง ๋ชปํ๋ค๋ฉด ๋น์ ์์ ์ ๊ฒ์ ๊ตฌํํ๋ ๊ฒ์ด ๊ทน๋๋ก ์ด๋ ค์ด ์ฝ์์ ๋ํด ์๊ฐํ๋ฉด์ ์ด๊ฒ์ด ์ ์๊ฒ ํฐ ๊ด์ฌ์ฌ์ ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์ํ๊ณ์ ํน์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ํ ์์์ ์๊ตฌ ์ฌํญ์ผ๋ก ๋๋ฉ๋๋ค.
์์ ํ ๋์ํ์ต๋๋ค. ๊ณ ๋ง๊ฒ๋ ์ต์ ๋ฒ๋ธ์ ์ ๋ง ๊ฐ๋จํ ๊ณ์ฝ์ ๊ฐ์ง๊ณ ์๊ณ then
์ ๊ฐ์ ๋ด์ฅ ๋ฉ์๋๋ ์๊ธฐ ๋๋ฌธ์ ์ด๋ค ๋ฉด์์๋ ํ๋ผ๋ฏธ์ค๋ณด๋ค ํจ์ฌ ๊ฐ๋จํฉ๋๋ค.
์์ํ์์ next
ํธ์ถ์ด Promises์ ๊ฐ์ ๋ฏธ์ธ ์์
์ ์์ฝํ๋ค๊ณ ์ฃผ์ฅํ๋ฉด ๋ ๋ณต์กํด์ง๊ณ ๋๋ ค์ง ์ ์์ต๋๋ค.
์ด๋ onNext๊ฐ RxJS์์ ๋๊ธฐ์์ด๋ผ๋ ์ฌ์ค์ ๊ธฐ๋ฐํ ๋ง์ ํจํด์ ๊ท์ฐฎ๊ฒ ํ ๊ฒ์ ๋๋ค.
์ผ๋ฐ์ ์ธ Flux ์ ์ฅ์ ํจํด์ ์ฌ์ฌ์ฉํ ์ ์๋๋ก ํค๋ณ๋ก Map of Observable์ ์ ์งํ๋ ๊ฒ์ผ ์ ์๋ค๊ณ ์๊ฐํฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ ๋ชจ๋ ์ฌ๋์ด ๊ตฌ๋ ์ ์ทจ์ํ ๋ ์ ๋ฆฌํฉ๋๋ค.
๊ทธ๋ ๊ฒ ํ๋ฉด MyStore.get(this.props.someID)
์ ๊ฐ์ ์์
์ ์ํํ ์ ์์ผ๋ฉฐ ํญ์ ๋์ผํ Observable์ ๋ฐํํฉ๋๋ค.
๊ทธ๋ ๊ฒ ํ๋ฉด MyStore.get(this.props.someID)๊ณผ ๊ฐ์ ์์ ์ ์ํํ๊ณ ํญ์ ๋์ผํ Observable์ ๋ฐํํ ์ ์์ต๋๋ค.
this.props.key
(gone I know)๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์๋ฏธ๊ฐ ์์ต๋๊น? ๋๋ถ๋ถ์ ๊ฒฝ์ฐ ์ด๋ฌํ ๊ณ ์ ์๋ณ์๋ฅผ ์ด๋ฏธ <... key={child.id} .. />
๋ก ์ ๋ฌํฉ๋๋ค.
๊ทธ๋ ๊ฒ ํ๋ฉด MyStore.get(this.props.someID)๊ณผ ๊ฐ์ ์์ ์ ์ํํ๊ณ ํญ์ ๋์ผํ Observable์ ๋ฐํํ ์ ์์ต๋๋ค.
์ด๊ฒ์ด ๋ด๊ฐ React Nexus์๋ ์ฌ์ฉํ๋ ํจํด์ ๋๋ค. Store#observe๋ ๋ฉ๋ชจํ๋ ๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅํ ๊ด์ฐฐ์๋ฅผ ๋ฐํํฉ๋๋ค. ๋ชจ๋ ๊ตฌ๋ ์๊ฐ ์ ์ด๋ ํ ํฑ ๋์ ์ฌ๋ผ์ง๋ฉด ์ ๋ฆฌ๋ฉ๋๋ค(์ค์ "๊ตฌ๋ ์ทจ์" ๋ฉ์์ง ๋ณด๋ด๊ธฐ์ ๊ฐ์ ๊ด๋ จ ๋ฐฑ์๋๋ณ ์ ๋ฆฌ ๋ฉ์ปค๋์ฆ ํฌํจ).
@sebmarkbage @gaearon v0.14 ์์ ์๋ฒ ์์
์ ์ด๋ป๊ฒ ๊ด์ฐฐํ ๊น์?
react-nexus๊ฐ ํ๋ ๊ฒ๊ณผ ์ ์ฌํ๊ฒ ๋ฌธ์์ด๋ก ๋ ๋๋งํ๊ธฐ ์ ์ ๋ชจ๋ ๊ด์ฐฐ์๊ฐ ํด๊ฒฐ๋ ๋๊น์ง ์ ์ ํ๊ฒ ๊ธฐ๋ค๋ฆด ์ ์์ต๋๊น(๊ทธ๋ฌ๋ ๋ฐ์ํ๋๋ก ๋ด์ฅ๋์ด ์์)?
IMO ๊ตฌ์ฑ ์์๊ฐ ์๋ฒ์์ ๋ ๋๋งํ "์ค๋น"๋๊ธฐ ์ ์ ์ฒซ ๋ฒ์งธ ๊ด์ฐฐ ๊ฐ์ ๊ธฐ๋ค๋ฆฐ๋ค๋ฉด ์ข์ ๊ฒ์ ๋๋ค.
@gaearon : IMO ๊ตฌ์ฑ ์์๊ฐ ์๋ฒ์์ ๋ ๋๋งํ "์ค๋น"๋๊ธฐ ์ ์ ์ฒซ ๋ฒ์งธ ๊ด์ฐฐ ๊ฐ์ ๊ธฐ๋ค๋ฆฐ๋ค๋ฉด ์ข์ ๊ฒ์ ๋๋ค.
์, :+1: ๋น๋๊ธฐ ๋ ๋๋ง์ ๊ฒฝ์ฐ. ๊ทธ ๋์ @andreypopp ์ react-async
๊ฐ ๋์์ด์ง๋ง React๋ฅผ "ํดํน"ํ๋ ค๋ฉด fibers
๊ฐ ํ์ํฉ๋๋ค. React๊ฐ ๊ธฐ๋ณธ์ ์ผ๋ก ๋น๋๊ธฐ ๋ ๋๋ง์ ์ง์ํ ์ ์๋ค๋ฉด ์ข์ ๊ฒ์
๋๋ค.
๋น๋๊ธฐ ๋ ๋๋ง์ ์ง์ํ๊ณ ์ถ์ง๋ง ์ด ๋ฌธ์ ์ ์ผ๋ถ๊ฐ ์๋๋๋ค. ์
๋ถํํ๋ 0.14์์๋ ์๋ง ๊ทธ๊ฒ์ ๋ง๋ค์ง ์์ ๊ฒ์ ๋๋ค. ๊ณ ๋ คํ๊ณ ๋ฆฌํฉํ ๋งํด์ผ ํ ๋ค์ํ ๋์์ธ์ด ํ์ํฉ๋๋ค.
๊ทธ๋ ๊ฒ ํ๋ ๋ฐ ํ์ํ ๋ด๋ถ ์ํคํ ์ฒ ๋ณ๊ฒฝ ์ฌํญ์ ์์ฑํ๊ณ ์ค๋ช ํ๋ ๋ฌธ์ ๋ฅผ ์์ ๋กญ๊ฒ ์์ฑํ์ญ์์ค.
@gaearon re: react-streaming-state ์ ๊ฐ์ ์๊ฐ์ ํ์ต๋๋ค . ์ฌ์ด๋ ๋ก๋ฉ ์ด์ธ์ ๋ชจ๋ ์ ์ฌ์ ์ธ ์์ฉ ํ๋ก๊ทธ๋จ์ ๊ณ ๋ คํ ๋ data
๋ณด๋ค ๋ ๋์ ์ด๋ฆ์ด ์์๊น์? ์๋ฅผ ๋ค์ด observed
๋ ๋ฉ์๋์ ๋ ๋ช
ํํ๊ฒ ์ฐ๊ด๋ฉ๋๋ค.
Bikeshedding์ผ๋ก ํ์ ํ๋ ค๋ ๊ฒ์ ์๋์ง๋ง ์ด๊ฒ์ ๋ฒ๋ฆฌ๊ณ ์ถ์์ต๋๋ค.
React์์ Observable์ ๊ธฐ๋ค๋ฆด ์ ์์ต๋๋ค. ์ด๊ฒ์ ๋ด๊ฐ ์ดํดํ ๋ React๋ฅผ ๋ฐ์ํ์ผ๋ก ๋ง๋ค์ด์ผ ํฉ๋๋ค.
react-async
๋ฅผ ๋ค์ ์์ฑํ๋ ๋์ ๋น์ทํ ์์ด๋์ด๋ฅผ ์คํํ๊ณ ์์ต๋๋ค. README ๋ฅผ ์ฐธ์กฐํ์ญ์์ค.
์ฃผ๋ชฉํ ๋งํ ์ฐจ์ด์ ์ React๊ฐ key
prop ๋ฐ stateful ๊ตฌ์ฑ ์์๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ์๊ณผ ์ ์ฌํ๊ฒ ํ๋ก์ธ์ค๋ฅผ ์กฐ์ ํ๊ธฐ ์ํด ๋ช
์์ ๊ด์ฐฐ ๊ฐ๋ฅ/ํ๋ก์ธ์ค ID๋ฅผ ๋์
ํ๋ค๋ ๊ฒ์
๋๋ค.
๋ช
๋ช
๋ ํ๋ก์ธ์ค์ id
๊ฐ ๋ณ๊ฒฝ๋๋ฉด React Async๋ ์ด์ ํ๋ก์ธ์ค ์ธ์คํด์ค๋ฅผ ์ค์งํ๊ณ ์ ์ธ์คํด์ค๋ฅผ ์์ํฉ๋๋ค.
API๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
import React from 'react';
import Async from 'react-async';
function defineFetchProcess(url) {
return {
id: url,
start() {
return fetch(url)
}
}
}
function MyComponentProcesses(props) {
return {
user: defineFetchProcess(`/api/user?user${props.userID}`)
}
}
@Async(MyComponentProcesses)
class MyComponent extends React.Component {
render() {
let {user} = this.props
...
}
}
ํ๋ก์ธ์ค API๋ ์ด์ ๊ตฌ๋ฌธ์ ์ผ๋ก๋ ์ด๋ฆ์ ์ผ๋ก ES6 Promises API๋ฅผ ๋ฐ๋ฅด์ง๋ง ์๋ฏธ์์ผ๋ก๋ process.then(onNext, onError)
๊ฐ ๋ผ์ด๋ธ ํ๋ก์ธ์ค๋น ํ ๋ฒ๋ง ํธ์ถ๋ ๊ฒ์ผ๋ก ์์๋์ง ์์ต๋๋ค. Promise๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๊ฐ์ฅ ์ธ๊ธฐ ์๋(?) ์ฌ์ฉ ์ฌ๋ก๋ฅผ ์์ฉํ๋๋ก ๋ง๋ค์ด์ก์ต๋๋ค. ํ์ง๋ง ์์งํ ์ง๊ธ์ ํผ๋์ ๋ง๊ธฐ ์ํด ๋ฐ๊ฟ์ผ ํ๋ค๊ณ ์๊ฐํ๋ค.
๋ด๊ฐ ํ๋ ธ์ ์๋ ์์ง๋ง ์ฌ์ฉ์ ์์ญ์์ ์ ์๋(์ด ๋ฌธ์ ์์) API๋ฅผ ๊ตฌํํ๋ ๊ฒ์ ๋ฐฉํดํ๋ ์ ์ผํ ๊ฒ์ componentWillUpdate
์ ๊ฐ์ด ๋ ๋๋ง ์ง์ ์ ์คํ๋์ง๋ง ์๋ก์ด props
์คํ๋๋ ์๋ช
์ฃผ๊ธฐ ํํฌ๊ฐ ์๋ค๋ ๊ฒ์
๋๋ค. ๊ทธ๋ฆฌ๊ณ state
์ด๋ฏธ ์ธ์คํด์ค์ ์ค์น๋์ด ์์ต๋๋ค.
์์ง ๋
ผ์๋์ง ์์ ํ ๊ฐ์ง๋ onError
์ฝ๋ฐฑ ์ฒ๋ฆฌ์
๋๋ค. Observable์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ฉด ํด๋น ์ ๋ณด๋ฅผ ๊ตฌ์ฑ ์์์์ ์ด๋ป๊ฒ๋ ์ฌ์ฉํ ์ ์์ด์ผ ํฉ๋๋ค. React๋ ์ค์ subscribe(callbacks)
ํธ์ถ์ ์ฒ๋ฆฌํ๊ธฐ ๋๋ฌธ์ ํด๋น ์ฝ๋ฐฑ ๊ฐ์ฒด์ ์ฃผ์
ํ๋ ค๋ฉด ํ์คํ๋ ๋ฉ์๋๊ฐ ํ์ํฉ๋๋ค.
์ ํ๋ฆฌ์ผ์ด์
๊ฐ๋ฐ์์๊ฒ ์ต๋ํ์ ์ ์ฐ์ฑ์ ์ ๊ณตํ๊ธฐ ์ํด ๋ ๊ฐ์ง ์ ๊ทผ ๋ฐฉ์์ด ์์ต๋๋ค. ์ฒซ ๋ฒ์งธ๋ this.data
์ ์ ์ฌํ ์ต์์ ์์ฑ์ ์ค๋ฅ๋ฅผ ๋ฐฐ์นํ๋ ๊ฒ์
๋๋ค. ์ด๊ฒ์ ์์ฒญ๋๊ฒ ๋ฌด๊ฑฐ์ ๋ณด์ด๋ฉฐ ๊ตฌ์ฑ ์์์ ๋ค์ ์คํ์ด์ค๋ฅผ ๋ ๋ง์ด ๋จน์ต๋๋ค.
๋ ๋ฒ์งธ๋ ๊ฐ๋ฐ์๊ฐ ์์ ์ onError
์ฝ๋ฐฑ์ ์๋ช
์ฃผ๊ธฐ ๊ธฐ๋ฅ์ผ๋ก ์ ์ํ ์ ์๋๋ก ํฉ๋๋ค. ๋ด ์ต์ ๋ฒ๋ธ์ ๋ํ ์ฌ์ฉ์ ์ ์ ์ค๋ฅ ์ฒ๋ฆฌ๋ฅผ ์ํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ๊ฒ์ ์ถ๊ฐํ ์ ์์ต๋๋ค.
onObserveError(key, error) {
// do something with the error
this.state.errors[key] = error;
this.setState({ errors: this.state.errors });
}
์ด๊ฒ์ Parse+React์ ๋ค์ ๋ฐ๋ณต์์ ์ํํ ์์
๊ณผ ์ ์ฌํฉ๋๋ค. ์ฐ๋ฆฌ๋ ์ฐ๋ฆฌ๊ฐ ์ํ๋ API๋ฅผ ์์ฑํ๊ธฐ ์ํด ์์ฒด ์ค๋ฅ ์ฒ๋ฆฌ๋ฅผ ๋ง๋ค์์ต๋๋ค. ๊ฐ์ธ { name => error } ์ง๋์ ์ค๋ฅ๊ฐ ์ถ๊ฐ๋๊ณ ๊ตฌ์ฑ ์์์๋ ๋น์ด ์์ง ์์ ๊ฒฝ์ฐ ์ง๋์ ๋ณต์ ๋ณธ์ ๋ฐํํ๋ ์ต์์ ๊ณต๊ฐ ๋ฉ์๋์ธ queryErrors()
๋ฐ null
๊ฐ ์์ต๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด (๋จ์ํ if (this.queryErrors())
ํ์ฉ.
๋ฌผ๋ก ์๋ก์ด ์์ฝ ๋ฉ์๋๋ฅผ ์ ์ํ๋ ๊ฒ๋ ๊น๋ค๋ก์ด ์์ ์ ๋๋ค. ์๋ ์ฒ ํ์ง ์๊ฒ ์ต๋๋ค. ๊ทธ๋ฌ๋ ๋ ๋๋งํ ๋ ๊ตฌ์ฑ ์์์์ ์ค๋ฅ๋ฅผ ์์์ ๋๋ ๋ช ์์ ์ผ๋ก ์ฌ์ฉํ ์ ์๋๋ก ํ๋ ๋ฐฉ๋ฒ์ด ํ์ํฉ๋๋ค.
@andrewimm ์์ด๋์ด๋ ์ค๋ฅ ๊ฒฝ๊ณ์ ์ํด ์ฒ๋ฆฌ๋ ๋๊น์ง ๊ณ์ธต ๊ตฌ์กฐ ์๋ก ์ค๋ฅ๋ฅผ ๋ฒ๋ธ๋งํ๋ ์ผ๋ฐ ์ค๋ฅ ์ ํ ์์คํ ์ ์ ๋ ฅํ๋ ๊ฒ์ ๋๋ค. https://github.com/facebook/react/issues/2928
์ด๊ฒ์ ๋ํ ๋ฉ์๋๋ฅผ ๋์ง๊ณ ์ ์์ ์ผ๋ก ๋ณต๊ตฌํ๋ ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํด์ผ ํฉ๋๋ค. render()
๋ฉ์๋๊ฐ throwํ๋ ๊ฒ๊ณผ ๊ฐ์ต๋๋ค. ์ด๊ฒ์ ํจ์ฌ ๋ ๋ง์ ์์
์ด ํ์ํ๊ณ ์ ๋๋ก ๊ตฌํํ๋ ๋ฐ ์๊ฐ์ด ์ข ๊ฑธ๋ฆฌ์ง๋ง ์ด๋ฌํ ๋ฐฉ์์ผ๋ก ์ค๋ฅ ์ฒ๋ฆฌ๋ฅผ ํตํฉํ๋ ๊ฒ์ด ์์ด๋์ด์์ต๋๋ค.
๋๋ ์ด๊ฒ์ด ์ ์ ํ ๋ฐ์ ์ธ๋ถ์ ๋์ด์ผ ํ๋ค๊ณ ์ฃผ์ฅํ๊ณ , 1๊ฐ ๋๋ 2๊ฐ์ ํต์ฌ ํตํฉ ์ง์ ์ react-async ๋ฐ react-nexus์ ๊ฐ์ ํ๋ก์ ํธ์ ์กฐ์ ๋์ด์ผ ์ ์ ํ React ์์์ ๊น๋ํ๊ฒ ์ํ๋ ์ ์์ต๋๋ค....
๋์ํฉ๋๋ค. ์ ์๋ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ ๊ฒ์ด
์ด๊ฒ์ ํ๋ ์์ํฌ ์์ฒด์ ๊ตฝ๊ธฐ
2015๋
4์ 21์ผ ํ์์ผ ์คํ 11:38 Rodolfo Hansen [email protected]
์ผ๋ค:
๋๋ ์ด๊ฒ์ด ์ ์ ํ ๋ฐ์ ์ธ๋ถ์ ๋จ๊ฒจ ๋์ด์ผํ๋ค๊ณ ์ฃผ์ฅํ๊ณ 1 ๋๋ 2 ํค
ํตํฉ ์ง์ ์ react-async ๋ฐ
react-nexus๋ฅผ ์ฌ์ฉํ์ฌ ์ ์ ํ React ์์์ ๊น๋ํ๊ฒ ์ํํ ์ ์์ต๋๋ค....โ
์ด ์ด๋ฉ์ผ์ ์ง์ ๋ต์ฅํ๊ฑฐ๋ GitHub์์ ํ์ธํ์ธ์.
https://github.com/facebook/react/issues/3398#issuecomment -95048028.
์ฃผ๋ง ๋์ ์ ๋ Flexy ๋ผ๋ ๋ ๋ค๋ฅธ Flux ๊ตฌํ์ ๊ตฌ์ถํ์ต๋๋ค. ์ฌ๊ธฐ์์ ์์ ์ ์ฝ๋๋ฅผ ํ์ธํ์ญ์์ค. ์ค์ ๋ก ์ฌ์ฉ๋๋ ์ต์ ๋ฒ๋ธ์ด๋ ๋ค๋ฅธ Reactive ํ๋ ์์ํฌ๊ฐ ์์์๋ ๋ถ๊ตฌํ๊ณ ์ต์ ๋ฒ๋ธ API๋ฅผ ์ค์ํ๋ .getObservable
๋ฉ์๋๋ฅผ ๋
ธ์ถํฉ๋๋ค.
๋ฐ๋ผ์ API๋ ์ค์ Observable๋ก ์์ฑํ ์ ์์ ๋งํผ ์ฝ๋ค๊ณ ๋งํ๊ณ ์ถ์ต๋๋ค.
์ฆ, ์ฝ๋๋ฅผ ๊ฐํนํ๊ฒ ํ๋จํ์ง ๋ง์ญ์์ค. ์ฃผ๋ง ๋์ ์ํ๋์์ต๋๋ค.
์ฐธ๊ณ ๋ก ์ด์ ๊ฐ์ ์์คํ ๊ณผ Flux๋ ์ค์ ๋ก ์๋ฒ ์ธก ๋ ๋๋ง์ ๋ ๊ณ ํต์ค๋ฝ๊ฒ ๋ง๋ญ๋๋ค. React-Nexus์ ์ ์ฌํ ์์คํ ์ ์ฌ์ฉํ์ฌ ์คํ ์ด๋ฅผ ์ด๊ธฐํํ๊ณ React ์ฑ์ ์ ๋ฌํ ์ ์์ต๋๋ค. ๊ทธ๋ฐ ๋ค์ ์์ ๊ณผ ๋์คํจ์ฒ๋ฅผ ๋ชจ๋ํฐ๋งํ๊ณ ๋ ์ด์ ์์ ์ด ์คํ๋์ง ์์ ๋๊น์ง ๊ณ์ ๋ค์ ๋ ๋๋งํ ์ ์์ต๋๋ค(ํ์ํ ๋ชจ๋ ๋ฐ์ดํฐ๊ฐ ์ด๋ฏธ ์์ ์ ์์).
๋๋ ์ด๊ฒ์ด ์ํ ๋น์ ์ฅ ๋ฐ์ดํฐ ๊ตฌ๋ ์ ์๋ก์ด ์๋ฏธ๋ฅผ ์ป๊ธฐ ์ํ ๊ฐ์ฅ ์์ ํตํฉ ์ง์ ์ด๋ผ๊ณ ์ฃผ์ฅํฉ๋๋ค. ๋ค๋ฅธ ์ด๋ค ํตํฉ ํฌ์ธํธ๋ฅผ ์ ์ํ์๊ฒ ์ต๋๊น? ํจ์ฌ ๋ ๋ณต์กํ ๋ฌธ์ ์ด๊ณ ์์ฒด ์ค๋ ๋๊ฐ ํ์ํ ๋น๋๊ธฐ ๋ ๋๋ง์ ํฌํจํ์ง ์์ผ๋ฉฐ ์ด ํํฌ๋ ๊ด๊ณ์์ด ๋น๋๊ธฐ ๋ ๋๋ง๊ณผ ํจ๊ป ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋ค๋ฅธ ๋ชจ๋ ๊ฒ์ ์ด๋ฏธ ๊ตฌ์ฑ ์์๋ณ๋ก React๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ตฌํํ ์ ์์ต๋๋ค. ํ๋ฌ๊ทธ์ธ์ ์ ์ญ ์ฃผ์ ์ ํ๊ฒฝ ์ ๋ฐ์์ ๊ตฌ์ฑ ์์ ์ฌ์ฌ์ฉ์ ์ค๋จํ๋ฏ๋ก React๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ตฌ์ถ๋ ํ๋ ์์ํฌ๋ ๊ฐ๋ณ ๊ตฌ์ฑ ์์์ ๋ํด ์ปจํ ์คํธ์ฌ์ผ ํ๋ฏ๋ก ํ๋ฌ๊ทธ์ธ์ ์ ์ญ ์ฃผ์ ์ ์ํํ์ง ์์ ๊ฒ์ ๋๋ค.
์ฐ๋ฆฌ๋ ์ด๋ค ํํฌ๋ฅผ ๋์น๊ณ ์์ต๋๊น?
์ผ,
์์งํ ๋งํด์, ์๋ก์ด ํํฌ๊ฐ ๊ตฌํ์ ๋ ์ฝ๊ฒ ๋ง๋ค๊ธด ํ์ง๋ง react-async
๋ฐ react-nexus
์์ฐํ ๊ฒ์ฒ๋ผ ํํฌ ์์ด๋ ์ธก๋ฉด ๋ฐ์ดํฐ ๋ก๋๋ฅผ ํ์คํ ๋ฌ์ฑํ ์ ์์ต๋๋ค.
์ด์จ๋ ํ์ฌ๋ React ๊ณ์ธต ๊ตฌ์กฐ ์ธ๋ถ์์ React ๊ตฌ์ฑ ์์ ์ธ์คํด์ค ์๋ช
์ฃผ๊ธฐ๋ฅผ ์ ์ง ๊ด๋ฆฌํ๋ ๊ฒ์ ๋
ธ์ถํ๊ณ ์ง์ํ๋ ๊ฒ์ด ๋์์ด ๋ ๊ฒ์
๋๋ค. react-nexus
์์ ๋ด๋ถ instanciateReactComponent
ํ๊ณ componentWillMount
, componentWillUnmount
๋ฑ์ ์ง์ ํธ์ถํ๋ฉฐ ์ด ์ ๊ทผ ๋ฐฉ์์ด ์ทจ์ฝํ๋ค๊ณ ์๊ฐํฉ๋๋ค( instanciateReactComponents
๋ ๋ค์ ๋ฒ์ ์ React?์์ ๋ณ๊ฒฝ๋๋ ๋ด๋ถ ๋ถ๋ณ์ ์์กดํฉ๋๋ค.).
์ํ ๋น์ ์ฅ ์ ๊ทผ ๋ฐฉ์์ ๊ฒฝ์ฐ ๋น๋๊ธฐ ๋ฐ์ดํฐ๋ฅผ _is_ ์ํ๋ก ๊ฐ์ ธ์ค๊ณ ๋ฐ๋ผ์ ์ผ๋ถ ๊ตฌ์ฑ ์์์ ์ํ์ ๋ณด๋ฅ/์๋ฃ/์คํจ ์ํ๋ฅผ ์ ์ฅํ๋ ๊ฒ์ด ๊ด๋ จ์ด ์๋ ๊ฒ ๊ฐ์ต๋๋ค. ์ค์ ์ฑ์์ react-nexus
๋ฅผ ์ฌ์ฉํ ๋ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ๋ฅผ ์ํํ๊ณ ๊ฐ์ ธ์ค๊ธฐ ์ํ๋ฅผ ์์ ๊ตฌ์ฑ ์์์ ์ํ์ผ๋ก ์ฃผ์
ํ๋ ๊ณ ์ฐจ ๊ตฌ์ฑ ์์๊ฐ ์์ต๋๋ค. ๋ฐ๋ผ์ ๋ด๋ถ ๊ตฌ์ฑ ์์๋ "์ํ ๋น์ ์ฅ"(๋ฐ๋์งํจ)์ด๊ณ ์ธ๋ถ ๊ตฌ์ฑ ์์๋ "์ํ ์ ์ฅ"(์: ๋ก๋ฉ ์คํผ๋ ๋๋ ์๋ฆฌ ํ์์๋ฅผ ํ์ํ๋ ๋ฐ์๋ ๋ฐ๋์งํจ)์
๋๋ค.
๋ค๋ฅธ ์ด๋ค ํตํฉ ํฌ์ธํธ๋ฅผ ์ ์ํ์๊ฒ ์ต๋๊น?
@ANDREYPOPP ๊ฐ ์ฌ๋ฐ๋ฅธ ์ง๋ฌธ์ ํ ๊ฒ ๊ฐ์ต๋๋ค. ๋ ๋๋งํ๊ธฐ ์ ์ ์ฌ์ฉ์ ์์ญ์์ ์๋ช
์ฃผ๊ธฐ ํํฌ๋ฅผ ๊ตฌํํด์ผ ํ๋ ์ ์ผํ ๊ฒ์ด ์๋๊ฐ์? ์ต์ํ์ API ๋ณ๊ฒฝ์ด ํ์ํ ๊ฒ์ฒ๋ผ ๋ณด์ด์ง๋ง ๋๋จธ์ง๋ ์
๋ ฅ ์คํธ๋ฆผ/์ด๋ฏธํฐ/๊ด์ฐฐ ๊ฐ๋ฅํ ํญ๋ชฉ์ ๋ฐ๋ผ data
๋ฅผ ๋ณ๊ฒฝํ ๋ forceUpdate๋ฅผ ์ ์ ํ๊ฒ ์ค์ ํ๊ณ ํธ๋ฆฌ๊ฑฐํ๋ ๊ฒ์
๋๋ค. ๋ด๊ฐ ๊ทธ๊ฒ์ ๋ํด ๋ค๋ฅธ ํน๋ณํ ๊ฒ์ ๋์น๊ณ ์์ง ์๋ค๋ฉด (์์ ํ ๊ฐ๋ฅ)?
๋๋ ์ฌ๊ธฐ์ ๋ ํฐ ๋
ผ์์ ๋น ์ ธ๋ค์ง ์์ต๋๋ค.
ํ์ง๋ง @sebmarkbage ์ ๋ตํ๊ธฐ ์ํด ๋ด๊ฐ ์ํ๋ ๊ฐ์ฅ ์ค์ํ ํํฌ ์ค ํ๋๋ ์ค์ ๊ด์ฐฐ ๊ฐ๋ฅ ํญ๋ชฉ์ ์ฌ์ฉํ์ง ์์ ๋๋ง ํ์ํ ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
.map
๊ฐ ๋ฉ๋๋ค.์ํฉ์ด ์ข ๋ ๊ฐ๋ฐฉ์ ์ด์๋ค๋ฉด Observable ๊ด๋ จ ๋์์ ์ปค์คํ ํ ์ผ๋ก ๋์ฒดํ ํ ์ด ์์ด์ผ ํ๋ค๊ณ ์๊ฐํฉ๋๋ค. ์ด๋ฐ ์์ผ๋ก ์ด๋ฒคํธ ์ด๋ฏธํฐ ๋๋ CSP ์ฑ๋์ ๋์ โโ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋ง์ง๋ง ๋ช ๋๊ธ์ด ๊ฐ์ฅ ์์ ํ์ฅ ์ง์ ์ด ์ค์ ๋ก "์ฐ๊ฒฐ" ๋ฐ "์ฐ๊ฒฐ ํด์ " ์๋ช ์ฃผ๊ธฐ ํํฌ๋ผ๊ณ ๋งํ๋ ๊ฒ ๊ฐ์ต๋๋ค. ์ด๋ฅผ ํตํด ๊ตฌ์ฑ ์์์ ๋น๋๊ธฐ ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ฒ ์ฐ๊ฒฐํ๊ณ ํด๋น ๊ตฌ๋ ์ ๊ด๋ฆฌํ ์ ์์ต๋๊น?
๊ทธ๋ฐ ๋ค์ Observable์ (์ฝ์ด ๋ด๋ถ ๋๋ ์ธ๋ถ) ์ด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์๋นํ ์ฌ์ํ๊ฒ ๊ตฌ์ถ๋ ์ ์์ง๋ง ์ด๋ฌํ ์๋ช ์ฃผ๊ธฐ ์ง์ ์ ๋ ธ์ถํ๋ ๊ฒ์ด ๋ ํฐ ๋งค๋ ฅ์ด ์์ต๋๊น?
ํฉ๋ฆฌ์ ์ธ ์์ฝ์ธ๊ฐ์?
๋๋ ๋ํ ์ด๊ฒ์ด React ์์ฒด์์ ํด๊ฒฐ๋์ด์ผ ํ๋ค๊ณ ์์ง ํ์ ํ์ง ๋ชปํฉ๋๋ค. ๋๋ React๊ฐ React ์์ ์ด ๊ธฐ๋ฅ์ ๊ตฌ์ถํ๋ ๋ฐ ํ์ํ ๋ชจ๋ ํํฌ๋ฅผ ์ ๊ณตํด์ผ ํ๋ค๊ณ ์๊ฐํ๋ ๊ฒฝํฅ์ด ํจ์ฌ ๋ ํฝ๋๋ค.
ํ์ง๋ง ์ ์ ๋์ observe()
ํ๋ค๊ณ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค. ๋ช ๊ฐ์ง ์๊ฐ:
this.props
, this.state
, this.context
๋ฐ ํ์ฌ this.data
๊ฐ ๋ชจ๋ render()
์ ์ฌ์ ์ธ ์ ๋ฐ์ดํฐ ์์ค์
๋๋ค. ์ด๊ฒ์ ๋์๊ฒ ๊ณผ๋ํ ๊ฒ ๊ฐ์ต๋๋ค. ๊ตฌ์ฑ ์์ ์ํ์์ ์์ฉ ํ๋ก๊ทธ๋จ ์ํ๋ฅผ ๋ถ๋ฆฌํ๋ ์์ด๋์ด์
๋๊น? ์ด๊ฒ์ ๊ตญ๊ฐ์ ๊ด๋ จ๋ ๋ช ๊ฐ์ง ๋ฌธ์ ๋ฅผ ๋ช
ํํ๊ฒ ํ๊ณ ๋ถ๋ฆฌํ ์ ์์ง๋ง ์๋ก์ด ์
๋ ฅ์ ๋์
ํ๋ ๋น์ฉ์ด ์ด๋๋ณด๋ค ํฌ์ง ์์ ์ ์๋ค๊ณ ์๊ฐํฉ๋๋ค. this.state
๊ฐ ๊ตฌ์ฑ ์์ ์ํ์๋ง ์ง์ค๋๋๋ก ํ๋ ค๋ฉด this.data
์ ํ๋๋ฅผ this.props
๋๋ this.context
์ถ๊ฐํ์ง ์๋ ์ด์ ๋ ๋ฌด์์
๋๊น?
this.data
์ด๋ฆ์ด ๋๋ฌด ์ผ๋ฐ์ ์
๋๋ค. props๋ ๋ฐ์ดํฐ, state๋ ๋ฐ์ดํฐ, ๋ชจ๋ ์ง์ญ ๋ณ์๋ ๋ฐ์ดํฐ์
๋๋ค. ์ด๋ฆ์ ์๋ฏธ๋ฅผ ์ถ๊ฐํ์ง ์๊ณ ๊ธฐ์กด ์๋ฏธ๋ฅผ ํผ๋์ค๋ฝ๊ฒ ํฉ๋๋ค. ์ ๋ this.observed
๋๋ ์ค์ ๋ก ์๋ฏธ๊ฐ ์๋ ๋ค๋ฅธ ์ด๋ฆ์ ํจ์ฌ ์ ํธํฉ๋๋ค. ๋ฐ๋ผ์ @matthewwithanm ์ ๋๊ธ์ +1:
data
๋ณด๋ค ๋ ๋์ ์ด๋ฆ์ด ์์๊น์? ์๋ฅผ ๋ค์ดobserved
๋ ๋ฉ์๋์ ๋ ๋ช ํํ๊ฒ ์ฐ๊ด๋ฉ๋๋ค.
observe()
๊ฐ ์๋ฒ์์ ์คํ๋๋๋ก ํ๋ฉด ๋ง์ดํธ ํด์ ๊ฐ ์ ๋ ๋ฐ์ํ์ง ์๊ธฐ ๋๋ฌธ์ ์ด๋ก ์ธํด ๋ฐ์ํ ์ ์๋ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ์ ๋ฆฌํ๋ ์ผ์ข
์ ํํฌ๊ฐ ํ์ํฉ๋๋ค.
props
๋๋ state
๋ณ๊ฒฝ๋ ๋๋ง๋ค observe()
๋ค์ ํธ์ถํ๋ฉด(๊ทธ๋ฆฌ๊ณ context
?) observe
๋ ์ฑ๋ฅ์ ์ต์ ํ๋์ด์ผ ํ๋ฉฐ ์ด์์ ์ผ๋ก๋ ์ค์๋ก ๋น์ธ๊ฒ ๋ง๋ค ์ ์์ต๋๋ค. ๊ทธ๊ฒ์ ๋จ๊ฑฐ์ด ๊ธธ์ ์ผ๋ถ๊ฐ ๋ฉ๋๋ค. ๋๋ React Nexus์์ ์ด๊ฒ์ ์ข์ํฉ๋๋ค.
๋ค์ ๋ฐ์ธ๋ฉ์ ์ด์ ๋ฐ์ธ๋ฉ๊ณผ ๋ค๋ฆ ๋๋ค. ์ ๊ฑฐ๋ ๋ฐ์ธ๋ฉ์ ๊ตฌ๋ ์ทจ์๋๊ณ ์ถ๊ฐ๋ ๋ฐ์ธ๋ฉ์ ๊ตฌ๋ ๋ฉ๋๋ค.
๋๋ ์ํ๊ฐ ์ปดํฌ๋ํธ๋ฅผ ๋ณต์กํ๊ฒ ๋ง๋ ๋ค๋ ๊ฒ์ ๋ฏฟ๊ฒ ๋์๊ณ , ๋ด ์์ ์ ์ปดํฌ๋ํธ์์ ๊ทธ๊ฒ์ ๋ ์ฌ์ฉ ํ๊ณ ๋์ ํ์ต๋๋ค . ์ด๊ฒ์ด @fisherwebdev๊ฐ ์ ๊ธฐํ ์ฐ๋ ค( observe
๊ฐ state
์ ์์กดํ๋๋ก ํ๋ ๊ฒ์ด ์ข์ ์๊ฐ์ด๋ผ๊ณ ํ์ ํ์ง ๋ชปํ๋ ์ด์ ์
๋๋ค. State๋ props์ ์์กดํ๊ณ ๊ด์ฐฐ์ state _and_ props์ ์์กดํฉ๋๋ค. ๋๋ฌด ๋ณต์กํ์ง ์์ต๋๊น? ์ฐจ๋ผ๋ฆฌ observe(props)
๊ฐ๊ณ ์ถ์ต๋๋ค.
๋๋ ๋ํ ๊ด์ฐฐ์ด state
์ ์์กดํด์๋ ์ ๋๋ค๋ ๊ฒ์ ๊นจ๋ซ๊ณ ์์ต๋๋ค. ๋๋ถ๋ถ ๊ทธ๋ด ํ์๊ฐ ์๊ธฐ ๋๋ฌธ์
๋๋ค. @gaearon ์ด ์ง์ ํ๋ฏ์ด ์ํ๋ฅผ ํ ๋จ๊ณ ์์ ์์ค์ผ๋ก ๋์ด์ฌ๋ฆฌ๋ ๊ฒ์ ์ถฉ๋ถํ ์ฝ๊ธฐ ๋๋ฌธ์ ๊ด์ฌ์ฌ๋ฅผ ๋ถ๋ฆฌํ๊ณ ๋๋ฉด ๋ ๊น๋ํด์ง๋๋ค. observe
๊ฐ state
์ ์ ์ฌ์ ์ผ๋ก ์์กดํ ์ ์๋ ๊ฒฝ์ฐ ๊ตฌ์ฑ ์์ ๋ด์์ ์
๋ฐ์ดํธ๋ฅผ ์ฒ๋ฆฌํ๋ ๋
ผ๋ฆฌ๊ฐ ํจ์ฌ ๋ ๋ณต์กํด์ง๋๋ค. props
์๋ง ์์กดํ๋ ๊ฒฝ์ฐ componentDidMount
/ componentWillReceiveProps
์ ํฌํฌ ์๋ ํธ๋ค๋ฌ๋ฅผ ๊ฐ์ง ์ ์์ต๋๋ค. ์ค์ ๊ฒฝ๋ก์ ์ฝ๋๊ฐ ์ ์ผ๋ฉด ๋ ๋๋ง ์ฃผ๊ธฐ๊ฐ ๋ ๋จ์ํด์ง๊ณ ๊ตฌ๋
์ ๋ค์ ํธ๋ฆฌ๊ฑฐํ๋ ์๋ํ์ง ์์ ์
๋ฐ์ดํธ ์๋ ์ค์ด๋ญ๋๋ค.
๊ด์ฐฐ(์ํ)์ ๋ํด +1
์ฐ๋ฆฌ๊ฐ ๋ค๋ฃจ๋ ๊ฒ์ด ์ ์์๋ก ๋ ๋์ IMO๊ฐ ๋ฉ๋๋ค.
๋๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก์ React๊ฐ ๊ฐ๋ฅํ ํ ์ ์ฐํด์ผ ํ๋ค๊ณ ์๊ฐํฉ๋๋ค. ๋๋ ๊ด์ฐฐ์ด ์ํ์ ์์กดํ๋ ๊ฒ์ ์ข์ ์๊ฐ์ด ์๋๋ผ๋ ๋ฐ ๋์ํฉ๋๋ค. ์, ๋ณต์กํ ์ ์์ต๋๋ค. ์, ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ ์ํ์ ์์กดํ์ง ์๋ ๊ฒ์
๋๋ค.
๊ทธ๋ฌ๋ ๊ทธ๊ฒ์ React ์ฌ์ฉ์์๊ฒ ํ์ฉ๋์ด์ผ ํ๋ ์ ํ์
๋๋ค.
ํ์ฌ API๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ณ (์๋ฅผ ๋ค์ด ๊ด์ฐฐ ๊ฐ๋ฅํ ๊ฒ ์ด์๊ณผ ํจ๊ป ์๋ํ๋๋ก ํ๊ธฐ ์ํด ์ ์ฐ์ฑ์ ์ถ๊ฐํ๊ธฐ ์ํด ๊ฐ๋ฅํ ํํฌ ์ ์ธ), ๊ด์ฐฐ ๋ฉ์๋์์ ์ํ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ๊ถ์ฅ๋์ง ์์์ ์ค๋ช
ํ๋ ๋ฌธ์๋ฅผ ์ฆ๋ช
ํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
๋๋ ๋ชจ๋ ์ฌ๋์ด ์ณ์ ์ผ์ ํ๊ธฐ๋ฅผ ์ํ๊ณ ์ฐ๋ฆฌ๊ฐ ์ฌ๋ฐ๋ฅธ ๋ฐฉํฅ์ผ๋ก ์ธ๋๋๊ธฐ๋ฅผ ์ํ๋ค๊ณ ๋ฏฟ์ต๋๋ค. ์๋ฝํ์ง ์๋ ์ํ๋ฅผ ๊ด์ฐฐํ๋ฉด ๋ฌธ์์์ "์ด๊ฒ์ ๋ฐํจํด์ ๋๋ค"์ ๊ฐ์ ๊ฒ์ ์ค์๋ก ์ฐพ๋ ๊ฒ๋ณด๋ค ์ฌ์ฉ์์๊ฒ ๋ ์ฝ์ต๋๋ค.
ํธ์ง: ์ฃ์กํฉ๋๋ค. ๋ฐฉ๊ธ flatMap
์ฐพ๊ณ ์์๋ค๋ ๊ฒ์ ๊นจ๋ฌ์์ต๋๋ค. ๋๋ ๊ทธ๊ฒ์ด ๋ฉ์์ง ๋ฐฐ์ด์ ํํํ๊ฒ ํ ๊ฒ์ด๋ผ๊ณ ์๊ฐํ๊ธฐ ๋๋ฌธ์ ํผ๋์ค๋ฌ์ ์ง๋ง ๋ ๋์ ์์ค์์ ์๋ํ๊ณ ์์ต๋๋ค(๋ฉ์์ง ๊ด์ฐฐ ๊ฐ๋ฅ).
์ ์๋ API๋ ํ ๋ฐ์ดํฐ ํ๋์ ๊ฒฐ๊ณผ๊ฐ ๋ค๋ฅธ ๋ฐ์ดํฐ ํ๋์ ๊ฒฐ๊ณผ์ ์ข ์๋๋ ๊ฒฝ์ฐ๋ฅผ ์ฒ๋ฆฌํฉ๋๊น? ์ฆ, ์ฒซ ๋ฒ์งธ ๊ฒฐ๊ณผ๋ฅผ ๋งคํํ๊ณ ๊ด์ฐฐ ๊ฐ๋ฅ ํญ๋ชฉ์ ๋ฐํํฉ๋๋ค.
observe(props, context) {
if (!props.params.threadID) {
return {};
}
const observeThread = ThreadStore.observeGetByID(
{id: props.params.threadID}
);
return {
thread: observeThread,
messages: observeThread.map(thread => {
return MessageStore.observeGetByIDs({ids: thread.messageIDs});
})
};
}
๋๋ ์ผ๋ฐ์ ์ผ๋ก ์ต์ ๋ฒ๋ธ์ ์ต์ํ์ง ์๊ธฐ ๋๋ฌธ์ ์ด ๋ฌธ์ ์ ๋ํด ์์ ํ ํ๋ฆด ์ ์์ต๋๋ค. promise-land์์ ์ด๊ฒ์ ๋งค์ฐ ๊ฐ๋จํฉ๋๋ค. then
์์ promise๋ฅผ ๋ฐํํ๋ฉด ํ์ then
์ด ํด๋น promise๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ๊ธฐ ๋๋ฌธ์
๋๋ค.
this.state
์์กดํด์๋ ์๋๋ค๋ ์๊ฒฌ์ ์ดํดํ์ง ๋ชปํฉ๋๋ค. ์บก์ํ๋ ์ํ๋ ํ์คํ React๋ฅผ ํจ์ฌ ๋ ๋ณต์กํ๊ฒ ๋ง๋ค์ง๋ง ๊ทธ๊ฒ ์ ๋ถ์
๋๋ค. ์บก์ํ๋ ์ํ๊ฐ ์์ผ๋ฉด ๋ฉ๋ชจํ๋ ์ฆ์ ๋ชจ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ง ํ์ํฉ๋๋ค. "Stores"์ ์ฌ์ธํ๋ฉด ๋ค, ์ํ๊ฐ ํ์ํ์ง ์์ง๋ง React์์ ๊ทธ๋ ๊ฒ ํ๋๋ก ๊ท์ ํ ๊ฒ์ ์๋๋๋ค.
์ถ๊ฐ ๋ํผ๋ฅผ ์์ฑํด์ผ ํ๋ ๋ช ๊ฐ์ง ํจํด์ด ์์ง๋ง ์ผ๋ฐ์ ์ธ ์ฌ์ฉ์์๋ ๊ทธ๋ด ํ์๊ฐ ์์ต๋๋ค. ์์ ์ธ์ ๊ด์ฐฐ๋ ๋ฐ์ดํฐ๋ ๊ฐ์ ์ ์ด๋๋ผ๋ ํญ์ ์ํ์ ์์กดํฉ๋๋ค. ๊ด์ฐฐ์ ์์กดํ๋ ๊ฒ์ด ๋์ ์ต๊ด์ ์๋๋ผ๊ณ ์๊ฐํฉ๋๋ค. ์
observe() {
return { items: Items.getPagedItems({ pageIndex: this.state.currentPage }) };
}
observe
๊ฐ state
์ ์์กดํ์ง ์๋๋ผ๋ ์ฌ์ ํ props
๋ฐ context
์ ์์กดํฉ๋๋ค. context
์ ์์กดํ์ง ์๋๋ผ๋ $# observe
์์ ์ฌ์ฉํ๋ ๊ตฌ์ฑ ์์์ ์ํ์ ๋ ๋๋งํ๊ธฐ ์ํด context
๋ฅผ ์ฌ์ฉํ๋ ๊ฐ์ ์ฐธ์กฐ๊ฐ ์์ต๋๋ค.
observe
๋ props๊ฐ ๋ณ๊ฒฝ๋์์ ์ ์๊ธฐ ๋๋ฌธ์ ๋ ๋ ํจ์ค๊ฐ ๋ค์ด๋ ๋๋ง๋ค ์ฌํ๊ฐ๋์ด์ผ ํฉ๋๋ค. ๊ทธ๋ฌ๋ ๊ฒฐ๊ณผ ๊ด์ฐฐ ๊ฐ๋ฅ ํญ๋ชฉ์ ํ์คํ ๋น๊ตํ๊ณ ๋์ผํ ๊ด์ฐฐ ํญ๋ชฉ์ด ๋ฐํ๋๋ ๊ฒฝ์ฐ ๊ตฌ๋
์ทจ์/์ฌ๊ตฌ๋
์ ํ์ง ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๊ฐ๋ณ ์์ฑ(shouldComponentUpdate ์ ์ธ)์ ๋ํด diff๋ฅผ ์ํํ ์ ์์ผ๋ฏ๋ก Map
๋ฅผ ์ ์ ๊ธฐ๋ฅ์ผ๋ก ์ฌ์ฉํ์ฌ ๊ณ ์ ํ ์บ์๋ฅผ ๊ตฌํํ๋ ๊ฒ์ด ์ด์์ ์
๋๋ค. ๊ทธ๋ ๊ฒ ํ๋ฉด ํธ๋ฆฌ์ ์ฌ๋ฌ ๊ตฌ์ฑ ์์์ ๋์ผํ ๊ด์ฐฐ ๊ฐ๋ฅ ํญ๋ชฉ์ ๋ฐํํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด ๋์ผํ ์ฌ์ฉ์๋ฅผ ๋ก๋ํ๋ ์ฌ๋ฌ ๊ตฌ์ฑ ์์. ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ์๋ Observable์ ๋ค์ ๋ง๋ค๊ณ ๊ฒฐ๊ตญ์๋ ํ๋จ ์บ์์ ๋๋ฌํ๊ฒ ๋ฉ๋๋ค. ์ด๊ฒ์ด ๋ฐ๋ก React ์กฐ์ ์ด ์๋ํ๋ ๋ฐฉ์์
๋๋ค. ๊ทธ๋ ๊ฒ ๋๋ฆฌ์ง ์์ต๋๋ค.
์ด observe
ํํฌ๋ ์ํ๊ฐ Observable์์ ์บก์ฒ๋๋ค๋ ์ ์์ React๋ฅผ ์์ ํ ๋ฐ์์ ์ผ๋ก ๋ง๋ค๋๋ก ์ค๊ณ๋์ง ์์์ต๋๋ค. ํ์ฌ ์ฃผ์ ์ค๊ณ ๋ชฉํ๋ ํด๋ก์ ์ ๊ฒฐํฉ๊ธฐ์์ ์ํ๋ฅผ ํธ๋ํํ๋ ๊ฒ์ ํผํ๊ณ ๋์ ๋๊ฒฐ ๋ฐ ๋ถํ์ด ๊ฐ๋ฅํ๊ณ ์์
์ ๊ฐ์ ์ ์ฌ์ ์ผ๋ก ๊ณต์ ํ ์ ์๋ ๊นจ๋ํ๊ณ ๋ณ๋์ ์ํ ํธ๋ฆฌ๋ฅผ ๊ฐ๋ ๊ฒ์
๋๋ค.
๋์ ๋ง์ง๋ง ์์ ์ ์ด๋ฅด๊ฒ ํ๋ ๊ฒ์...
์ฐ๋ฆฌ๋ ์ด๊ฒ์ ํต์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ถ๊ฐํ ํ์๊ฐ _ํ์ํ์ง ์์ต๋๋ค_. ์๋ "๊ณต๊ฐ" ์ธํฐํ์ด์ค๋ mountComponent/receiveComponent์์ผ๋ฉฐ ๊ทธ ์์ ์ ์ฒด ๋ณตํฉ ๊ตฌ์ฑ ์์ ์์คํ ์ ๊ตฌ์ถํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ์ด์ ๋ ๋์ ์ถ์ํ ๋ง๋์ ์ํด ํ์ฑํ๋๋ ๋ค๋ฅธ ๊ฒ์ ๊ตฌ์ถํ ์ ์๊ธฐ ๋๋ฌธ์ ์ถ์ํ ๋ง๋๋ฅผ ๋์ด๋ ๊ฒ์ด ํจ์ฌ ๋ ๊ฐ๋ ฅํ๋ค๋ ๊ฒ์ ์ฌ์ฉํ๋ ์ฌ๋์ ๋ง์ง ์์ต๋๋ค. ๊ตฌ์ฑ ์์ ์ ์ฒด ์ต์ ํ์ ๊ฐ์.
React์ ์ฃผ์ ๋ชฉ์ ์ ์ํ๊ณ์ ์๋ก ๋ค๋ฅธ ์ถ์ํ๊ฐ ๊ณต์กดํ ์ ์๋๋ก ๊ตฌ์ฑ ์์ ๊ฐ์ ๊ณ์ฝ์ ์์ฑํ๋ ๊ฒ์ ๋๋ค. ๊ทธ ์ญํ ์ ์ค์ํ ๋ถ๋ถ์ ๊ณตํต ๊ฐ๋ ์ ๋ํ ์ถ์ํ ์์ค์ ๋์ฌ ์๋ก์ด ๊ต์ฐจ ๊ตฌ์ฑ ์์ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์๋๋ก ํ๋ ๊ฒ์ ๋๋ค. ์๋ฅผ ๋ค์ด ํ์ ํธ๋ฆฌ์ ๋ชจ๋ ์ํ๋ฅผ ์ ์ฅํ ๋ค์ ํ์ ํธ๋ฆฌ๋ฅผ ๋ถํ์ํต๋๋ค. ๋๋ ์๋ฒ์์ ์๋ ๋ง์ดํธ ํด์ ๋ฅผ ํฌํจํ๊ฑฐ๋ ์๋ฒ์์ ์กฐ์ ์ ํ์ด๋ฐ ์ธก๋ฉด์ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
์ด ๋ชจ๋ ๊ฒ์ ๋ง์๊ณ ๊ท ์ผํ๊ฒ ๋ง๋ค๊ธฐ ์ํด ํฌํจ๋ ์ผ๋ถ ๋ฐฐํฐ๋ฆฌ๋ฅผ ์ ๊ณตํ๋ ๊ฒ๋ ์ค์ํฉ๋๋ค.
๋ง์ดํฌ๋ก ๋ชจ๋ํ(์: ์๋ก์ด ๋ผ์ดํ ์ฌ์ดํด ํํฌ ์ถ๊ฐ)๊ฐ ํ๋ ์์ํฌ์ ๋น๋ํ๋ ๊ฒ๋ณด๋ค ์๋ฐํ ๋งํ๋ฉด ์์ํ ์น๋ฆฌ๊ฐ ์๋๋ผ๋ ์ ์ ๊นจ๋ซ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ๋ํ ์์คํ ์ ์ฒด์ ์ถ์ํ์ ๋ํด ๋ ์ด์ ์ถ๋ก ํ ์ ์์์ ์๋ฏธํฉ๋๋ค.
์ด์ ๊ฐ์ ๊ฒ์ด "์ฒ ํ/์ค๊ณ ๋ชฉํ/๋น๋ชฉํ"๋ก ๋ฌธ์์ ์์์ผ๋ฉด ํฉ๋๋ค.
React์ ์ฃผ์ ๋ชฉ์ ์ ์ํ๊ณ์ ์๋ก ๋ค๋ฅธ ์ถ์ํ๊ฐ ๊ณต์กดํ ์ ์๋๋ก ๊ตฌ์ฑ ์์ ๊ฐ์ ๊ณ์ฝ์ ์์ฑํ๋ ๊ฒ์ ๋๋ค. ๊ทธ ์ญํ ์ ์ค์ํ ๋ถ๋ถ์ ๊ณตํต ๊ฐ๋ ์ ๋ํ ์ถ์ํ ์์ค์ ๋์ฌ ์๋ก์ด ๊ต์ฐจ ๊ตฌ์ฑ ์์ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์๋๋ก ํ๋ ๊ฒ์ ๋๋ค.
์ด๊ฑฐ ๋๋ฌด ์ข์. ๋๋ ์ด๊ฒ์ด ์ผ์ข ์ ๋ฌธ์์ ์๋ค๋ฉด ์ข์ ๊ฒ์ด๋ผ๋ @gaearon์ ๋ง์ ๋์ํฉ๋๋ค.
์ฐ๋ฆฌ๋ ํ์คํ ์ด๊ฒ์ ํต์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ถ๊ฐํ ํ์๊ฐ ์์ต๋๋ค.... ๊ทธ๋ฌ๋, ๋ ๋์ ์ถ์ํ ๋ง๋์ ์ํด ํ์ฑํ๋๋ ๋ค๋ฅธ ๊ฒ์ ๊ตฌ์ถํ ์ ์๊ธฐ ๋๋ฌธ์ ์ถ์ํ ๋ง๋๋ฅผ ๋์ด๋ ๊ฒ์ด ํจ์ฌ ๋ ๊ฐ๋ ฅํ๋ค๋ ๊ฒ์ ์ฌ์ฉํ๋ ์ฌ๋์ ๋ง์ง ์์ต๋๋ค. ๊ตฌ์ฑ ์์ ์ ์ฒด ์ต์ ํ์ ๊ฐ์.
๋๋ (์ ์ด๋ ๋๋ฅผ ์ํด) ๊ณผ๋ฌตํจ์ ๋ค๋ฅธ API๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ด ์๋๋ผ ์๋ํ๊ธฐ ์ํด ๋น์ธ์ด(์์ง ์ ์๋๊ณ ์๋) ๊ตฌ์กฐ์ ์์กดํ๋ API๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค. ์ด๊ฒ์ ์์ ํ ์ ๋ ์ ์์ง๋ง Promise ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์๋ก๋ฅผ ์ ๋ขฐํ ์ ์๋ Promise ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ํด ๊ฑฑ์ ํฉ๋๋ค. ์ด๋ก ์ธํด ๋ถํ์ํ ๋ํ ๋ฐ ๋ฐฉ์ด ์์ ์ด ๋ฐ์ํ์ฌ ์ฌ๋ฐ๋ฅด๊ฒ ํด๊ฒฐ๋์๋์ง ํ์ธํ๊ณ ์ต์ ํ ๊ธฐํ๊ฐ ์ ํ๋ฉ๋๋ค. . ๋๋ ๋ ๋์ ๊ฒ์ ๊ฒฐ์ฝ ๋ณ๊ฒฝํ ์ ์๋ ๊นจ์ง ๊ตฌํ์ผ๋ก jQuery์ฒ๋ผ ๊ฐํ๊ฒ ๋ ๊ฒ์ ๋๋ค.
@jquense ์ ์ ์ผ๋ก ๋์ํฉ๋๋ค. ์ค๋์ ์ ์ด ํํฌ๋ฅผ ์ถ๊ฐํ๊ณ ์ถ์์ต๋๋ค. (์๋ ์คํ: https://github.com/reactjs/react-page/commit/082a049d2a13b14199a13394dfb1cb8362c0768a )
2๋ ์ ๋ง ํด๋ ์์ง ํ์คํ๊น์ง๋ ๋ฉ์๋ค๋ ๊ฒ์ด ๋ง์ค์ฌ์ก๋ค. ์ฝ์ด๋ฅผ ์ถ๊ฐํ๊ธฐ ์ ์ ํ์ค ํ๋กํ ์ฝ์ ์ํ์ต๋๋ค.
๋ง์ ํ๋ ์์ํฌ๊ฐ Observable๊ณผ ๊ฐ์ ๊ฒ์ ๋ํ ํ์์ฑ์ ๋์ํ๊ณ ํ์คํ๊ฐ ์ ๋ง์ ๋ง๋ API๊ฐ ์ ์๋๋ ์ง์ ์ ๋๋ฌํ๊ณ ์๋ค๊ณ ์๊ฐํฉ๋๋ค. ๋๋ ์ฐ๋ฆฌ๊ฐ ๊ทธ๊ฒ์ ์ฝ๊ฐ ์กฐ์ ํด์ผ ํ ํ์๊ฐ ์๋ค๊ณ ํ์ ํ์ง๋ง ๋์ ์์ค์ ์ํคํ ์ฒ๊ฐ ์๋ํ๋ ํ ๊ต์ฒด ๊ฐ๋ฅํ๊ณ ๊ฒฐ๊ตญ ์๋ ดํด์ผ ํฉ๋๋ค.
ํ๋ผ๋ฏธ์ค์์ ์ผ์ด๋ ์ผ์ Observable์ด ๊ฒช์ง ์๋ ํน์ ์์ญ์์ API ๋ฐ ๋๋ฒ๊น ์คํ ๋ฆฌ๊ฐ ์ฌ๊ฐํ๊ฒ ๋ถ์กฑํ๋ค๋ ๊ฒ์ ๋๋ค. Promises๊ฐ ์ต์ํ์ ๋ถ์์ ์๋ฃจ์ ์ ํ์คํํด์ผ ํ๋ ๋ณด๋ค ์๋ฒฝํ ์คํ ๋ฆฌ์ ๋๋ค.
์๊ฒฌ์ ์ ์ผํ ์ฐจ์ด์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค. ๋ด๊ฐ ๊ด์ฐฐํ Observables(์ ํญํ ์ ์์์ต๋๋ค. ์ฃ์กํฉ๋๋ค)๋ Zalgo ์ ์ฌ๋ ฅ์ ๋๋ค. Observable์ด ๊ตฌ๋ ์ ๋ํ ์๋ต์ผ๋ก ๋๊ธฐ์ ์ผ๋ก ๊ฐ์ ํธ์ํ ์ ์๋์ง ์ฌ๋ถ์ ๋๋ค. ์ด๋ค ์ฌ๋๋ค์ ๊ทธ๊ฒ์ ๋ฐ๋ํ๋ ๊ฒ์ฒ๋ผ ๋ณด์ด์ง๋ง ๋ด๊ฐ ์ดํดํ๋ ํ React์ Observable ์ฌ์ฉ์ ์ด๊ฒ์ ์์กดํ ๊ฒ์ ๋๋ค. ๊ทธ๊ฒ์ ๋ํด ๋ ผํํ ์ ์์ต๋๊น?
์ผ๋ฐ์ ์ผ๋ก ์๋น์๊ฐ ํญ์ ์ ์ดํ ์ ์๊ณ observeOn
์ ๊ฐ์ ๊ฒ์ผ๋ก ํญ์ ๋น๋๊ธฐ๋ฅผ ์ ํํ ์ ์๊ธฐ ๋๋ฌธ์ Zalgo๊ฐ Observable์ ๋ฌธ์ ๊ฐ ์๋ค๋ ๊ฒ์ ์ฐพ์ง ๋ชปํ์ต๋๋ค.
๋ง์นจ๋ด ์ด์ ๋ํ ํฉ์๊ฐ ์ด๋ฃจ์ด์ง๊ฒ ๋์ด ๊ธฐ์ฉ๋๋ค. ๊ฐ์ธ์ ์ผ๋ก Observable๋ณด๋ค ์ฑ๋์ ์ ํธํ์ง๋ง Observable์ด ์ธ์ด์ ์ถ๊ฐ๋๋ค๋ฉด ๋ ์ด์ ๊ธฐ๋ค๋ฆด ํ์๊ฐ ์๋ค๋ ๋ฐ ๋์ํฉ๋๋ค.
์ฆ, ๊ธฐ๋ณธ API๋ฅผ ์ค์ํ๋ ๋น Observable๊ณผ ์๋ํ ์ ์๋๋ก API๋ฅผ ์ถฉ๋ถํ ์ด์ด ๋๋๋ก ํฉ์๋ค.
๋๋ Zalgo๋ ๋ฌธ์ ๋ผ๊ณ ์๊ฐํ์ง ์์ต๋๋ค. ๊ทธ๋ฌ๋ Observable์ ์ฌ์ฉํ๋ฉด ์ค์ผ์ค๋ฌ๋ฅผ ์ฌ์ฉํ์ฌ ์ํ๋ ๊ฒฝ์ฐ ๋น๋๊ธฐ๋ฅผ ํ์ธํ ์ ์์ต๋๋ค. ์ด์ ๊ธฐ๋ณธ ์ค์ผ์ค๋ฌ๋ ๋น๋๊ธฐ์ด๋ฏ๋ก ํ์์ ๋ฐ๋ผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
@sebmarkbage ๋๋ ๋น์ ์ด ๋ด ์ฐ๋ ค์ ๋๋ถ๋ถ์ ํด๊ฒฐํ๋ค๊ณ ์๊ฐํ๋ฉฐ ์ด์ ์ด๊ฒ์ ํ๋ ์์ํฌ์ ์ถ๊ฐํ๋ ์ด์ ์ ๋ด
๋๋ค. ๊ทธ๋ฌ๋ this.data
์ ๋ํด ์ธ๊ธํ ์ ์์ต๋๊น? -- (1) ํด๋น ํ๋๋ฅผ props/context/state๋ก ์ ์ ์/์์ด์ผ ํฉ๋๊น, ์๋๋ฉด (2) ์ด๋ฆ์ ๋ฐ๊ฟ ์ ์์ต๋๊น?
์ฝ๊ฐ ์์ ๊ฑฐ ํ๊ธฐ -yํ์ง๋ง ์ด์จ๋ ๊ณ์ ... Zalgo ๋ฌธ์ ๋ API ๊ธฐ๋ ์ธก๋ฉด์์ ์ค์ํ์ง ์ฌ๋ถ์ ๊ดํ ๊ฒ์ด ์๋๋ผ ๊ด์ฐฐ ๊ฐ๋ฅํ ์ํธ ์ด์ฉ์ฑ ๋ฐ ๊ตฌํ ์ฉ์ด์ฑ ์ค ํ๋์ ๋๋ค. Promise ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ธ๊ณ๋ฅผ ๋ค๋ฅธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ Promise๋ฅผ ์ฒ๋ฆฌํ ๋ ๋งค์ฐ ๋ฐฉ์ด์ ์ด์ด์ผ ํ๋ ์ฑ๊ฐ์ ์์น์ ๋์ด๊ฒ ํ Zalgo์ ๋ํ ์ด๊ธฐ ๋์๊ฐ ์์ต๋๋ค. (์๋์์ ๋ฐ๋ณต๋๋ ๋ด ์์ ์์ )
...ํ๋ก๋ฏธ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ(์ฌ์ ๋ถ๋ง ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํฌํจ)๊ฐ ์๋ก๋ฅผ ์ ๋ขฐํ ์ ์๋ ๊ณณ์์๋ ์ฌ๋ฐ๋ฅด๊ฒ ํด๊ฒฐ๋์๋์ง ํ์ธํ๊ธฐ ์ํด ๋ถํ์ํ ๋ํ ๋ฐ ๋ฐฉ์ด ์์ ์ด ํ์ํฉ๋๋ค.
์ด๊ธฐ ์ฝ์์ด ๋ชจ๋ ๋น๋๊ธฐ ํด๊ฒฐ์ ์ค์ํ์ง ์์๊ธฐ ๋๋ฌธ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ง์ ๋๋๋ผ๋ thenables
๊ฐ ์ ๋ขฐํ ์ ์๋ค๊ณ ๊ฐ์ ํ ์ ์์ด ์ ์ฌ์ ์ต์ ํ๊ฐ ์ค๋จ๋๋ ์์น์ ์์ต๋๋ค. ์ด๊ฒ์ React๊ฐ ์ฌ์ฉํ Observable ๊ตฌํ์ ์ ๊ณตํ์ง ์์ ๊ฒ์ด๋ฉฐ(๋๊ฐ ๊ทธ๊ฒ์ ์ํ๊ฒ ์ต๋๊น?) ์ฌ๊ธฐ์์ ํนํ ๊ด๋ จ์ด ์๋ ๊ฒ์ผ๋ก ์๊ฐ๋ฉ๋๋ค. ์ฐ๋ฆฌ๋ Observable์ด ์ ๊ณตํ๋ ๋งค์ฐ ์ฌ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ ์ ์ผ๋ก ์์กดํ ์ ์๊ฒ ๋๊ธฐ๊น์ง๋ ๋ช ๋
์ด ๊ฑธ๋ฆด ๊ฒ์
๋๋ค. ์ํธ์์ฉ์ด ์ค์ํฉ๋๋ค. @gaearon ์ ์์ ์ ๋ํ์ฌ React๊ฐ ๋๊ธฐํ ํธ์ถ์ ์์กดํ๊ณ ํญ์ ๋น๋๊ธฐ์์ผ๋ก ์ง์ ๋์ด ์๋ ๊ฒฝ์ฐ jquery์ ๊ฐ์ ์์น๊ฐ ๋ถ๋ ๊ตฌํ์ ๊ฐํ๊ฒ ๋ฉ๋๋ค.
์์ ํ ๋์ ํด. ์ค๋์ ์ ์ด ํํฌ๋ฅผ ์ถ๊ฐํ๊ณ ์ถ์์ต๋๋ค. 2๋ ์ ๋ง ํด๋ ์์ง ํ์คํ๊น์ง๋ ๋ฉ์๋ค๋ ๊ฒ์ด ๋ง์ค์ฌ์ก๋ค. ์ฝ์ด๋ฅผ ์ถ๊ฐํ๊ธฐ ์ ์ ํ์ค ํ๋กํ ์ฝ์ ์ํ์ต๋๋ค.
์ ๋ ์ฐธ์ํ๊ณ ์๊ฐํ๋ ๊ธฐ์๊ณ ํ์คํ ์๋ก๊ฐ โโ๋ฉ๋๋ค. :) ๊ทธ๋ฆฌ๊ณ ์ผ๋ฐ์ ์ผ๋ก ๋๋ Promise์ ์กฐ๊ธฐ ์ฑํ์ด ๋ด๊ฐ ์ฌ๊ธฐ์ ๋ ผ์ํ๋ ๋จ์ ์ ๊ฐ์น๊ฐ ์๋ค๊ณ ์๊ฐํ๋ฏ๋ก ๋ด ์ฐ๋ ค๋ฅผ ์ซ์ดํ๊ฑฐ๋ ์น์ธํ์ง ์๋ ๊ฒ์ผ๋ก ๋ฐ์๋ค์ด์ง ๋ง์ญ์์ค. ๋๋ ์ด์ ๋ํ ์ผ๋ฅ API์ ์ ๋ง์ ๊ฝค ํฅ๋ถํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ๋๋ ๋ํ Observable์ด ์ฌ๊ธฐ์์ ์ผ๋ง๋ ์ข์/๊ฐ์ฅ ํฉ๋ฆฌ์ ์ธ ์ ํ์ธ์ง ์ ์ ์์ต๋๋ค.
"Observable์ RxJS ๊ณ์ฝ์ด ๋ ์ผ๋ฐ์ ์ด๊ณ ๋๊ธฐ ์คํ์ ํ์ฉํ๊ธฐ ๋๋ฌธ์ ์ฌ์ฉํด์ผ ํ์ง๋ง @jhusain ์ ์ ์์ด ๋ ์ผ๋ฐ์ ์ผ๋ก ์ฌ์ฉ๋๋ฉด ๋์ ํด๋น ๊ณ์ฝ์ผ๋ก ์ ํํ ๊ฒ์ ๋๋ค."
์ปจํ ์คํธ๋ฅผ ์กฐ๊ธ ๋ ์ถ๊ฐํ๋ฉด ๋ฉ๋๋ค. ๋น์ฐจ๋จ ์ญ์์ ์ฌ์ฉํ์ฌ ๋น๋๊ธฐ ์คํธ๋ฆผ ์ฒ๋ฆฌ์ ๋ํ ํ์ค์ ์ ๊ณตํ๋ Reactive Streams ์ด๋์ ํฐ๋ธ(http://www.reactive-streams.org/)๊ฐ ์์ต๋๋ค. ์ฌ๊ธฐ์๋ ๋คํธ์ํฌ ํ๋กํ ์ฝ๋ฟ๋ง ์๋๋ผ ๋ฐํ์ ํ๊ฒฝ(JVM ๋ฐ JavaScript)์ ๋ชฉํ๋ก ํ๋ ๋ ธ๋ ฅ์ด ํฌํจ๋ฉ๋๋ค.
ํ์ฌ ์ฃผ์ ๊ตฌํ์ fe Akka Streams ๋๋ RxJava์
๋๋ค. RxJ๊ฐ ์ด๋ฏธ ๋์ผํ ์ธํฐํ์ด์ค, ๊ตฌ๋
์์ ํ์ฌ ์ธํฐํ์ด์ค๋ฅผ ์ค์ํ๋์ง ๋ชจ๋ฅด๊ฒ ์ต๋๋ค.
@jhusain ์ ์ ์์ด ๋ฌด์์ธ์ง ๋ ๋ฐํ ์ ์์ต๋๊น?
React๊ฐ ์ด ์ด๋์ ํฐ๋ธ๋ฅผ ์๊ฒฉํ ์ค์ํด์ผ ํ๋์ง ๋ชจ๋ฅด๊ฒ ์ต๋๋ค. ํ์ํ ๊ฒฝ์ฐ RxJ(์ค์ํ ๊ฒ์ด๋ผ๊ณ ๊ฐ์ )๋ฅผ ์ค๊ฐ์ ๋ฃ๊ณ React ์ธํฐํ์ด์ค์ ์ ์ํ๊ณ RxJ์ ๋ํ ์ญ์๊ณผ ๊ฐ์ ๊ณ ๊ธ ๊ฐ๋ ์ ํ์ฉํ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค. ๋ง์ด ์ ์ํ์ง ์์๋ ๋จ).
์ด ์ด๋์ ํฐ๋ธ์ ๋ํ ์ ์ฅ์ด๋ ๋ชฉํ๊ฐ ์์ต๋๊น?
@vladap ๋๋ ์ด๊ฒ์ด @jhusain์ ์ธ๊ธ๋ ์ ์์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
@jhusain ์ ์ฝ์์ผ๋ฉฐ ํฅํ ์ด ์ฌ์์ผ๋ก ์ด๋ํ ๋๊ธฐ๊ฐ ํ์คํ์ง ์์ต๋๋ค. ํน๋ณํ ์ฅ์ ์ด ์๋์?
Reactive-streams ์ฌ์์ ๋ ํฐ ์ง์์ ์ ๊ณตํ๋ฉฐ ์ด๋ฏธ ๋ฒ์ 1.0์ ์์ต๋๋ค. RxJava๋ ์ด๋ฏธ ์ด ์ฌ์์ ๊ตฌํํ๊ณ ์๊ธฐ ๋๋ฌธ์ ๋๋ RxJ๊ฐ ๋ฐ๋ฅผ ๊ฒ์ด๋ผ๊ณ ๊ฐ์ ํฉ๋๋ค(๊ทธ๋ฌ๋ ํ์ธํ์ง๋ ์์์ต๋๋ค).
์ด ๋ธ๋ก๊ทธ ๋ Akka ์คํธ๋ฆผ์ ์ฌ์ฉํ๋ ๋ช ๊ฐ์ง ์์ ํจ๊ป ์ธํฐํ์ด์ค๋ฅผ ์์ฝํฉ๋๋ค.
๋ฐฑ์๋์ ํ๋ก ํธ์๋์์ ๋์ผํ ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ๋ช ๊ฐ์ง ์ด์ ์ด ์์์ ์ ์ ์์ต๋๋ค. ์ฃผ๋ก ๋ ๋ค์์ ์์ ํ๊ธฐ ๋๋ฌธ์ ๋๋ค. ๋ฐฑ์๋์ ํ๋ก ํธ์๋ ๊ทธ๋ฃน ๊ฐ์ ํ๋ ฅ์ ๋์์ด ๋ ์ ์์ง๋ง ๋ค๋ฅธ ํํธ์ผ๋ก๋ websocket ๋๋ sse๊ฐ ์คํธ๋ฆฌ๋ฐ์ ์ํ ์ค์ ํตํฉ ์ง์ ์ด๋ผ๊ณ ๊ฐ์ ํฉ๋๋ค.
์ง๊ธ์ www.reactive-streams.org ์์ ๊ตฌํ์ ๋ชฉ๋ก์ ์ฐพ์ ์ ์์ง๋ง ๋ง์ง๋ง์ผ๋ก ํ์ธํ ๊ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
Bjรถrn Antonsson โ Typesafe Inc.
๊ฐ๋น ๋น์ด๋ง โ Oracle Inc.
์กด ๋ธ๋ฆฌ์ค๋น โ Pivotal Software Inc.
์กฐ์ง ์บ ๋ฒจ โ Netflix, Inc
๋ฒค ํฌ๋ฆฌ์คํ
์จ โ Netflix, Inc
๋งํฐ์์ค ๋์๋์ธ โ spray.io
๋ง๋ฆฌ์ฐ์ค ์๋ฆญ์ผ โ Twitter Inc.
ํ ํญ์ค โ Red Hat Inc.
Viktor Klang โ Typesafe Inc.
Roland Kuhn ๋ฐ์ฌ โ Typesafe Inc.
Doug Lea โ SUNY Oswego
์คํ
ํ ๋ง๋๋ โ Pivotal Software Inc.
Norman Maurer โ Red Hat Inc.
Erik Meijer โ Applied Duality Inc.
ํ ๋ ๋ชฝ๊ณ ๋ฉ๋ฆฌ - Kaazing Corp.
ํจํธ๋ฆญ ๋
ธ๋์ โ Typesafe Inc.
์ํ๋ค์ค ๋ฃจ๋ํ โ spray.io
Endre Varga โ Typesafe Inc.
์ด์ฉ๋ฉด ๋ด๊ฐ ๋๋ฌด ๋ฉ๋ฆฌ ๊ฐ ์๋ ์์ง๋ง ๋ ํฐ ๋งฅ๋ฝ์ด ๋ฏธ๋์ ๊ฒฐ์ ์ ๋์์ด ๋ ์ ์๋ค๊ณ ๋ฏฟ์ต๋๋ค.
@vladap ๋ด๊ฐ ์ดํดํ๊ณ github ๋ฌธ์ ์์ ๋ณธ ๊ฒ์์ @jhusain ์ ์ด๋ฏธ ๊ทธ๋ค๊ณผ ํจ๊ป ์์
ํ๊ณ ์์ผ๋ฏ๋ก ๊ทธ๋ ๊ฒ ๋ง์ ๋ฌธ์ ๊ฐ ์์ ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
์ธํฐํ์ด์ค ๊ด์ ์์ ๋ค๋ฅธ github ๋ฌธ์ ๋ฐ ๊ธฐํ ์ฌ์ ๋ฌธ์์์๋ ํ์
ํ ์ ์๋ ๊ฒ์์ ๊ด์ฐฐ์๋ ๋ค์๊ณผ ๊ฐ์ ์์ฑ๊ธฐ ์ธํฐํ์ด์ค๋ฅผ ํ์คํ ์กด์คํ ๊ฒ์
๋๋ค.
{
next(value),
throw(e),
return(v)
}
๋ฐ์์ ๋ํด ์์ ํด์ผ ํ๋ ์ธํฐํ์ด์ค๋ฅผ ์กด์คํ๋ ๋จ์ผ '๊ตฌ๋ ' ๋ฐฉ๋ฒ์ผ๋ก ๋งค์ฐ ๊ธฐ๋ณธ์ ์ธ ๊ด์ฐฐ ๊ฐ๋ฅ ํญ๋ชฉ์ ๊ตฌํํ๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค.
๊ฐ์ ๊ธฐ๋ฅ์ ๊ฐ์ง ๋ค๋ฅธ ์ด๋ฆ์ฒ๋ผ ๋ณด์ด์ง๋ง ๊ทธ๋ฐ ์๋ฏธ์์๋ ๊ด์ฐฎ์ต๋๋ค. ์๋ง๋ ์ฌ์์์์ ๊ฐ์ ์ด๋ฆ์ ์ ํธํ ๊ฒ์ด์ง๋ง ๊ฒฐ๊ตญ์๋ ์ด๋ฌํ ๋ฐฉ๋ฒ์ด ๋์ผํ๊ฒ ์ํ๋๋ ํ ํฌ๊ฒ ์ ๊ฒฝ ์ฐ์ง ์์ต๋๋ค.
onSubscribe()์ ํด๋นํ๋ ๋๋ฝ์ ํ๊ฐํ ์ ์์ต๋๋ค. ๋ด๊ฐ ์ธ๊ธํ ๋ธ๋ก๊ทธ์์ ์ ์๋ ๊ทธ๊ฒ์ด ๋ฐฐ์์ ์ ์ดํ๋ โโํต์ฌ์ด๋ผ๊ณ ๋งํฉ๋๋ค. ๋ค๋ฅธ ์ฌ์ฉ ์ฌ๋ก๊ฐ ์๋์ง ๋ชจ๋ฅด๊ฒ ์ต๋๋ค. ์ด๊ฒ์ผ๋ก๋ถํฐ ๋๋ React๊ฐ ๋ฐฐ์ ์ ์ด์ ์ ๊ฒฝ ์ฐ์ง ์๊ฑฐ๋ ๊ทธ๊ฒ์ ๋ํ ๋ค๋ฅธ ์ ๋ต์ด ์๋ค๊ณ ๊ฐ์ ํฉ๋๋ค. ๊ทธ๊ฒ์ ๋ณต์กํ ์ผ์ด๋ฏ๋ก React ๊ด์ฌ์ฌ๊ฐ ์๋์ ์ดํดํฉ๋๋ค.
์ ๋ต์ด ์ ์ ๋ฐ๋ผ ์๋ค๋ ๊ฒ์ ์ฌ๋ฐ๋ฅด๊ฒ ์ดํดํ๊ณ ์์ต๋๊น? ์ฑ์ด ๋ณต์กํ๊ณ ์ญ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ผ๋ฉฐ RxJS์ ๊ฐ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๊ทธ ์ฌ์ด์ ๋ฌด์ธ๊ฐ๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ React ๊ตฌ์ฑ ์์๋ฅผ fe websocket์ ์ง์ ์ฐ๊ฒฐํ๋ฉด ์ฑ์ด ๊ฐ๋จํ๊ณ ์ ๋ฐ์ดํธ๊ฐ ๋๋ฆฌ๊ธฐ ๋๋ฌธ์ ์ญ์ ๋ฌธ์ ๊ฐ ์์ต๋๋ค.
ํฅํ ECMAScript์ ๋ํด ์ ์๋ ๊ด์ฐฐ ๊ฐ๋ฅํ ์ธํฐํ์ด์ค๋ ์ด๋์์ ์ฐพ์ ์ ์์ต๋๊น? ์ด๋ฏธ ์๋ ๊ฒฝ์ฐ.
ํ์ฌ ์ ์์ ์ฌ๊ธฐ์์ ์ฐพ์ ์ ์์ต๋๋ค:
https://github.com/jhusain/asyncgenerator
JH
2015๋ 5์ 7์ผ ์ค์ 2์ 32๋ถ์ vladap [email protected] ์์ ๋ค์๊ณผ ๊ฐ์ด ์ผ์ต๋๋ค.
ํฅํ ECMAScript์ ๋ํด ์ ์๋ ๊ด์ฐฐ ๊ฐ๋ฅํ ์ธํฐํ์ด์ค๋ ์ด๋์์ ์ฐพ์ ์ ์์ต๋๊น? ์ด๋ฏธ ์๋ ๊ฒฝ์ฐ.
โ
์ด ์ด๋ฉ์ผ์ ์ง์ ํ์ ํ๊ฑฐ๋ GitHub์์ ํ์ธํ์ธ์.
Reactive Streams Proposal(RSP)์ ์ญ์์ ์ฒ๋ฆฌํ๋ Observable์ ๋์ ํ๊ธฐ ๋๋ฌธ์ TC-39 ์ ์๋ณด๋ค ๋ ๋์๊ฐ๋๋ค. RSP Observable์ ์ญ์์ ์กด์คํ๋ฉด์ ๋คํธ์ํฌ๋ฅผ ํตํด ์คํธ๋ฆผ์ ํจ์จ์ ์ผ๋ก ์ ์กํ๋๋ก ์ต์ ํ๋์์ต๋๋ค. ์ด๊ฒ์ ๋ถ๋ถ์ ์ผ๋ก RxJava์์ ์ํ๋ ์์ ์ ๊ธฐ๋ฐ์ผ๋ก ํ๋ฉฐ, ์ด๋ ๋งค์ฐ ์ธ์์ ์ธ ์์ง๋์ด๋ง ๋ถ๋ถ์ ๋๋ค(์ ์ฒด ๊ณต๊ฐ: Netflix์ ๋๋ฃ Ben Christensen์ด ์ค๊ณํ์ต๋๋ค).
๋ณด๋ค ์์์ ์ธ Observable ์ ํ์ ํ์คํํ๊ธฐ๋ก ๊ฒฐ์ ํ ์ฃผ๋ ์ด์ ๋ ์ฃผ์์ ๋๋ค. ๋ ์์์ ์ธ Observable์ ES2015 Iterable ๊ณ์ฝ์ ์ด์ค์ผ๋ก, ์ ํ์ด ์ ์ด๋ ES2015์์ ์ด๋ฏธ ํ์คํ๋ ์ ํ๋งํผ ์ ์ฐํ๋ค๋ ๊ท์คํ ๋ณด์ฅ์ ์ ๊ณตํฉ๋๋ค. ๋ํ JS์๋ ๋ฐฐ์์ด ํ์ํ์ง ์์ Observable์ ๋ํ ๋ค์ํ ์ฌ์ฉ ์ฌ๋ก๊ฐ ์์ต๋๋ค. ๋ธ๋ผ์ฐ์ ์์ DOM์ ํธ์ ์คํธ๋ฆผ์ ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ์ฑํฌ์ด๋ฉฐ ๋ฒํผ์ฒ๋ผ ํจ๊ณผ์ ์ผ๋ก ์๋ํฉ๋๋ค. RSP ์ ํ์ด ๋ ๋ณต์กํ๋ค๋ ์ ์ ๊ฐ์ํ ๋ ์ฐ๋ฆฌ์ ์ ๊ทผ ๋ฐฉ์์ ๋ ์์์ ์ธ ์ ํ์ ๋จผ์ ํ์คํํ ๋ค์ ๋์ค์ ๋ ๊ณ ๊ธ ์ ํ์ ๊ตฌํํ ์ฌ์ง๋ฅผ ๋จ๊ฒจ๋๋ ๊ฒ์ ๋๋ค. ์ด์์ ์ผ๋ก๋ ์ฌ์ฉ์ ์์ญ์์ ๊ฒ์ฆ๋ ๋๊น์ง ๊ธฐ๋ค๋ ค์ผ ํฉ๋๋ค.
์ฐธ๊ณ ๋ก RxJS๋ ํ์ฌ RSP Observable์ ๊ตฌํํ ๊ณํ์ด ์์ต๋๋ค.
JH
2015๋ 5์ 7์ผ ์ค์ 2์ 30๋ถ์ vladap [email protected] ์์ ๋ค์๊ณผ ๊ฐ์ด ์ผ์ต๋๋ค.
๊ฐ์ ๊ธฐ๋ฅ์ ๊ฐ์ง ๋ค๋ฅธ ์ด๋ฆ์ฒ๋ผ ๋ณด์ด์ง๋ง ๊ทธ๋ฐ ์๋ฏธ์์๋ ๊ด์ฐฎ์ต๋๋ค. ์๋ง๋ ์ฌ์์์์ ๊ฐ์ ์ด๋ฆ์ ์ ํธํ ๊ฒ์ด์ง๋ง ๊ฒฐ๊ตญ์๋ ์ด๋ฌํ ๋ฐฉ๋ฒ์ด ๋์ผํ๊ฒ ์ํ๋๋ ํ ํฌ๊ฒ ์ ๊ฒฝ ์ฐ์ง ์์ต๋๋ค.
onSubscribe()์ ํด๋นํ๋ ๋๋ฝ์ ํ๊ฐํ ์ ์์ต๋๋ค. ๋ด๊ฐ ์ธ๊ธํ ๋ธ๋ก๊ทธ์์ ์ ์๋ ๊ทธ๊ฒ์ด ๋ฐฐ์์ ์ ์ดํ๋ โโํต์ฌ์ด๋ผ๊ณ ๋งํฉ๋๋ค. ๋ค๋ฅธ ์ฌ์ฉ ์ฌ๋ก๊ฐ ์๋์ง ๋ชจ๋ฅด๊ฒ ์ต๋๋ค. ์ด๊ฒ์ผ๋ก๋ถํฐ ๋๋ React๊ฐ ๋ฐฐ์ ์ ์ด์ ์ ๊ฒฝ ์ฐ์ง ์๊ฑฐ๋ ๊ทธ๊ฒ์ ๋ํ ๋ค๋ฅธ ์ ๋ต์ด ์๋ค๊ณ ๊ฐ์ ํฉ๋๋ค. ๊ทธ๊ฒ์ ๋ณต์กํ ์ผ์ด๋ฏ๋ก React ๊ด์ฌ์ฌ๊ฐ ์๋์ ์ดํดํฉ๋๋ค.
์ ๋ต์ด ์ ์ ๋ฐ๋ผ ์๋ค๋ ๊ฒ์ ์ฌ๋ฐ๋ฅด๊ฒ ์ดํดํ๊ณ ์์ต๋๊น? ์ฑ์ด ๋ณต์กํ๊ณ ์ญ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ผ๋ฉฐ RxJS์ ๊ฐ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๊ทธ ์ฌ์ด์ ๋ฌด์ธ๊ฐ๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ React ๊ตฌ์ฑ ์์๋ฅผ fe websocket์ ์ง์ ์ฐ๊ฒฐํ๋ฉด ์ฑ์ด ๊ฐ๋จํ๊ณ ์ ๋ฐ์ดํธ๊ฐ ๋๋ฆฌ๊ธฐ ๋๋ฌธ์ ์ญ์ ๋ฌธ์ ๊ฐ ์์ต๋๋ค.
โ
์ด ์ด๋ฉ์ผ์ ์ง์ ํ์ ํ๊ฑฐ๋ GitHub์์ ํ์ธํ์ธ์.
๊ท์คํ ์ธ๋ถ์ฌํญ์ ์ํ ๋ง์ ๊ฐ์ฌํฉ๋๋ค. ๊ทธ๊ฒ์ ๋ง์ ์๋ฏธ๊ฐ ์์ต๋๋ค.
@gaearon ๋ณต์ฌํ์ต๋๋ค. ES6 ํด๋์ค์ ํจ๊ป ParseReact๋ฅผ ์ฌ์ฉํ๊ณ ์ถ์๊ธฐ ๋๋ฌธ์ mixin์ ๊ด์ฐฐ API๋ฅผ ๊ณ ์ฐจ ๊ตฌ์ฑ ์์๋ก ๋ค์ ๊ตฌํํด์ผ ํ์ต๋๋ค.
https://gist.github.com/amccloud/d60aa92797b932f72649 (์๋ ์ฌ์ฉ๋ฒ)
@aaronshaf @gaearon ์ผ๋ฑ์ ์ผ๋ก ๋ง๋๋ ์ด์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
1) props ๋ค์์คํ์ด์ค๋ฅผ ์ก์๋จน์ง ์์ต๋๋ค. ์๋ฅผ ๋ค์ด ๊ณ ์ฐจ ์ปดํฌ๋ํธ๋ ๋ค๋ฅธ ์ฉ๋๋ก ์ฌ์ฉํ ์ ์๋ props ๊ฐ์ฒด์ ๋ฐ์ดํฐ์ ๊ฐ์ ์ด๋ฆ์ ์๊ตฌํ ํ์๊ฐ ์์ต๋๋ค. ์ฌ๋ฌ ๊ฐ์ ๊ณ ์ฐจ ๊ตฌ์ฑ ์์๋ฅผ ์ฐ๊ฒฐํ๋ฉด ๋ ๋ง์ ์ด๋ฆ์ ๊ณ์ ์ฌ์ฉํ๋ฏ๋ก ์ด์ ์ด๋ฌํ ์ด๋ฆ์ ๊ณ ์ ํ๊ฒ ์ ์งํ๋ ๋ฐฉ๋ฒ์ ์ฐพ์์ผ ํฉ๋๋ค. ์ด๋ฏธ ์์ฑ๋์์ ์ ์๋ ํญ๋ชฉ์ ์์ฑํ๊ณ ์๋๋ฐ ์ด์ ์ด๋ฆ ์ถฉ๋์ด ๋ฐ์ํ๋ฉด ์ด๋ป๊ฒ ๋ฉ๋๊น?
๊ฒ๋ค๊ฐ, ๊ณ ์ฐจ ๊ตฌ์ฑ ์์์ ๋ํ ๋ชจ๋ฒ ์ฌ๋ก๋ ๋ํ๋ ๊ตฌ์ฑ ์์์ ๊ณ์ฝ์ ๋ณ๊ฒฝํ์ง ์๋ ๊ฒ์ด์ด์ผ ํ๋ค๊ณ ์๊ฐํฉ๋๋ค. ์ฆ, ๊ฐ๋ ์ ์ผ๋ก ์์๊ณผ ๋์ผํ ์ํ์ด์ด์ผ ํฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์๋น์๊ฐ ์์ ํ ๊ฒ๊ณผ ์์ ํ ๋ค๋ฅธ props ์ธํธ๋ฅผ ์ ๊ณตํ ๋ ์ฌ์ฉํ๊ณ ๋๋ฒ๊ทธํ๋ ๊ฒ์ด ํผ๋์ค๋ฝ์ต๋๋ค.
HOC ๋์ ์ผ๋ฐ ๊ตฌ์ฑ ์์๊ฐ ๋ ์ ์์ต๋๋ค.
import Observe from 'react/addons/Observe';
class Foo {
render() {
return (
<Observe
render={this.renderData}
resources={{
myContent: xhr(this.props.url)
}} />
);
}
renderData({ myContent }) {
if (myContent === null) return <div>Loading...</div>;
return <div>{myContent}</div>;
}
}
render
์ํ์ผ๋ก ์ ๋ฌ๋ ํจ์๋ฅผ ์ ์ดํ๊ธฐ ๋๋ฌธ์ ์ด๋ฆ์ด ์ถฉ๋ํ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค. ๋ฐ๋ฉด์ ์์ ์์ ์ํ๋ฅผ ์ค์ผ์ํค์ง ์์ต๋๋ค.
์ฌ๊ธฐ์ ๋ด๊ฐ ๋์น๊ณ ์๋ ๊ฒ์ด ๋ฌด์์ ๋๊น?
Observe
๊ตฌ์ฑ ์์๊ฐ props์์ Observables๋ฅผ ๊ฐ์ ธ์จ ๊ฒฝ์ฐ ์ด๊ฒ์ ํจ์ฌ ๋ ์ฅํฉํ ์ ์์ต๋๋ค.
render() {
return (
<Observe myContent={Observable.fetch(this.props.url)}
render={this.renderData} />
);
}
renderData({ myContent }) {
if (myContent === null) return <div>Loading...</div>;
return <div>{myContent}</div>;
}
์ด๊ฒ์ ๋ํ ์ข์ ์ ์ render
์ ์ ํ ๋ค์ด๊ฐ์ง ์๊ธฐ ๋๋ฌธ์ shouldComponentUpdate
๊ฐ false๋ฅผ ๋ฐํํ๋ฉด ์ฌ๊ตฌ๋
์ ํผํ ์ ์๋ค๋ ๊ฒ์
๋๋ค.
๋ง์ง๋ง์ผ๋ก Observe
๊ตฌ์ฑ ์์๋ก ๋ํํ๋ render
๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์์ฑํ ์ ์์ต๋๋ค.
@observe(function (props, state, context) {
myContent: Observable.fetch(props.url)
})
render({ myContent }) {
if (myContent === null) return <div>Loading...</div>;
return <div>{myContent}</div>;
}
๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ๋
ผ๋ฆฌ๋ฅผ ์ฝ์
ํ๋ ๋์ render
๋ฅผ ์์ํ ๋ ๋๋ง ํจ์๋ก ์ ์งํ๋ ๊ฒ์ ์ ํธํฉ๋๋ค.
์ ์๊ฐ์๋ ์ด๊ธฐ ์ ์์ด ์ข์ ๊ฒ ๊ฐ์ต๋๋ค. ์ํ๊ฐ rx-react
๋ก ์๋ํ๋ ๋ฐฉ์๊ณผ ๋งค์ฐ ์ ์ฌํ๋ฉฐ ๋งค์ฐ ์ผ๊ด์ฑ ์๋ ๊ฒ์ฒ๋ผ ๋ณด์ด๋ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ๋
ผ๋ฆฌ์์ ์ํ ๊ด๋ฆฌ๋ฅผ ๋ถ๋ฆฌํ ์ ์์ต๋๋ค.
๋๋ฅผ ๊ดด๋กญํ๋ ์ ์ผํ ๊ฒ์ ํ๋์ ์ต์ ๋ฒ๋ธ ๋์ ์ต์ ๋ฒ๋ธ์ ๋งต์ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค. ์ฌ์ฉ์์๊ฒ ์ต์ ๋ฒ๋ธ ๊ตฌ์ฑ ๋ฐฉ๋ฒ์ ์ ํํ ์ ์๋ ๊ฐ๋ฅ์ฑ์ ์ ๊ณตํ์ง ์์ง๋ง ์ด๊ฒ์ ์ฌ์ํ ๋ฌธ์ ์ด๊ธฐ ๋๋ฌธ์ ๋๋ค.
์ค์ ๋ก ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ๋
ผ๋ฆฌ๋ฅผ ์ฃผ์
ํ๋ ๊ฒ์ด ์๋๋ผ ์ผ๋ถ ์
๋ ฅ์ ์ ์ฅํ๋ ๊ฒ์
๋๋ค. <Observe />
๊ตฌ์ฑ ์์๋ง ๋ ๋๋งํ๋ ์์ ๋ฒ์ ์ผ๋ก ์คํ์ ์ ๊ฑฐํฉ๋๋ค. ์ํ ์ ์ฅ ๊ตฌ์ฑ ์์๋ฅผ ๋ ๋๋งํ๋ ๊ฒ์ ๋๋ฌธ ์ผ์ด ์๋๋ฏ๋ก render
๊ฐ ์ง๊ธ๋ณด๋ค ๋ ์์ํ๋ค๊ณ ์๊ฐํ์ง ์์ต๋๋ค.
๋๋ #3858์ ์ต์ ๊ณผ ์ด ์ ์์ ๊ฒฐํฉํ๋ ค๊ณ ๋ ธ๋ ฅํ๋ค.
๋ชจ๋ HOC ์ ๊ทผ ๋ฐฉ์์์ ์ด์ ์ ๋ช ์์ ์ด์ง๋ง @sebmarkbage์ ์ํด ๋จ์ ์ด ์ค๋ช ๋ฉ๋๋ค . props ์ด๋ฆ์ ์ด๋ ์์ ์์ ์ถฉ๋ํ ์ ์์ต๋๋ค.
ํ์ฌ ์ ์์์ ์ด์ ์ ๋ช ์์ ์ด์ง๋ง ๋ถ์ ์ ์ธ ์ธก๋ฉด์ ๋ ๋ณต์กํ ์๋ช ์ฃผ๊ธฐ์ ๋ ํฐ ํต์ฌ ๊ตฌ์ฑ ์์ API ํ๋ฉด์ ๋๋ค.
#3858์์ ์ด์ ์ "memoized render" ์ข
์์ฑ์ ๋ ๋๋ง ์์ฒด์ ํจ๊ป ๋ฐฐ์นํ๋ ๊ฒ์
๋๋ค(๋ค๋ฅธ ๊ณณ์์๋ ์ฌ์ฉ๋์ง ์์ผ๋ฏ๋ก ์๋ฏธ๊ฐ ์์). ๊ทธ๋ฌ๋ ์ ๋ "look sync but is async" ์ ๋ํด ์ฐ๋ คํ๊ณ ์์ผ๋ฉฐ ์ด๋ป๊ฒ ํ๋์ง ์ดํดํ์ง ๋ชปํฉ๋๋ค. this
์ ๋๋ฌด ์์กดํ๋ ๊ฒฝ์ฐ ๋ถ๋ณ ๋ชจ๋ธ๋ก ์์
ํ ์ ์์ต๋๋ค . ๋ํ ์๋์ผ๋ก ๋ณ๊ฒฝ ์ฌํญ์ ์ถ์ ํ๊ณ ๋ฐ์ดํฐ ์์ค๋ฅผ React์ ์ฐ๊ฒฐํ๋ ๊ฒ(๋๋ React์ ํจ๊ป ์๋ํ๋๋ก ๋ํํ๋ ๊ฒ)์ ๋ํด ์ฝ๊ฒ ์ถ๋ก ํ ์ ์๊ธฐ ๋๋ฌธ์ React-was-eas-to-reason-about ๋ฐฉ์์ผ๋ก ์ ๋ฅผ ์๋ชป ๋ฌธ์ง๋ฆ
๋๋ค. ๋๋ ์ฑ๋ฅ์ ๋ฐํํ๊ณ ์์ฉ๊ตฌ๋ฅผ ์ค์ด๋ ๊ฒ ๋ชจ๋๋ฅผ ๊ตฌํํด์ผ ํ๋ค๋ ์๋ ฅ์ด ์๋ค๋ ๊ฒ์ ์ดํดํฉ๋๋ค.
๋ด ์ ์์์ ๋๋ ์ฝ๋ก์ผ์ด์ ๊ณผ ๋ช ์์ฑ์ ์ ์งํ๊ณ ์์ง๋ง:
<Observe />
(๋๋ <Observe />
๋ก render๋ฅผ ๋ํํ๋ observe()
๋ฐ์ฝ๋ ์ดํฐ)๋ ์ ๋์จ์ผ ๋ฟ์ด๋ฉฐ React ์ฝ์ด์ _any_ ๋ณ๊ฒฝ ์ฌํญ์ ์ ์ํ์ง ์์ต๋๋ค.<Observe />
๋ฅผ ๊ฐ์ง ์ ์์ต๋๋ค. ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ ์๋ ์๊ณ ์ฌ์ฉํ์ง ์์ ์๋ ์์ต๋๋ค.์ฌ๊ธฐ์์ ํ๋ฅญํ ํ ๋ก ๊ณผ ์์ , ๋ง์ ์กด๊ฒฝ์ ํํฉ๋๋ค. :)
๋๋ ์ด๊ฒ์ด ๊ทธ๊ฒ์ ํต์ฌ์ผ๋ก ๋ง๋ค ๊ฐ์น๊ฐ ์๋ค๋ ๋ฐ ๋์ํฉ๋๋ค. ์๋ง๋ ์ถ๊ฐ ๊ธฐ๋ฅ์ ์ฌ๋๋ค์ด ๋ ์์ ํ ์ปค๋ฐํ๊ธฐ ์ ์ ์๋ ดํ๊ณ ํ์คํํ๋ ค๊ณ ์๋ํ ์ ์๋ ์ถฉ๋ถํ ๊ฒฌ์ธ๋ ฅ์ ์ด ์ ์์ ์ ๊ณตํฉ๋๋ค. ์ฆ, ๋๋ ์ด ์ ์์ด ๋ฏธ๋๋ฉ๋ฆฌ์ฆ์ ์ํด https://github.com/facebook/react/issues/3858 ๋ฐ https://github.com/facebook/react/pull/3920 ๋ณด๋ค ๋ซ๋ค๊ณ ์๊ฐํฉ๋๋ค.
์ด๊ฒ์ ๋ด๊ฐ ์ฌ์ด๋ ํ๋ก์ ํธ์์ ์ฌ์ฉํ๊ณ ์๋ ๊ฒ์ ๋๋ค(๊ทธ๋์ ์๊ธ ์๊ฐฑ์ด) - @elierotenberg ์ ๋ฉ์ง ์์ ๊ณผ ์ ์ฌํ์ง๋ง ์ด ์ฑ์ด React์์ 100%๊ฐ ์๋๋ฉฐ ์ํธ
CoffeeScript์ ๋ฏน์ค์ธ์ ๋๋นํ๊ฑฐ๋ ์ํ๋ ๊ฒฝ์ฐ ์ด๊ฒ์ด ES6์ฒ๋ผ ๋ณด์ผ ๋๊น์ง ๊ณ์ ๋์ ๊ฐ๋๊ฒ ๋จ๊ณ ์์ต๋๋ค. :)
_ = require 'lodash'
module.exports = DeclareNeedsMixin =
componentDidMount: ->
<strong i="12">@needsConsumerId</strong> = _.uniqueId @constructor.displayName
<strong i="13">@sinkNeeds</strong> <strong i="14">@props</strong>, <strong i="15">@state</strong>
componentWillUpdate: (nextProps, nextState) ->
<strong i="16">@sinkNeeds</strong> nextProps, nextState
componentWillUnmount: ->
@props.flux.declareNeeds <strong i="17">@needsConsumerId</strong>, []
sinkNeeds: (props, state) ->
if not @declareNeeds?
return console.warn 'Missing method required for DeclareNeedsMixin: `declareNeeds`', @
needs = <strong i="18">@declareNeeds</strong> props, state
props.flux.declareNeeds <strong i="19">@needsConsumerId</strong>, needs
# Intended to be overridden by the host class.
# Returns a set of facts, stored as an array.
# Yes, immutable data is awesome, that's not the point here though. :)
# Facts are serializable data, just values.
# declareNeeds: (props, state) ->
# []
๊ทธ๋ฆฌ๊ณ ๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉํฉ๋๋ค.
module.exports = EmailThreads = React.createClass
displayName: 'EmailThreads'
mixins: [DeclareNeedsMixin]
propTypes:
flux: PropTypes.flux.isRequired
declareNeeds: (props, state) ->
[Needs.GmailData.myThreads({ messages: 20 })]
...
๋ฐ๋ผ์ declareNeeds
๋ ์ด ๊ตฌ์ฑ ์์์ ํ์ํ ์ค๋ช
์ ๋ํ props ๋ฐ state์ ๋จ๋ฐฉํฅ ํจ์์
๋๋ค. ์ค์ ๊ตฌํ์์ @props.flux.declareNeeds
์ ์์ ์ธก์ ์ต์์ ๊ตฌ์ฑ ์์์ ์ค์ ๋์ด ์ด๋ฌํ ์๊ตฌ ์ฌํญ์ ProcessSink
๊ฐ์ฒด๋ก ํก์ํฉ๋๋ค. ์ํ๋ ๋๋ก ์ผ๊ด ์ฒ๋ฆฌํ๊ณ ๋์ผํ flux
๋ฅผ ๊ณต์ ํ๋ ๊ตฌ์ฑ ์์์์ needs
์ค๋ณต์ ์ ๊ฑฐํ ๋ค์ ์ด๋ฌํ ์๊ตฌ ์ฌํญ(์: ์์ผ ์ฐ๊ฒฐ ๋๋ HTTP ์์ฒญ ๋ง๋ค๊ธฐ)์ ์ถฉ์กฑํ๊ธฐ ์ํด ๋ถ์์ฉ์ ์ํํฉ๋๋ค. ๋ ์ด์ ํ์ํ์ง ์์ ๊ตฌ์ฑ ์์๊ฐ ์์ ๋ ์์ผ ์ฐ๊ฒฐ๊ณผ ๊ฐ์ ์ํ ์ ์ฅ ํญ๋ชฉ์ ์ ๋ฆฌํ๊ธฐ ์ํด ์ฐธ์กฐ ์นด์ดํ
์ ์ฌ์ฉํฉ๋๋ค.
๋ฐ์ดํฐ๋ ์์ผ ์ด๋ฒคํธ ๋ฐ ์์ฒญ๊ณผ ๊ฐ์ ์ํ ์ ์ฅ ๋นํธ์์ ๋์คํจ์ฒ๋ก(๊ทธ๋ฐ ๋ค์ ์ ์ฅ์ ๋๋ ์ด๋๋ ์ง) ํ์๋ฅผ ์ถฉ์กฑ์ํค๊ธฐ ์ํด ๊ตฌ์ฑ ์์๋ก ๋ค์ ํ๋ฆ ๋๋ค. ์ด๊ฒ์ ๋๊ธฐ๊ฐ ์๋๋ฏ๋ก ๋ฐ์ดํฐ๋ฅผ ์์ง ์ฌ์ฉํ ์ ์์ ๋ ๋ชจ๋ ๊ตฌ์ฑ ์์๊ฐ ๋ ๋๋ง์ ์ฒ๋ฆฌํฉ๋๋ค.
๋๋ ์ฌ์ฉ์ ๊ณต๊ฐ์์ ์ด๋ฌํ ์ข ๋ฅ์ ์๋ฃจ์ ์ ํ์ํ๋ ๊ฒ์ด ๊ฐ๋ฅํ๋ฉฐ ํ์ฌ API๊ฐ ๊ทธ๋ฐ ์ข ๋ฅ์ ์คํ์ ์ ๋ง ์ ์ํํ๊ณ ์๋ค๋ ๋ ๋ค๋ฅธ ๋ชฉ์๋ฆฌ๋ก ์ด๊ฒ์ ๊ณต์ ํ๊ณ ์์ต๋๋ค. ์๋ก ๋ค๋ฅธ ์ ๊ทผ ๋ฐฉ์ ๊ฐ์ ์ํธ ์ด์ฉ์ฑ์ ์ง์ํ๊ธฐ ์ํด ์ฝ์ด๊ฐ ์ทจํ ์ ์๋ ์ต์ ๋จ๊ณ์ ๊ด์ ์์ @elierotenberg ๊ฐ ์ด๋ฅผ ๋ชป ๋ฐ์๋ค๊ณ ์๊ฐํฉ๋๋ค.
์ด์จ๋ ํ์ฌ๋ React ๊ณ์ธต ๊ตฌ์กฐ ์ธ๋ถ์์ React ๊ตฌ์ฑ ์์ ์ธ์คํด์ค ์๋ช ์ฃผ๊ธฐ๋ฅผ ์ ์ง ๊ด๋ฆฌํ๋ ๊ฒ์ ๋ ธ์ถํ๊ณ ์ง์ํ๋ ๊ฒ์ด ๋์์ด ๋ ๊ฒ์ ๋๋ค.
์ํ ๋น์ ์ฅ ์ ๊ทผ ๋ฐฉ์์ ๊ฒฝ์ฐ ๋น๋๊ธฐ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ๊ฐ ์ํ ์ ์ฅ์ด๋ฏ๋ก ์ผ๋ถ ๊ตฌ์ฑ ์์์ ์ํ์ ๋ณด๋ฅ/์๋ฃ/์คํจ ์ํ๋ฅผ ์ ์ฅํ๋ ๊ฒ์ด ์ ์ ํฉ๋๋ค.
@elierotenberg ์ @andrewimm ์ ์ผ๋ฅ ์ค๋ฅ ์ฒ๋ฆฌ์ ๋ํด ํ๋ฅญํ ์ง์ ์ ํ์ต๋๋ค. @sebmarkbage ์ต์ํ์ interop ์ง์ ์ ๋ํ ๋ณธ๋ฅ์ด onError
๋ฐ onCompleted
๊ฐ์ ์ก์ธ์คํ๋ ๋ฐฉ๋ฒ์ ๋ํ ๋๊ฐ์ด ๊ฐ๋จํ ์ด์ผ๊ธฐ๊ฐ ์์ด์ผ ํฉ๋๋ค. this.observed
์ค ํ๋์ ๋ง์ง๋ง ๊ฐ์ ๋ณด์ ํ๋ ๊ฒฝ์ฐ์๋ ๋ง์ฐฌ๊ฐ์ง์
๋๋ค next/error/completed
like { next: "foo" }
. ๊ด์ฐฐ ๊ฐ๋ฅํ ๊ณ์ฝ์ ์ผ๊ธ ๊ธฐ๋ฅ์ผ๋ก ์ง์ํ์ง ์๊ณ , ๋๋ ์ด ์ ์์ด ์ญ๊ฐ๋๋ ๊ฒ์ ๋ํด ์ฝ๊ฐ ํ์์ ์
๋๋ค.
๊ทธ๋ฆฌ๊ณ ์ด๊ฒ์ ์ธํฐ๋ท์ด๊ณ ์ฌ๊ธฐ์์ ์ฒ์์ผ๋ก ์๋ฆฌ๋ฅผ ๋ธ ๊ฒ ์ค ํ๋์ด๊ธฐ ๋๋ฌธ์ React ๋ฌธ์ ํผ๋๋ ํ๋ฅญํ ์์ ๊ณผ ์์ด๋์ด์ ๋ํ ์ต๊ณ ์ ์ฝ๊ธฐ์ด์ ๋ง๋ฅ ์์ค์ ๋๋ค. :+1:
๋์๊ฒ ๋ฐ์ธ๋ฉ๊ณผ ๊ฐ์ ๋์๊ฐ ๋๋ค.
์ด๊ฒ์ด ํ์ฌ ์ ์/๊ตฌํ๊ณผ ์ด๋ค ๊ด๋ จ์ด ์๋์ง ํ์คํ์ง ์์ง๋ง ๊ตฌ์ฑ ๋ฐ ๊ณ ์ฐจ ์กฐ์์ ํ์ฑํํ๋ ๊ฒ์ด ์ค์ ๋ก ๋ฐ์ดํฐ ์ข ์์ฑ ์ถ์ ์ ํต์ฌ ๊ธฐ๋ฅ์ด๋ผ๋ ๊ฒ์ ์์์ต๋๋ค. ํนํ ๋ฐ์์ฑ ๋ฐ์ดํฐ ์์ค(ํ๋ญ์ค, ํ๋ญ์ค ์ ์ ๋๋ ์ ๋ฐ์ดํธ๋ฅผ ์ ๊ณตํ๋ ๊ฒ ์ด์ธ์ ๋ชจ๋ ๊ฒ).
react-nexus@^3.4.0
๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์ ์๋ฅผ ์ดํด๋ณด์ธ์.
// the result from this query...
@component({
users: ['remote://users', {}]
})
// is injected here...
@component(({ users }) =>
users.mapEntries(([userId, user]) =>
[`user:${userId}`, [`remote://users/${userId}/profile`, {}]]
).toObject()
))
class Users extends React.Component {
// ... this component will receive all the users,
// and their updates.
}
๋์ฒด๋ก ์ปดํฌ๋ํธ API์ ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ์ด ์์ด์ผ ํ๋์ง ๊ถ๊ธํฉ๋๋ค. ๊ณ ์ฐจ์ ๊ตฌ์ฑ ์์๋ฅผ ๋ฐํํ๋ ๋ฐ์ฝ๋ ์ดํฐ๋ ๊ตฌ์ฑ ์์ ๋ฉ์๋ ๋ค์์คํ์ด์ค๋ฅผ ์ค์ผ์ํค์ง ์๊ณ ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ์ ํํํ๋ ์์ฃผ ์ข์ ๋ฐฉ๋ฒ์ ์ ๊ณตํ๋ ๊ฒ ๊ฐ์ต๋๋ค.
๊ทธ๋ฌ๋ @sebmarkbage ๊ฐ ์ธ๊ธํ๋ฏ์ด ๋์ props ๋ค์์คํ์ด์ค๊ฐ ์ค์ผ๋ ์ํ์ด ์์ต๋๋ค. ์ง๊ธ์ ์ํ ๋ณํ๊ธฐ ๋ฐ์ฝ๋ ์ดํฐ( react-transform-props
)๋ฅผ ์ฌ์ฉํ์ฌ ์ํ์ ๋ด๋ถ ๊ตฌ์ฑ ์์๋ก ์ ๋ฌํ๊ธฐ ์ ์ ์ ๋ฆฌํ๊ฑฐ๋ ์ด๋ฆ์ ๋ณ๊ฒฝํ๊ณ ์์ต๋๋ค. ๋ ์ผ๋ฐ์ ์ด๊ณ ์ด๋ฆ ์ถฉ๋์ ์ํ์ด ์ฆ๊ฐํฉ๋๋ค.
๊ธฐํธ๊ฐ ์์ฑ ํค์์ ์ฌ์ฉํ์ฌ ํด๊ฒฐํ ์ ์์ต๋๊น? propTypes
๊ฒ์ฌ๊ฐ Symbol
-keyed ์ํ์ ์ง์ํฉ๋๊น? JSX๋ ๊ณ์ฐ๋ ์ธ๋ผ์ธ ์ํ ํค๋ฅผ ์ง์ํฉ๋๊น(ํญ์ ๊ณ์ฐ๋ ์์ฑ + ๊ฐ์ฒด ํ์ฐ์ ์ฌ์ฉํ ์ ์์)?
์ด๊ฒ์ด ์ฃผ์ ์์ ์กฐ๊ธ ๋ฒ์ด๋๋ฉด ์ฃ์กํ์ง๋ง ๊ตฌ์ฑ ์์ ์์ค์์ ๋ฐ์ดํฐ deps๋ฅผ ํํํ๊ธฐ ์ํ ์ ์ ํ ์ถ์ํ/API๋ฅผ ์ฌ์ ํ ์ฐพ์์ผ ํ๋ ๊ฒ ๊ฐ์ต๋๋ค.
๋ด 2์ผํธ
๋๋ ์๊ฐ์ด ์ง๋จ์ ๋ฐ๋ผ ๋ณํ๋ ๊ฐ์น์ ๋ํ 'children as a function' ํจํด์ผ๋ก ๋ง์ ์๊ฐ์ ๋ณด๋์ต๋๋ค. @elierotenberg๊ฐ ์ฒ์์ผ๋ก ์๊ฐํด
<Springs to={{x: 20, y: 30}} tension={30}>
{val => <div style={{left: val.x, top: val.y}}>moving pictures</div>}
</Springs>
์ํ ์ถฉ๋์ด ์๊ณ ์์ ์ ์ํ๋ฅผ ์ฌ์ฉํ์ง ์์ต๋๋ค. ๋ํ ์ฌ๋ฌ ์คํ๋ง์ ์ค์ฒฉํ ์ ์์ผ๋ฉฐ ๋ฐ์์ ๋ชจ๋ ํ๋ ๋นํธ๋ฅผ ๊ด๋ฆฌํฉ๋๋ค. ์ด๋ฌํ '๊ด์ธก ๊ฐ๋ฅ ํญ๋ชฉ'(ํ!)์ onError
, onComplete
๋ฐ ๊ธฐํ ์ํ(graphql ์ฟผ๋ฆฌ?)๋ ํ์ฉํ ์ ์์ต๋๋ค.
'ํ๋ญ์ค'์ ๋ํ ๋๋ต์ ์ธ ์ค์ผ์น ์๋
<Store
initial={0}
reduce={(state, action) => action.type === 'click'? state+1 : state}
action={{/* assume this comes as a prop from a 'Dispatcher' up somewhere */}}>
{state => <div onClick={() => dispatch({type: 'click'})}> clicked {state} times</div>}
</Store>
์ฐ๋ฆฌ๋ Asana์์ _render callbacks_์ด๋ผ๊ณ ๋ถ๋ฅด๋ ์ด ํจํด์ ์ฌ์ฉํ์ง๋ง ๊ถ๊ทน์ ์ผ๋ก ์ด ํจํด์์ ๋ฉ์ด์ง๊ณ ์์ต๋๋ค.
์ฅ์
StoreComponent
์์ ์ฌ์ฉ์ StoreComponent
๋จ์
shouldComponentUpdate
๋ ๋ ๋ ์ฝ๋ฐฑ์ด ์ํ ์ด์์ผ๋ก ๋ซํ ์ ์์ผ๋ฏ๋ก ๊ตฌํํ๊ธฐ๊ฐ ๋งค์ฐ ์ด๋ ต์ต๋๋ค. A
-> Store
-> B
์ ๊ตฌ์ฑ ์์ ํธ๋ฆฌ๊ฐ ์๋ค๊ณ ์์ํด๋ณด์ญ์์ค. A
์๋ B
๋ํ props๋ก ๋ ๋๋ง ์ฝ๋ฐฑ ์ค์ ์ก์ธ์ค๋๋ ์ํ์ ์นด์ดํฐ๊ฐ ์์ต๋๋ค. ์นด์ดํฐ๋ก ์ธํด A
์
๋ฐ์ดํธ๋๊ณ Store
๊ฐ ์
๋ฐ์ดํธ๋์ง ์์ผ๋ฉด B
์๋ ์ค๋๋ ๋ฒ์ ์ ์นด์ดํฐ๊ฐ ์์ต๋๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก ์ฐ๋ฆฌ๋ ํญ์ ์คํ ์ด๋ฅผ ์
๋ฐ์ดํธํด์ผ ํ์ต๋๋ค.์ด์ StoreComponent
๊ฐ ReactElement
๋ฅผ ์ฌ์ฉํ๋ ๋ชจ๋ธ๋ก ์ด๋ํ๊ณ ์ ์ฅ์๊ฐ ์ ๋ฐ์ดํฐ๋ฅผ ์์ ํ๋ฉด ์ ์ฅ์๊ฐ ํน์ ์ํ์ ์ฌ์ ์ํ๋ ReactElement๋ฅผ ๋ณต์ ํฉ๋๋ค. Component ์์ฑ์์ ์ํ์ ์ฌ์ฉํ๋ ๊ฒ๊ณผ ๊ฐ์ด ์ด ํจํด์ ์ํํ๋ ๋ฐฉ๋ฒ์๋ ์ฌ๋ฌ ๊ฐ์ง๊ฐ ์์ต๋๋ค. TypeScript์์ ๋ชจ๋ธ๋งํ๊ธฐ๊ฐ ๊ฐ์ฅ ์ฝ๊ธฐ ๋๋ฌธ์ ์ด ์ ๊ทผ ๋ฐฉ์์ ์ฌ์ฉํ์ต๋๋ค.
ํ๋ฅญํ ์ , '์์ผ๋ก' ์๊ตฌ ์ฌํญ์ ์๋ฐํ์ง ์๊ณ ๋ ๋ฐฉ๋ฒ์ ์๊ฐํ ์ ์์ต๋๋ค.
@threepointone https://github.com/reactjs/react-future/pull/28 ์ ์ ์์ ๊ณต๊ธํ๊ธฐ ์ํ ๊ตฌํ ์ ์ ์ค ํ๋์ฒ๋ผ ๋ค๋ฆฝ๋๋ค.
๊ทํ์ ์์์ @pspeter3 , Store๋ฅผ ํญ์ ์
๋ฐ์ดํธํ๋๋ก ๋ง๋๋ ๋ฐ ์ฌ๊ฐํ ๋จ์ ์ด ์์ต๋๊น / shouldComponentUpdate: ()=> true
? ์ด์จ๋ '์์'์ด ์ฒด์ธ์ Store
์์ด ๋ ๋๋ง๋์์ ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค. ์๊ฐ ๋ด ์ค์ ๊ณ ๋ง์!
@threepointone ๊ทธ๊ฒ์ด ๋ฐ๋ก ์ฐ๋ฆฌ๊ฐ ๊ฒฝ๊ณ๋ฅผ ์ํด ํ ์ผ์
๋๋ค. ๊ทธ ์ํฅ์ด ์ ํํ ๋ฌด์์ธ์ง๋ ๋ถ๋ถ๋ช
ํ์ง๋ง, ํ์๋ค์ ํผํฌ๋จผ์ค ๊ฑฑ์ ์ด ์์๋ค. ํ
์คํธ์ ์ด๋ ค์๊ณผ ๊ฒฐํฉ๋ ๊ฑฑ์ ์ React.cloneElement(this.props.child, {data: this.state.data})
๋ฅผ ์ฌ์ฉํ๋๋ก ์ ํํ์ต๋๋ค.
@pspeter3 ํ ์คํธ ๊ฐ๋๊ฐ ํ์คํ ๋ฌธ์ ์ ๋๋ค. ShallowRenderer๊ฐ '๋ ๋ ์ฝ๋ฐฑ'์ ์ธ์ํ๋ค๋ฉด ์ด๋ป๊ฒ ๋ ๊น์? ๋์์ด ๋ ๊น์?
Ps- '์ฝ๋ฐฑ ๋ ๋๋ง':thumbs_up:
@sebmarkbage es-observable ์ ๋ํ ํ์ฌ ๋
ผ์๋ subscribe
๊ฐ ๋น๋๊ธฐ๋ฅผ ๋ณด์ฅํ๊ณ [Symbol.observer]
๋ฉ์๋๊ฐ ๋๊ธฐ์์ผ๋ก ๋ฐ๋ก ๊ฐ๊ธฐ ๋ฐ ๊ตฌ๋
์ ์ ๊ณต๋๋ค๋ ๊ฒ์
๋๋ค. ํ์ฌ ๋
ผ์ ์ค์ด๋ค.
๋๊ธฐ ๊ตฌ๋ ์ ์ฐฌ์ฑํ์ฌ ์์์ ์ธ๊ธํ ์ฌ์ฉ ์ฌ๋ก์ ํจ๊ป ์ด ํฐ์ผ ์ ์ฐธ์ฌํ์ง๋ง ๊ฑฐ๊ธฐ์ ์ถ๊ฐํ ๋ด์ฉ์ด ์๋์ง ๋ชฐ๋์ต๋๋ค.
๋๋ ์ฌ๊ธฐ์ ์๋ ์์ด๋์ด๊ฐ ์ธ๋ถ ์ํ๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํ ๋งค์ฐ ๊นจ๋ํ ํจํด์ด๋ผ๊ณ ์๊ฐํ์ง๋ง ์กฐ๊ธ ๊ฐ์ง๊ณ ๋๊ณ ๋ ํ์๋ HOC ์ ๊ทผ ๋ฐฉ์์ ์ ํธํฉ๋๋ค.
- ๋ํ @gaearon ๋ ๋น์ HOC ์ ์ ์ฌ์ฉํ์ฌ, ์์ ๋นํธ ๋จ์ํ ComposedComponent.observe
ํ๊ณ ์ฌ์ฉํ์ฌ this.state
๋ณด๋ค๋ this.state.data
- https://gist.github.com/tgriesser/d5d80ade6f895c28e659
์ ์๋ es7 ๋ฐ์ฝ๋ ์ดํฐ๋ก ์ ๋ง ๋ฉ์ง๊ฒ ๋ณด์ ๋๋ค.
<strong i="20">@observing</strong>
class Foo extends Component {
static observe(props, context) {
return {
myContent: xhr(props.url)
};
}
render() {
var myContent = this.props.data.myContent;
return <div>{myContent}</div>;
}
}
ํด๋์ค ๋ฐ์ฝ๋ ์ดํฐ๋ data
์ ๋ํ getter๋ฅผ ์ถ๊ฐํ์ฌ ์๋ ์ ์๋ API(๊ด์ฐฐ ๊ฐ๋ฅํ ๊ตฌ๋
์ ์ํฅ์ ๋ฏธ์น๋ ๋ก์ปฌ ์ํ๋ฅผ ๋บ ๊ฐ์ผ๋ก ๋์ํฉ๋๋ค. ์ฃผ๋ณ ์์์ด ํจ์ฌ ์ ์ต๋๋ค. ๊ตฌ๋
/๊ตฌ๋
์ทจ์).
๋๊ธฐ ๊ตฌ๋ ์ด ์์ผ๋ฉด ํฐ ๋ฌธ์ ๊ฐ ๋ ์ ์์ต๋๋ค.
"์ํ ๋ฌธ์ "์ "์ธก๋ฉด ๋ฐ์ดํฐ ๋ก๋"(ํ์ ๋ฐ์ดํฐ)๋ฅผ ์ผ๊ด๋ ๋ฐฉ์์ผ๋ก ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ์๊ณ ์๋ค๊ณ ์๊ฐํฉ๋๋ค. stateless "React-way"๋ก ๋ง๋ญ๋๋ค. ์ด๋ค ์์ ์์๋ ์ํ ์ผ๊ด์ฑ์ ์ ์งํ๋ ๋ฐฉ๋ฒ์ ์ฐพ์๊ณ UI = React(state)
ํจํด์ ๋ง์ต๋๋ค. ๋๋ ๊ทธ๊ฒ์ ์์ ํ ๋ฐฉํ์ผ๋ก ๋ง๋ค๊ณ , ๋ ๋ง์ ์๋ฅผ ์ถ๊ฐํ๊ณ , ์ข์ ํ๋ ์ ํ
์ด์
์ ํ ์ ์์ ๊ฒ์
๋๋ค. https://github.com/AlexeyFrolov/slt . ๋ฐ๋ฉด์ ์ ํ
์คํธ๋์์ผ๋ฉฐ ํ๋ก๋์
ํ๋ก์ ํธ์์ ๋ฐ๋ณต์ ์ผ๋ก ์ฌ์ฉํ๊ณ ์์ต๋๋ค. ์๋ฆฌํ ๋ง์์ ๊ธฐ์ฌ๋ฅผ ํ์ํฉ๋๋ค.
์๋ ํ์ธ์ ์ฌ๋ฌ๋ถ,
์ฐ๋ฆฌ ํ์ฌ์์ ๋ฐ๋
์ ์ ์ด ์ ์์ผ๋ก ํด๊ฒฐ๋ ๊ฒ๊ณผ ๋์ผํ ๋ฌธ์ ์ ์ง๋ฉดํ๊ธฐ ๋๋ฌธ์ ์ ์ ์ด ์ค๋ ๋๋ฅผ ์ฐ์ฐํ ๋ฐ๊ฒฌํ์ง ์์๋ค๋ ๊ฒ์ด ์ฌ๋ฏธ์์ต๋๋ค.
์ฐ๋ฆฌ๋ ๋๊ท๋ชจ ํ๋ก์ ํธ์ React๋ฅผ ์ฌ์ฉํ๊ธฐ ์์ํ์ต๋๋ค(๋งค์ฐ ์ํ์ ์ธ ๋ฐ์ดํฐ๊ฐ ํฌํจ๋ Microsoft Visio์ ๋ณต์ก์ฑ์ ๊ฐ์ง ํธ์ง๊ธฐ๋ฅผ ์๊ฐํด ๋ณด์ธ์). ๋ฐ๋๋ผ ๋ฐ์ ์๊ฐ ์ฐ๋ฆฌ์ ์ฑ๋ฅ ์๊ตฌ ์ฌํญ์ ๋ฐ๋ผ๊ฐ์ง ๋ชปํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ ํ๋ญ์ค๋ ๋ง์ ์์ ์์ฉ๊ตฌ์ ๋ชจ๋ ๊ตฌ๋
์ ์ค๋ฅ ๊ฒฝํฅ์ผ๋ก ์ธํด ์ฐ๋ฆฌ์๊ฒ ์ฝ๊ฐ์ ์คํจ์์ต๋๋ค. ๊ทธ๋์ ์ฐ๋ฆฌ๋ ๊ด์ฐฐ ๊ฐ๋ฅํ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ ํ์ํ๋ค๋ ๊ฒ์ ์์๋์ต๋๋ค.
์ฌ์ฉํ ์ค๋น๊ฐ ๋ ์ฌ์ฉ ๊ฐ๋ฅํ ๊ฒ์ ์ฐพ์ ์ ์์๊ธฐ ๋๋ฌธ์ ๋
น์์ ์ต์ ๋ฒ๋ธ(ํนํ: ์๋ ๊ตฌ๋
)์ ์์น์ ๋ฐ๋ผ ์์ฒด ์ต์ ๋ฒ๋ธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๊ตฌ์ถํ์ต๋๋ค.
์ด๊ฒ์ ์ค์ ๋ก React ๊ตฌ์ฑ ์์์ ํ์ฌ ์๋ช
์ฃผ๊ธฐ์ ๋งค์ฐ ๊น๋ํ๊ฒ ๋ค์ด๋ง์ผ๋ฉฐ ์ด์ํ ํดํน์ด๋ ์์ ๋ ๋๋ง ์ฝ๋ฐฑ๋ ํ์ํ์ง ์์์ต๋๋ค(์๋์์ ์ฌ์ฉ๋๋ ObserverMixin์ ์ฝ 10loc์).
์ด๊ฒ์ ์ฐ๋ฆฌ์ DX๋ฅผ ๋ง์ด ํฅ์์์ผฐ๊ณ ์ฐ๋ฆฌ ํ์ ์ํด ์์ฃผ ์ ์๋ํ๊ธฐ ๋๋ฌธ์ ์ฐ๋ฆฌ๋ ๊ทธ๊ฒ์ ์คํ ์์ค ๋ก ๊ฒ์ํ๊ธฐ๋ก ๊ฒฐ์ ํ์ต๋๋ค. ๊ทธ ๋์ ์ด๊ฒ์ ์ ํฌ์์ ์
์ฆ๋์๊ณ (์๋ฅผ ๋ค์ด ES7 ๊ด์ฐฐ ๊ฐ๋ฅํ ์ด๋ ์ด ํด๋ฆฌํ์ ์ ๊ณตํจ) ๊ณ ๋๋ก ์ต์ ํ๋์์ต๋๋ค.
๋ค์์ ์งง์ ํ์ด๋จธ ์์ ์
๋๋ค( JSFiddle ๋ก๋ ์ฌ์ฉ ๊ฐ๋ฅ). IMHO DX๋ ์ด๋ณด๋ค ๋ ์ข์ ์ ์์ต๋๋ค... :์๋:
var store = {};
// add observable properties to the store
mobservable.props(store, {
timer: 0
});
// of course, this could be put flux-style in dispatchable actions, but this is just to demo Model -> View
function resetTimer() {
store.timer = 0;
}
setInterval(function() {
store.timer += 1;
}, 1000);
var TimerView = React.createClass({
// This component is actually an observer of all store properties that are accessed during the last rendering
// so there is no need to declare any data use, nor is there (seemingly) any state in this component
// the combination of mobservable.props and ObserverMixin does all the magic for us.
// UI updates are nowhere forced, but all views (un)subscribe to their data automatically
mixins: [mobservable.ObserverMixin],
render: function() {
return (<span>Seconds passed: {this.props.store.timer}</span>);
}
});
var TimerApp = React.createClass({
render: function() {
var now = new Date(); // just to demonstrate that TimerView updates independently of TimerApp
return (<div>
<div>Started rendering at: {now.toString()}</div>
<TimerView {...this.props} />
<br/><button onClick={resetTimer}>Reset timer</button>
</div>);
}
});
// pass in the store to the component tree (you could also access it directly through global vars, whatever suits your style)
React.render(<TimerApp store={store} />, document.body);
์ด ์ ๊ทผ ๋ฐฉ์์ ๋ํ ์์ธํ ๋ด์ฉ์ ์ด ๋ธ๋ก๊ทธ ๋ฅผ ์ฐธ์กฐํ์ญ์์ค. BTW, ES6 ํด๋์ค๋ฅผ ์ฌ์ฉํ๋ ์ฌ๋๋ค์ ์ํด ๋ฐ์ฝ๋ ์ดํฐ ๋ฐ/๋๋ ์ปจํ ์ด๋๊ฐ lib ์ ์ถ๊ฐ๋๋์ง ํ์ธํ๊ฒ ์ต๋๋ค.
์ฌํ๊ฒ๋ ๋๋ react-europe ์ ์ ์ด ์ค๋ ๋๋ฅผ ๋ณด์ง ๋ชปํ์ต๋๋ค. ๊ทธ๋ฌ๋ ์๊ฐ์ ์ฃผ๋ ์ด์ผ๊ธฐ๋ฅผ ํด์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค! :+1: ์ ๋ ํนํ GraphQL์ ์ถ์ํ์ Redux ์ด๋ฉด์ ์ฌ๊ณ ์์ ์ ์ข์ํ์ต๋๋ค. :)
@mweststrate ์ ๋ ์ปค๋ฎค๋ํฐ๊ฐ ๊ถ๊ทน์ ์ผ๋ก "Observable"๊ณผ "Immutable data" ์๋ฃจ์ ์ค์์ ์ ํํด์ผ ํ ํ์๊ฐ ์๋ค๊ณ ์๊ฐํฉ๋๋ค. ํ๋์ ์๋ฃจ์ (https://github.com/AlexeyFrolov/slt/issues/4)์์ ๋ ์ ๊ทผ ๋ฐฉ์์ ์ฅ์ ์ ๋ชจ๋ ๊ฐ๊ธฐ ์ํด ์ด๋ค ์์ผ๋ก๋ ํผํฉํด์ผ ํ ์๋ ์์ต๋๋ค. ๋ด ์๋ฃจ์ ์์๋ ์ด๋ค ์์ ์์๋ ์ํ์ ์ผ๊ด์ฑ์ ์ค์ ์ ๋ "๋ถ๋ณ ๋ฐ์ดํฐ" ์ ๊ทผ ๋ฐฉ์์ ๊ตฌํํ์ต๋๋ค. Observable๊ณผ Generator๋ ์ง์ํ ๊ณํ์ ๋๋ค. ์ด๊ฒ์ "ํ์" ๋๋ "๋ณด์ถฉ" ๋ฐ์ดํฐ(์: ํ์ด์ง ๋ณธ๋ฌธ, ์์ฐ, ์ถ์ฒ, ๋๊ธ, ์ข์์)๋ฅผ ๊ฐ์ ธ์ค๊ณ ์ฑ ์ํ์ ์ผ๊ด์ฑ์ ์ ์งํ๊ธฐ ์ํด ๋ฅผ ์ฌ์ฉํ๋ ๊ท์น์ ์์ ๋๋ค.
https://github.com/AlexeyFrolov/slt#rules -์์
์์น ํค๋๋ก API ๋ฆฌ๋๋ ์ ์ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ฃผ๋ ๋ณต์กํ ์ค์ (๋ด ํ๋ก๋์ ์ฝ๋) ์์ ์ ๋๋ค.
import r from "superagent-bluebird-promise";
import router from "./router";
export default {
"request": function (req) {
let route = router.match(req.url);
let session = req.session;
route.url = req.url;
return this
.set("route", route)
.set("session", req.session);
},
"route": {
deps: ["request"],
set: function (route, request) {
let {name, params: { id }} = route;
if (name === "login") {
return this;
}
let url = router.url({name, params: {id}});
let method = request.method ? request.method.toLowerCase() : "get";
let req = r[method]("http://example.com/api/" + url);
if (~["post", "put"].indexOf(method)) {
req.send(request.body);
}
return req.then((resp) => {
let ctx = this.ctx;
let path = url.substr(1).replace("/", ".");
if (!resp.body) {
let location = resp.headers.location;
if (location) {
ctx.set("request", {
method: "GET",
url: location.replace('/api', '')
});
}
} else {
ctx.set(path, resp.body);
}
return ctx.commit();
});
}
}
}
๋๋จธ์ง์์๋ React์ ์ง์ ๋ฐ์ธ๋ฉํ์ง ์๋๋ค๋ ์ ์ ์ ์ธํ๊ณ ๋ ๊ทํ์ ๋์ผํ ์ ๊ทผ ๋ฐฉ์์ ๋๋ค(์ ๊ฒฝ์ฐ์๋ ํ์ํ์ง ์์). ๊ณต๋์ ๋ชฉํ๋ฅผ ๋ฌ์ฑํ๊ธฐ ์ํด์๋ ์ด๋ป๊ฒ๋ ํ์ ๋ชจ์์ผ ํ๋ค๊ณ ์๊ฐํฉ๋๋ค.
๊ณ ๋ คํ๊ธฐ ์ด๋ ค์ด ๋ง์ ๊ฒฝ์ฐ๊ฐ ์๊ธฐ ๋๋ฌธ์ ๋์ ์๊ฐ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
์์ ์๊ฒฌ์์ ์ต์ข ์ฌ์ฉ์๊ฐ "๋ฐ์ดํฐ๊ฐ ์๋" ๊ตฌ์ฑ ์์๋ฅผ ๋ง๋ค๋ ค๊ณ ํ ๋๋ง๋ค ์๊ฐํด์ผ ํ๋ ๊ฐ๋ฅํ ๋ฒ์๋ฅผ ๋์ดํ ์ ์์ต๋๋ค.
.state
๋ฐ .data
์ด๊ธฐํ.context
, .props
, .state
๋ฐ .observe
์ฝํ๋๋ ์ด ์ ์์ด ์ค๋ฅ๊ฐ ๋ฐ์ํ๊ธฐ ์ฝ๊ณ ๋ถ์์ ํ๋ฉฐ ๋๋ฒ๊ทธํ๊ธฐ ์ด๋ ค์ด ๊ตฌ์ฑ ์์๋ก ์ด์ด์ง ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
@glenjamin connect
๋ฐ disconnect
์๋ช
์ฃผ๊ธฐ ํํฌ๊ฐ ์ ์ํ ๋ด์ฉ์ ๋์ํฉ๋๋ค.
์ฃผ์ ์์ ๋ฒ์ด๋ ๊ฒ์ด๋ผ๋ฉด ์ฌ๊ณผ๋๋ฆฝ๋๋ค(์ ํํ ๋งํ ์ ์์). ๊ทธ๋ฌ๋ ๋ค์์ ๊ตฌ์ฑ ์์ ํธ๋ฆฌ์ ์ํธ ์์ฉํ๊ธฐ ์ํด API๋ฅผ ๋ ธ์ถํ๋ ๊ฒ์ด ์ด ๋ฌธ์ ์ ์ ๊ทผํ๋ ํฅ๋ฏธ๋ก์ด ๋ฐฉ๋ฒ์ด๋ผ๊ณ ์๊ฐํ๋ ์ด์ ์ ๋ํ ์์ ๋๋ค. https://github.com/kevinrobinson/redux/blob/feature/loggit-todomvc/examples/loggit -todomvc/loggit/renderers/precompute_react_renderer.js#L72
์ด ๋ฐฉ๋ฒ์ ํธ๋ฆฌ๋ฅผ ๊ฑท๋ ์ ์ ํด์ปค์ ๋๋ค. ๋ฐ๋ผ์ ์ ์ง๋ฌธ์ ์ด๋ฐ ์ข ๋ฅ์ ์์ ์ ์ํํ๊ธฐ ์ํ ๊ณต๊ฐ API๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด "๊ฐ๋ก ๋ฐ์ดํฐ ๋ก๋"์์ ํ์ ์ ๊ฐ๋ฅํ๊ฒ ํ๋ ๋ฐฉ๋ฒ์ ๋๋ค. ํํฅ์์ผ๋ก ์์ ": https://github.com/kevinrobinson/redux/blob/feature/loggit-todomvc/examples/loggit-todomvc/loggit/react_interpreter.js#L8
๊ทธ๋ฌ๋ ์ฌ๊ธฐ์ ๊ตฌ์ฑ ์์ ํธ๋ฆฌ์ ์ํธ ์์ฉํ๊ธฐ ์ํด API๋ฅผ ๋ ธ์ถํ๋ ๊ฒ์ด ์ด ๋ฌธ์ ์ ์ ๊ทผํ๋ ํฅ๋ฏธ๋ก์ด ๋ฐฉ๋ฒ์ด ๋ ๊ฒ์ด๋ผ๊ณ ์๊ฐํ๋ ์ด์ ์ ๋ํ ์๊ฐ ์์ต๋๋ค.
@swannodette๊ฐ ReactConf์์ ์ด์ ๋ํด ์ด์ผ๊ธฐํ๋ค๊ณ ๋ฏฟ์ต๋๋ค. Om Next๊ฐ ํ๋ ๊ฑด์ง ๊ถ๊ธํฉ๋๋ค.
๋ค, ์ฒซ ReactConf์์ ๊ฐ์ ๊ฒ์ ์ ์ํ์ต๋๋ค. ์ต์ Om.next๋ฅผ ๋ณด๊ฑฐ๋ EuroClojure ์ด์ผ๊ธฐ๋ฅผ ๋ค์ด๋ณธ ์ ์ด ์์ง๋ง ์ด์ ์๋ Om์ด ์ฌ์ฉ์๊ฐ ์ด๋ฅผ ์ํํ๊ธฐ ์ํด ๊ตฌ์ถํด์ผ ํ๋ ์์ฒด ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ์ต๋๋ค.
์ด ๋ฐฉ๋ฒ์ ํธ๋ฆฌ๋ฅผ ๊ฑท๋ ์ ์ ํด์ปค์ ๋๋ค. ๋ฐ๋ผ์ ์ ์ง๋ฌธ์ ์ด๋ฐ ์ข ๋ฅ์ ์์ ์ ์ํํ๊ธฐ ์ํ ๊ณต๊ฐ API๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด "๊ฐ๋ก ๋ฐ์ดํฐ ๋ก๋"์์ ํ์ ์ ๊ฐ๋ฅํ๊ฒ ํ๋ ๋ฐฉ๋ฒ์ ๋๋ค. ํํฅ์์ผ๋ก ์์ "
์ด๊ฒ์ ํ ์คํธ ์ ํธ๋ฆฌํฐ์์ ๋ณผ ์ ์๋ ์์ ๋ ๋๋ง๊ณผ ๋๋ต ๋์ผํ๋ค๊ณ ์๊ฐํฉ๋๋ค. ReactEurope ์์ @sebmarkbage์ ๋ํ DOM ๋ฐ String ๋ ๋๋ง์ ํผ์ด๋ก์ ์ด๊ฒ์ ์ผ๊ธ API๋ก ๋ง๋๋ ๊ฒ์ ๋ํด ์ธ๊ธํ์ต๋๋ค. 0.14 ๋ณ๊ฒฝ ์ฌํญ์ ์ด๋ฅผ ์ํ ๊ธธ์ ๋ฉ์ง๊ฒ ํฌ์ฅํ๋ ๊ฒ ๊ฐ์ต๋๋ค.
์ด๊ธฐ ๋ฐ์์ ์ฝ๊ฐ ๋ฎ์ ์์ค์ผ ์ ์๋ค๋ ๊ฒ์ ๋๋ค. ๊ทธ๋ฌ๋ ํ์ฅ ๊ฐ๋ฅํ ์น ํญ๋ชฉ๊ณผ ์ ์ฌํ ๋ฐฉ์์ผ๋ก ์ฌ์ฉ์ ๊ณต๊ฐ์์ ์คํํ๊ธฐ๊ฐ ๋ ์ฌ์ธ ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
๋์ํฉ๋๋ค. ํธ๋ฆฌ๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํด ๋ ๋๋งํ ์ ์๋ ๋ฐฉ๋ฒ์ด ์๋ค๋ฉด ํธ๋ฆฌ๋ฅผ ํ์ํ๊ณ ํ์ํ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ์ฐพ์ ์ ๋ฌํ ์ ์๋ค๋ ์ ์ ๋์ํฉ๋๋ค.
์ ์ฒด ๊ฐ์ DOM ํธ๋ฆฌ์ ์ก์ธ์คํ๋ ๊ฒ์ ์์ ํ ๋ณ๊ฐ์ ๋ฌธ์ ๋ก ์ทจ๊ธ๋๋๋ผ๋ ์ก์ธ์คํ๊ณ ์ถ์ ๋๋๋๋ก ๊ฐ๋ ฅํ๊ณ ์ ์ฉํ ๊ธฐ๋ฅ์
๋๋ค.
React๊ฐ 0.14 ์ดํ๋ก ๋์๊ฐ๋ ๊ธธ์ ๊ณ ๋ คํ ๋ ๊ทธ๊ฒ์ด ์๋ฏธ๊ฐ ์๋ค๊ณ ์๊ฐํฉ๋๋ค.
์ต์ ๋ฒ๋ธ์ ๋ณต์ก์ฑ์ ๊ฐ์ํ ๋, ์ด ์ค๋ ๋์ ํ๋ฅญํ ์ฌ๋ฌ๋ถ์ด Meteor์ ๋ฐ์ ๋ฐ์ดํฐ ๊ตฌํ์ ์ดํด๋ณด๊ธฐ๋ฅผ ๊ฒธ์ํ๊ฒ ์ ์ํฉ๋๋ค: https://github.com/meteor/meteor/wiki/Tracker-Manual. React์ ์กฐ์ ํ๋ ค๋ฉด componentWillMount
๋ฉ์๋์์ ๋ค์๊ณผ ๊ฐ์ด ๋ฌธ์ ๊ทธ๋๋ก 3-5์ค์ ์ฝ๋๊ฐ ํ์ํฉ๋๋ค.
componentWillMount() {
if (typeof this.getState === 'function') {
Tracker.autorun(() => {
// Assuming this.getState() calls some functions that return
// reactive data sources
this.setState(this.getState());
});
}
}
Tracker(๋ณ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ์ฝ๊ฒ ์ถ์ถ๋จ)๊ฐ React์์ ๊ด์ฐฐ ๊ฐ๋ฅํ ์ง์์ ํ์์ฑ์ ์ ๊ฑฐํ๋์ง ๋ชจ๋ฅด๊ฒ ์ง๋ง ํ์คํ ๊ทธ๋ ๊ฒ ๋ณด์ ๋๋ค.
MOBservable์ ๊ด์ฐฐ ๊ฐ๋ฅํ ๊ฐ์ด ๋ณ๊ฒฝ๋๋ฉด ๊ตฌ์ฑ ์์๋ฅผ ์์ผ๋ก ์๋ก ๊ณ ์น๋ ๋งค์ฐ ์ ์ฌํ ํจํด์ ๋ฐ๋ฅด๋ฏ๋ก ํ์ฌ ์๋ช ์ฃผ๊ธฐ ๋ฉ์๋ + ๋ฐ์ฝ๋ ์ดํฐ๋ ํ์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ด๋ฌํ ์ข ๋ฅ์ ํจํด์ ํํํ๊ณ ํ์ฌ ๋ฐ์ดํฐ ์์ค ๊ฐ๋ ์ ํํํ๊ธฐ์ ์ถฉ๋ถํ ์ ์ฐ์ฑ์ ์ ๊ณตํ๋ ๊ฒ์ผ๋ก ๋ณด์ ๋๋ค. ๋ณต์กํ ์ผ๋ง ํ ๊ฒ์ ๋๋ค.
componentWillMount: function() {
var baseRender = this.render;
this.render = function() {
if (this._watchDisposer)
this._watchDisposer();
var[rendering, disposer] = mobservableStatic.watch(() => baseRender.call(this), () => {
this.forceUpdate();
});
this._watchDisposer = disposer;
return rendering;
}
},
@Mitranim ๋์ํฉ๋๋ค. ์ ๋ง ์ ์ฝ์์ต๋๋ค. ์ฐพ์์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค! ๊ทธ๊ฒ์ ํจ๊ณผ์ ์ผ๋ก https://github.com/facebook/react/pull/3920 ์ด ์ ์ํ๋ ๊ฒ์ ๋๋ค.
์ฐ๋ฆฌ๋ ์ด๋ค ์ ์์ด ๋ ๋์์ง ๊ฒฐ์ ํ์ง ๋ชปํ์ต๋๋ค. ๋ ๋ค ์ฌ์ฉํด ๋ณธ ๊ฒฐ๊ณผ ๋ฐ์ํ ํ๋ก๊ทธ๋๋ฐ(๋งํฌํ ๋๋ก, https://github.com/meteor/meteor/wiki/Tracker-Manual)์ด ๊ฐ์ผ ํ ๊ธธ์ด๋ผ๊ณ ๋๋ถ๋ถ ํ์ ํ์ง๋ง ํฉ์์ ๋๋ฌํ์ง ๋ชปํ๊ณ ์ฐ๋ฆฌ๋ ์ฌ์ ํ ๋ฌด์์ด ๊ฐ์ฅ ํฉ๋ฆฌ์ ์ธ์ง ์์๋ด๋ ค๊ณ ๋ ธ๋ ฅํ๊ณ ์์ผ๋ฏ๋ก ํผ๋๋ฐฑ์ ํ์ํฉ๋๋ค.
@Mitranim @jimfb ์ ๋ ๋ช ๋ ๋์ Meteor์ ์ด๋ ฌํ ํฌ์ด์์ต๋๋ค. Tracker๋ ์ ๋ง ๋ฉ์ง๊ณ ๋งค์ฐ ๋งค๋ ฅ์ ์ ๋๋ค. ๋งค์ฐ ๊ฐ๋จํ ๋ฒ์ ์ ํธ๋์ปค๊ฐ ์๋ํ๋ ๋ฐฉ์์ ๋ณด์ฌ์ฃผ๋ ํ๋ ์ ํ ์ด์ ์ ๋ง๋ค์์ต๋๋ค.
https://github.com/ccorcos/meteor-track/blob/master/client/main.js
๊ทธ๋ฆฌ๊ณ Tracker๋ก ๊ด์ฐฐ ๊ฐ๋ฅํ ์คํธ๋ฆผ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๋ง๋ค์์ต๋๋ค.
https://github.com/ccorcos/meteor-tracker-streams
ํ์ง๋ง Blaze ๋์ React๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ผ๋ก ์์ ํ ์ ํํ๋ฉด์ Tracker๊ฐ ๋๋ฌด ๋ณต์กํ๊ณ ๋๋ก๋ ๊ฐ๋จํ publish/subsrcribe/onChange ๋ฉ์๋๊ฐ 100๋ฐฐ ๋ ์ฝ๋ค๋ ๊ฒ์ ๊นจ๋ฌ์์ต๋๋ค.
๋ํ, ๋ชจ๋ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ํฌ์ ์ํด Tracker์๋ 99%์ ๊ฒฝ์ฐ์ ์ดํด๊ฐ ๊ฐ๋ ๋ช ๊ฐ์ง ๋ถ์์ฉ์ด ์์ง๋ง ๋๋ก๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค. ๋ค์์ React ๊ตฌ์ฑ ์์์์ ๋ณด์ด๋ ๋ฐฉ๋ฒ์ ๋๋ค.
componentWillMount: ->
<strong i="15">@c</strong> = Tracker.autorun =>
@setState({loading: true})
Meteor.subscribe 'users', => @setState({loading: false})
Tracker.autorun =>
@setState({users: Users.find({}, {sort:{name:-1}}).fetch()})
componentWillUnmount: ->
@c.stop()
๋ถ์์ฉ์ ๋ํ ์ ์์ ์ c.stop()
๊ตฌ๋
๊ณผ ๋ด๋ถ ์๋ ์คํ๋ ์ค์ง๋๋ค๋ ๊ฒ์
๋๋ค.
@ccorcos ์, https://github.com/facebook/react/pull/3920์์ ๋ชจ๋ ๋ถ์์ฉ์ ์์ ํ React ๋ด๋ถ์ ์์ต๋๋ค. ์ฌ์ค, React ์ฝ์ด๋ ๋์ฐ๋ณ์ด๋ฅผ ์ํํ์ง ์๋ ์์ ํ ๋ถ๋ณ/๊ธฐ๋ฅ์ ์ธ ๋ฐฉ์์ผ๋ก ๊ทธ๊ฒ๋ค์ ๊ตฌํํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๋ถ์์ฉ์ ์ธ๋ถ์์ ๋ณผ ์ ์๊ธฐ ๋๋ฌธ์ ๊ตฌํ ์ธ๋ถ ์ฌํญ์ ๋๋ค.
ํฅ๋ฏธ๋กญ์ต๋๋ค... ๊ทธ๋ ๋ค๋ฉด ๊ทธ๋ฅ onChange ์ฝ๋ฐฑ์ ์ฌ์ฉํ์ง ์๋ ์ด์ ๋ ๋ฌด์์ ๋๊น? ๋๋ ๊ทธ๊ฒ๋ค์ด ๊ฐ์ฅ ํธํ๋๋ ๊ฒ์ ๋ฐ๊ฒฌํ์ต๋๋ค. Meteor(Tracker), RxJS, Highland.js ๋ฑ์ ์ฌ์ฉํ๋ ์๊ด์์ด ์ด๋ฒคํธ ์ฝ๋ฐฑ์ผ๋ก ํญ์ ๊ฐ๋จํ๊ฒ ํตํฉํ ์ ์์ต๋๋ค. React ๊ณ ์ฐจ ๊ตฌ์ฑ ์์์ ๋์ผํฉ๋๋ค.
Redux๊ฐ ๋ง์์ ๋๋ ์ ์ ์ด ๋ ผ๋ฆฌ๋ฅผ ํ๋ ์์ํฌ์์ ์ ์ธํ๊ณ React ๊ตฌ์ฑ ์์๋ฅผ ์์ํ ๊ธฐ๋ฅ์ผ๋ก ์ ์งํ๋ค๋ ๊ฒ์ ๋๋ค.
@ccorcos ์ฃผ์ ๋ฌธ์ ๋ ๊ตฌ์ฑ ์์ ์ธ์คํด์ค๊ฐ ํ๊ดด๋ ๋ ๋ชจ๋ "๊ตฌ๋ "์ ์ ๋ฆฌํด์ผ ํ๋ค๋ ๊ฒ์ ๋๋ค. ๊ตฌ์ฑ ์์ ์์ฑ์๋ ์ข ์ข ์ด ์ ๋ฆฌ๋ฅผ ์์ด๋ฒ๋ ค ๋ฉ๋ชจ๋ฆฌ ๋์๊ฐ ๋ฐ์ํฉ๋๋ค. ์ฐ๋ฆฌ๋ ๊ทธ๊ฒ์ด ์๋์ด๊ธฐ๋ฅผ ์ํ๋ฏ๋ก ์ฐ๊ธฐ๊ฐ ๋ ์ฝ๊ณ (๋ณด์ผ๋ฌ ํ๋ ์ดํธ๊ฐ ์ ์) ์ค๋ฅ๊ฐ ๋ฐ์ํ๊ธฐ ์ฝ์ต๋๋ค(์๋ ์ ๋ฆฌ).
@jimfb ๋ง์ต๋๋ค. ์๋ ๊ตฌ๋ ์ทจ์๋ Tracker์ ์ ๊ทผ ๋ฐฉ์์์ ์ ๋ง ๋ฉ์ง ๊ธฐ๋ฅ ์ค ํ๋์ ๋๋ค. ๋ฐ์ ๋ฐ์ดํฐ ์์ค์ ๋ํ ๊ฐ ํธ์ถ์ ๊ตฌ๋ ์ ๋ค์ ์ค์ ํ๊ณ ๊ตฌ์ฑ ์์๊ฐ ๋ฐ์ดํฐ ํธ์ถ์ ์ค์งํ๋ฉด ์ ๋ฆฌํ ๊ฒ์ด ์์ต๋๋ค!
์, ํ์ง๋ง ์ค์ ๋ก "์๋์ผ๋ก" ๊ตฌ๋
์ทจ์๋๋ ๊ฒ์ ์๋๋๋ค. ๊ตฌ์ฑ ์์๊ฐ ๋ง์ดํธ ํด์ ๋ ๋ c.stop()
๋ฅผ ํธ์ถํด์ผ ํฉ๋๋ค. ๊ทธ๋ฌ๋ mixin์ ์ฌ์ฉํ์ฌ ์ถ์ํํ ์ ์์ต๋๋ค.
componentWillMount: ->
<strong i="7">@autorun</strong> =>
@setState({loading: true})
Meteor.subscribe 'users', => @setState({loading: false})
Tracker.autorun =>
@setState({users: Users.find({}, {sort:{name:-1}}).fetch()})
๊ทธ๋ฌ๋ ์ด๊ฒ์ ์ค์ ๋ก ๋ค๋ฅธ API์ ๋ค๋ฅด์ง ์์ต๋๋ค. ๋ง์ดํธ ํด์ ๋ฑ์ ๊ฒฝ์ฐ ์๋์ผ๋ก ๊ตฌ๋ ์ ์ทจ์ํ๋ ๊ธฐ๋ณธ ์ ๊ณต ๋ฉ์๋๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค. ๋ณด์ธ์. ์ ๋ Meteor์ ์ด๋ ฌํ ํฌ์ ๋๋ค. ๊ทธ๋์ ๋๋ ๋น์ ์๊ฒ ์ด๊ฒ์ ๋ํด ์ด์ผ๊ธฐํ๊ณ ์ถ์ง ์์ต๋๋ค. ๊ทธ๋ฅ ๊ฐ๋, ๋๋ ๊ทธ๊ฒ์ ์ต์ํ์ง ์์ ๋๊ตฐ๊ฐ์๊ฒ ์ด ๋ด์ฉ์ ์ค๋ช ํ๋ ๊ฒ์ด ์ ๋ง ์ด๋ ต๋ค๋ ๊ฒ์ ์๊ฒ ๋ฉ๋๋ค. ํํธ, ๊ฐ๋จํ ๋ฆฌ์ค๋/์ด๋ฒคํธ ์ด๋ฏธํฐ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ์ดํดํ๊ณ ๊ตฌํํ๊ธฐ๊ฐ ํจ์ฌ ๋ ๊ฐ๋จํ๋ฉฐ ์ฌ์ฉํ๋ ค๋ ๋ฐ์์ฑ ์์คํ ๊ณผ ๋งค์ฐ ํธํ๋๋ ๊ฒฝํฅ์ด ์์ต๋๋ค...
@ccorcos ์ฐ๋ฆฌ๋ ๋ค๋ฅธ ๋ฉ์ปค๋์ฆ์ ๋ํด ์ด์ผ๊ธฐํ๊ณ ์์์ง๋ ๋ชจ๋ฆ ๋๋ค. ๋ง์ง๋ง์ผ๋ก ํ์ธํด๋ณด๋ Tracker์๋ ์๊ตฌ ๊ตฌ๋ ์ด ์์์ต๋๋ค. ๋ฐ์ ๋ฐ์ดํฐ ์์ค์ ๋ํ ์ข ์์ฑ์ ์ค์ ํ๋ ๊ฐ ํจ์(์ก์ธ์คํ์ฌ)๋ ๋ณ๊ฒฝ๋ ๋ _ํ ๋ฒ_ ๋ค์ ์คํ๋๊ณ ๊ตฌ๋ ์ด ์ข ๋ฃ๋ฉ๋๋ค. ๋ฐ์ดํฐ ์์ค์ ๋ค์ ์ก์ธ์คํ๋ฉด ํ ๋ฒ ๋ ๋ณ๊ฒฝํ๊ธฐ ์ํด "๊ตฌ๋ "์ด ๋ค์ ์ค์ ๋ฉ๋๋ค. ๋ฑ๋ฑ.
@Mitranim ์ ์ ํํ๊ณ #3920์ ์๋ฏธ๋ Meteor๋ณด๋ค ๋ "์๋"์ด๋ฉฐ(๊ตฌ๋ ์ทจ์๋ ์ค์ ๋ก ์๋์ ๋๋ค) ์ผ๋ฐ์ ์ธ ์ฌ์ฉ ์ฌ๋ก์์ ๋ง ๊ทธ๋๋ก API ํ๋ฉด์ ์ด 0์ด๊ธฐ ๋๋ฌธ์ ํจ์ฌ ๊ฐ๋จํฉ๋๋ค.
@ccorcos @Mitranim ์ฌ์ฉํ ์ค๋น๊ฐ ๋ Tracker/Vue.js ์๊ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๊ฒฝ์ฐ Mobservable ์ ์๋ํ ์ ์์ผ๋ฉฐ _render_ ๋์ ์ก์ธ์ค๋๋ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ๊ด์ฐฐํ๊ณ ๋ง์ดํธ ํด์ ์ ๋ชจ๋ ๊ตฌ๋ ์ ์ญ์ ํฉ๋๋ค(๊ทธ๋๊น์ง ๊ตฌ๋ ์ด ํ์ฑ ์ํ๋ก ์ ์ง๋จ). ์ง๊ธ๊น์ง Mendix์์ ๊ฝค ํฐ ํ๋ก์ ํธ์ ์ฑ๊ณต์ ์ผ๋ก ์ ์ฉํ์ต๋๋ค. ์์ฒด ๋ชจ๋ธ ๊ฐ์ฒด๋ฅผ ์ ๊ณตํ๋ ๋์ ๊ธฐ์กด ๊ฐ์ฒด๋ฅผ ์ฅ์ํ ๋ฟ๋ง ์๋๋ผ ๋ฐ์ดํฐ์ ๋ฐฉํด๊ฐ ๋์ง ์์ต๋๋ค.
๋ง์ง๋ง์ผ๋ก ํ์ธํด๋ณด๋ Tracker์ ์๊ตฌ ๊ตฌ๋ ์ด ์์์ต๋๋ค.
@Mitranim ๊ตฌ๋ ์ ์๊ตฌ์ ์ผ ์ ์์ต๋๋ค. ์ด๊ฒ ์ข ๋ด.
sub = Meteor.subscribe('chatrooms')
# this subscription lasts until...
sub.stop()
์ด์ Tracker์ ๋ช ๊ฐ์ง ํฅ๋ฏธ๋ก์ด ๊ธฐ๋ฅ์ด ์์ต๋๋ค. ์ด๊ฒ ์ข ๋ด.
comp = Tracker.autorun ->
Meteor.subscribe('chatrooms')
# this subscription lasts until...
comp.stop()
๋ง์ง๋ง ์์ ๋ ๊ทธ๋ค์ง ์ ์ฉํ์ง ์์ต๋๋ค. ์ฐ๋ฆฌ๊ฐ ์ด๋ฐ ์ผ์ ํ ๋๊น์ง.
roomId = new ReactiveVar(1)
comp = Tracker.autorun ->
Meteor.subscribe('messages', roomId.get())
# when I change the roomId, the autorun will re-run
roomId.set(2)
# the subscription to room 1 was stopped and now the subscription to room 2 has started
# the subscription is stopped when I call stop...
comp.stop()
๋ฐ์ ๋ฐ์ดํฐ ์์ค์ ๋ํ ์ข ์์ฑ์ ์ค์ ํ๋ ๊ฐ ํจ์(์ก์ธ์คํ์ฌ)๋ ๋ณ๊ฒฝ๋ ๋ ํ ๋ฒ ๋ค์ ์คํ๋๊ณ ๊ตฌ๋ ์ด ์ข ๋ฃ๋ฉ๋๋ค.
๊ตฌ๋ ์ ์๋ ์คํ์ด ๋ค์ ์คํ๋๊ฑฐ๋(๋ฐ์ ์ข ์์ฑ์ด ๋ณ๊ฒฝ๋จ) ํด๋น ๊ตฌ๋ ์ด ์๋ ๊ณ์ฐ์ด ์ค์ง๋ ๋๊น์ง ์ง์๋ฉ๋๋ค. ๋ ๋ค compute.onInvalidate ํํฌ๋ฅผ ํธ์ถํฉ๋๋ค.
๋ค์์ ๋๊ฐ์ ์ผ์ ํด๋ธ ์์ฃผ ๊ธฐ๋ฐํ ๋ฒ์ ์ ๋๋ค. Tracker๊ฐ ์ด๋ป๊ฒ ์๋ํ๋์ง ์ดํดํ๋ ๋ฐ ๋์์ด ๋๊ธฐ๋ฅผ ๋ฐ๋๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ด์ฉ๋ฉด ๋น์ ์ ๊ทธ๊ฒ์ด ์ผ๋ง๋ ์ง์ ๋ถํด์ง ์ ์๋์ง๋ ์๊ฒ ๋ ๊ฒ์ ๋๋ค.
comp = Tracker.autorun ->
Meteor.subscribe('chatrooms')
# is the same as
comp = Tracker.autorun (c) ->
sub = null
Tracker.nonreactive ->
# dont let comp.stop() stop the subscription using Tracker.nonreactive
sub = Meteor.subscribe('chatrooms')
c.onInvalidate ->
# stop the subscription when the computation is invalidated (re-run)
sub.stop()
# invalidate and stop the computation
comp.stop()
@ccorcos ์ด์ ํผ๋์ ์์ธ์ด ๋ณด์
๋๋ค. ๋ด ์ฌ์ ์ด์๋ค. ๊ตฌ๋
์ ๋ํด ์ด์ผ๊ธฐํ ๋ _Meteor ๊ตฌ๋
_์ ์๋ฏธํ๋ ๊ฒ์ ์๋๋๋ค. ๊ทธ๋ค์ ์๋ฒ์์ ํด๋ผ์ด์ธํธ๋ก ํธ์๋๋ ๋ฐ์ดํฐ๋ฅผ ๊ฒฐ์ ํ์ง๋ง ์ด ํ ๋ก ์ ์ฃผ์ ์ธ ๋ณด๊ธฐ ๊ณ์ธต ์
๋ฐ์ดํธ์ ๊ด๋ จ์ด ์์ต๋๋ค. _subscription_์ ๋งํ ๋ ๋๋ ์ ํต์ ์ธ ์ด๋ฒคํธ ๋ฆฌ์ค๋์ ๋ฐ์์ฑ ๋ฐ์ดํฐ ์์ค์ ์์กดํ๋ ๊ธฐ๋ฅ์ ์ฌ์คํํ๋ Tracker์ ๋ฅ๋ ฅ ์ฌ์ด์ ํํ์ ์ ๊ทธ๋ ธ์ต๋๋ค. React ๊ตฌ์ฑ ์์์ ๊ฒฝ์ฐ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์จ ๋ค์ setState
๋๋ forceUpdate
๋ฅผ ํธ์ถํ๋ ๊ตฌ์ฑ ์์ ๋ฉ์๋์
๋๋ค.
@mweststrate ์๋ฅผ ๋ค์ด ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค. ํฅ๋ฏธ๋กญ๊ฒ ๋ณด์ ๋๋ค.
์ ์. ๊ทธ๋์ ๊ทธ๋ค์ ๊ทธ๊ฒ์ ํ๋ ์๋ฆฌํ ๋ฐฉ๋ฒ์ ๊ฐ์ง๊ณ ์์ต๋๋ค.
componentWillMount: function() {
this.comp = Tracker.autorun(() => {
let sub = Meteor.subscribe('messages')
return {
loading: !sub.ready(),
messages: Messages.find().fetch()
}
})
componentWillUnmount: function() {
this.comp.stop()
}
๊ตฌ๋ ์ ๋ฌธ์ ์์ด ๋งค๋ฒ ๋ค์ ๊ตฌ๋ ํฉ๋๋ค. sub.ready ๋ฐ Messages.find.fetch๋ ๋ชจ๋ "๋ฐ์์ "์ด๋ฉฐ ๋ณ๊ฒฝ๋ ๋๋ง๋ค ์๋ ์คํ์ด ๋ค์ ์คํ๋๋๋ก ํธ๋ฆฌ๊ฑฐํฉ๋๋ค. Tracker์ ๋ฉ์ง ์ ์ ์๋ ์คํ์ ์จ๊ธฐ๊ธฐ ์์ํ๊ณ ๋ฌธ์์์ ํน์ ๊ธฐ๋ฅ์ด "๋ฐ์ ์ปจํ ์คํธ" ๋ด์ ์๋ค๋ ๊ฒ์ ๋ฌธ์์ ํฌํจํ ๋์ ๋๋ค.
์ด๊ฒ์ mixin์ ๋์ง ์ ์์ต๋๋ค.
componentWillMount: function() {
this.comp = Tracker.autorun(() => {
return this.getReactiveData()
})
componentWillUnmount: function() {
this.comp.stop()
}
๊ทธ๋ฆฌ๊ณ ๋๋ฉด ์๋ํ๋ ๋ง์ ์ฒ๋ผ ๋ฐ์ํ๋ ๊ธฐ๋ฅ๋ง ๋จ๊ฒ ๋ฉ๋๋ค!
getReactiveData: function() {
let sub = Meteor.subscribe('messages')
return {
loading: !sub.ready(),
messages: Messages.find().fetch()
}
}
ํธ๋์ปค๊ฐ ์ด๋ ๊ฒ ๋ฉ์ง๋ฐ...
@ccorcos ์ถ์ ๊ธฐ ์คํ์ผ ์ด๋ฒคํธ๋ฅผ ์ฌ์ฉํ ๋ ์๋ unsubs์ ๋ํด ๋ค์ ์๋ชป๋ ๊ฒ์ผ๋ก ๋ํ๋ฌ์ต๋๋ค. componentWillUnmount
์์ ๋ฆฌ์ค๋๋ฅผ ์ค์งํด์ผ ํฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ๊ณ์ํด์ ๋ฐ์ดํฐ ์์ค์ ๋๋ฌํ๊ณ setState
๋ฅผ ํธ์ถํฉ๋๋ค(ํ์ฌ ์ฌ์ฉ๋์ง ์๋ isMounted()
๋ก ํ์ธํ์ง ์๋ ํ).
์ฐธ๊ณ ๋ก ์ฐ์ํ ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ๋ง๋ค์ด ๊ตฌ์ฑ ์์ ๋ฉ์๋๋ฅผ ๋ฐ์ํ์ผ๋ก ๋ง๋ค ์ ์์ต๋๋ค. ๋ค์์ ๋ช ๊ฐ์ง ์์ ๋๋ค. [1] , [2] . ๋ค์๊ณผ ๊ฐ์ด ๋ณด์ ๋๋ค.
export class Chat extends React.Component {
<strong i="13">@reactive</strong>
updateState () {
this.setState({
auth: auth.read(),
messages: messages.read()
})
}
/* ... */
}
@Mitranim ๊ฝค ๊น๋ํฉ๋๋ค -- ๊ทธ๋๋ ๊ณ ์ฐจ์ ๊ธฐ๋ฅ์ ์ ํธํฉ๋๋ค. ;)
@sebmarkbage @jimfb ์ ๋ ์ด ์ค๋ ๋์ alt ์ค๋ ๋(#3858)๋ฅผ ๋ช ๋ฌ ๋์ ํ๋ก์ฐํ๊ณ ์์ผ๋ฉฐ ํต์ฌ ํ์ด ์ด ๋ฌธ์ ์ ๋ํด ํฉ์์ ๋๋ฌํ๋์ง ๋๋ ์ ์ด๋ ์ผ๋ฐ์ ์ธ ๋ฐฉํฅ์ ๋๋ฌํ๋์ง ๊ถ๊ธํฉ๋๋ค.
@oztune ์ ๋ฐ์ดํธ ์์; ์ฐ๋ฆฌ๋ ๋ค๋ฅธ ์ฐ์ ์์์ ์ง์คํ์ต๋๋ค. ์ด ์ฃผ์ ์ ๋ํ ์ ๋ฐ์ดํธ๊ฐ ์์ ๋ ์ค๋ ๋ ์ค ํ๋์ ๊ฒ์ํ ๊ฒ์ ๋๋ค.
์ฌ๋ฌ๋ถ, ์ปจํ ์ด๋๋ฅผ ๊ตฌ์ฑํ๋ ๋ฒ์ฉ API๋ฅผ ๋ง๋ค์์ต๋๋ค. ๋ฐ์ ๊ตฌ์ฑ๊ธฐ๋ฅผ ํ์ธํ์ญ์์ค. ์ฆ, ๊ณ ์ฐจ ๊ธฐ๋ฅ์ ๊ฐ์ง ์ปจํ ์ด๋๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
import { compose } from `react-komposer`;
// Create a component to display Time
const Time = ({time}) => (<div>{time}</div>);
// Create the composer function and tell how to fetch data
const composerFunction = (props, onData) => {
const handler = setInterval(() => {
const time = new Date().toString();
onData(null, {time});
}, 1000);
const cleanup = () => clearInterval(handler);
return cleanup;
};
// Compose the container
const Clock = compose(composerFunction)(Time);
// Render the container
ReactDOM.render(<Clock />, document.getElementById('react-root'));
์ฌ๊ธฐ ๋ผ์ด๋ธ ๋ฒ์ ์ด ์์ต๋๋ค: https://jsfiddle.net/arunoda/jxse2yw8/
๋ํ Promises, Rx.js Observables ๋ฐ With Meteor's Tracker๋ฅผ ์ฌ์ฉ ํ์ฌ ์ปจํ ์ด๋๋ฅผ ๊ตฌ์ฑํ๋ ๋ช ๊ฐ์ง ์ฌ์ด ๋ฐฉ๋ฒ์ด ์์ต๋๋ค.
๋ํ ์ด์ ๋ํ ๋ด ๊ธฐ์ฌ๋ฅผ ํ์ธํ์ญ์์ค. Let's Compose Some React Containers
@arunoda ์ฐ๋ฆฌ๋ ๋งค์ฐ ๋น์ทํ ์ผ์ ํ๊ฒ ๋์์ต๋๋ค. ํ ๊ฐ์ง ๊ถ๊ธํ ์ ์ prop์ด ๋ณ๊ฒฝ๋ ๋๋ง๋ค composerFunction ์ด ํธ์ถ๋์ง ์๋๋ก ํ๋ ๋ฐฉ๋ฒ์ ๋ฌด์์ ๋๊น?
@oztune ์ค์ ๋ก ์ด์ ๋ค์ ์คํ๋ฉ๋๋ค. ์ฐ๋ฆฌ๋ ์ด Lokka ์ Meteor๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๋ ๋ค ๋ก์ปฌ ์บ์๊ฐ ์์ผ๋ฉฐ ์ฐ๋ฆฌ๊ฐ composerFunction์ ์ฌ๋ฌ ๋ฒ ํธ์ถํ๋๋ผ๋ ์๋ฒ์ ๋๋ฌํ์ง ์์ต๋๋ค.
ํ์ง๋ง ๋ค์๊ณผ ๊ฐ์ด ํ ์ ์๋ค๊ณ ์๊ฐํฉ๋๋ค.
const options = {propsToWatch: ["postId"]};
const Clock = compose(composerFunction, options)(Time);
์ด๋ค ์์ด๋์ด?
@arunoda ๊ทธ๊ฒ์ด ์ฐ๋ฆฌ๋ ์๋ํ ๊ฒ์ด์ง๋ง, ๊ทธ๊ฒ์ ์ก์ ๊ณผ ๊ทธ ์์กด์ฑ ์ฌ์ด์ ์ฝ๊ฐ์ ๋จ์ ์ ๋ง๋ญ๋๋ค. ์ด์ react-async์ ์ ์ฌํ ์์ ์ ์ํํฉ๋๋ค. ์ฌ๊ธฐ์ ์ฃผ์ด์ง ์์ ์ ์ฆ์ ์ํํ๋ ๋์ composerFunction์ด ํจ์์ ํค๋ฅผ ๋ฐํํฉ๋๋ค. ํค๊ฐ composerFunction์ ์ํด ๋ฐํ๋ ์ด์ ํค์ ๋ค๋ฅธ ๊ฒฝ์ฐ ์ ๊ธฐ๋ฅ์ด ์ํ๋ฉ๋๋ค. ์ด๊ฒ์ด ์ด github ์ค๋ ๋์ ์ ์ ์ธ์ง ํ์คํ์ง ์์ผ๋ฏ๋ก Twitter(๋์ผํ ์ฌ์ฉ์ ์ด๋ฆ)์์ ๊ณ์ํด์ ๊ธฐ์ฉ๋๋ค.
@oztune ๋๋ ์๋ก์ด GH ์ด์๋ฅผ ๋ง๋ค์๊ณ ๊ฑฐ๊ธฐ์ ์ฐ๋ฆฌ์ ์ฑํ ์ ๊ณ์ํฉ์๋ค. ํธ์ํฐ๋ณด๋ค ํจ์ฌ ๋์ ๊ฒ ๊ฐ์์.
๋ด๊ฐ Observable์ ์ํ(์: this.props.todo$)์ผ๋ก ์ ๋ฌํ๊ณ JSX์ ํฌํจํ ์ ์๋๋ก JSX๊ฐ Observable์ ์ง์ ์ดํดํ๊ณ ๋ ๋๋งํ๋๋ก ํ๋ฉด ์ ๋ฉ๋๋ค. ๊ทธ๋ฌ๋ฉด API๊ฐ ํ์ํ์ง ์๊ณ ๋๋จธ์ง๋ React ์ธ๋ถ์์ ๊ด๋ฆฌ๋๊ณ HoC๋ ๊ด์ฐฐ ๊ฐ๋ฅ ํญ๋ชฉ์ ์ฑ์ฐ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. props์ ์ผ๋ฐ ๋ฐ์ดํฐ ๋๋ ๊ด์ฐฐ ๊ฐ๋ฅ ๋ฐ์ดํฐ๊ฐ ํฌํจ๋์ด ์๋์ง ์ฌ๋ถ๋ ์ค์ํ์ง ์์ผ๋ฏ๋ก ํน๋ณํ this.data๊ฐ ํ์ํ์ง ์์ต๋๋ค.
๋ํ React render๋ ์ถ๊ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์ด ๋งํฌ์ ์ค๋ช ๋ ๋์์ธ์ ํ์ฉํ๋ Oservable[JSX]์ ๋ ๋๋งํ ์ ์์ต๋๋ค.
https://medium.com/@milankinen/containers -are-dead-long-live-observable-combinators-2cb0c1f06c96#.yxns1dqin
์๋
ํ์ธ์,
ํ์ฌ๋ก์๋ rxjs ์คํธ๋ฆผ๊ณผ ํจ๊ป ์ํ ๋น์ ์ฅ ๊ตฌ์ฑ ์์๋ฅผ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋ค๋ฅธ API์ ํ์์ฑ์ ์ดํดํ์ง ๋ชปํฉ๋๋ค.
๋๋ ์์ ๋ฅผ ์์ฑํ์ต๋๋ค. ๋ณด๋ ์์ ๋ง์ฐ์ค๋ฅผ ์ฌ๋ฆด ์ ์๊ณ 26์ ๋๋ฌํ๋ฉด ๋ค์ ์์ํ๋๋ก ๋ณ๊ฒฝ๋ฉ๋๋ค.
์ด ๋ฐฉ๋ฒ์ ๋ํด ์ด๋ป๊ฒ ์๊ฐํ๋์ง ๋ฃ๊ณ ์ถ์ต๋๋ค.
์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
https://jsfiddle.net/a6ehwonv/74/
@giltig : ์ ๋ ์ต๊ทผ์ ์ด๋ ๊ฒ ๋ฐฐ์ฐ๊ณ ์๋๋ฐ ์ข์์. Cycle.js์ ํจ๊ปํฉ๋๋ค.
๋ธ๋ฆฌ์ง์ ์ํด ์ฃผ์ ๋ฅผ ์ ๋ฌํ์ง ์๊ณ ๋ ๊ตฌ์ฑ ์์์ ์ ์๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ์ด๋ป๊ฒ๋ ์ฝ๊ฒ ๋ค์ ์ ์๊ฒ ๋์ด ๊ฐ์ฌํฉ๋๋ค. ๋ด๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์ดํดํ๋ค๋ฉด ์ฌ๊ธฐ์ ์ ์๋ ๊ฒ๊ณผ๋ ๊ฑฐ์ ๋ฐ๋์ ๋๋ค. ๋๋ ํฉ์ฑ ์ด๋ฒคํธ์ ๋ํด React vdom์ ๊ด์ฐฐํ ์ ์๋ ๊ฒฝ์ฐ "ref"๋ฅผ ๊ด์ฐฐ์ฉ์ผ๋ก ์ฌ์ฉํ์ฌ CSS ํ๊ทธ๊ฐ ๊ด์ฐฐ๋์ง ์๋๋ก ํ ์ ์์ต๋๋ค.
๋ ํฐ ๊ตฌ์ฑ ์์๋ฅผ ๋ง๋ค๊ธฐ ์ํด React ๊ธฐ๋ฅ ๊ตฌ์ฑ ์์๋ฅผ ์ง์ ์ฌ์ฉํ ์ ์๋๋ก RxJ๋ CombineLatest์์ ๊ฐ์ฒด๋ฅผ ์ง์ํ ์ ์์ต๋๋ค.
const myFancyReactComponent = ({surface, number, gameover}) => (
<div>
{gameover ? gameover : surface}
{number}
</div>
)
const LiveApp = Rx.Observable.combineLatest(
LiveSurface, DynamicNumberView, DynamicGameOver,
myFancyReactComponent
)
์๋
,
์ฐ๋ฆฌ๊ฐ Cycle์ด๋ ๋ค๋ฅธ ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ์ง ์๋ ์ด์ ๋ ํ๋ ์์ํฌ๋ณด๋ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ ํธํ๊ธฐ ๋๋ฌธ์ด๋ฉฐ(๊ฐ๋ฐ์์๊ฒ ๋ ๋ง์ ์ ์ด ๊ถํ์ด ์์) ๋ํ React๊ฐ ๊ฐ์ง ์ปค๋ฎค๋ํฐ์ ํ์ ์ฆ๊ธฐ๊ณ ์ถ๊ธฐ ๋๋ฌธ์
๋๋ค.
ํ์ฌ React์ฉ์ผ๋ก ๋ง์ ๋ ๋ ์์ง์ด ๊ฐ๋ฐ๋์์ผ๋ฉฐ ์ฌ์ฉํ์ง ์๋ ๊ฒ์ด ์ ๊ฐ์
๋๋ค(ReactNative, ReactDom, ReactThree ๋ฑ). Rxjs๋ง ์ฌ์ฉํ๊ณ ์์์ ๋ณด์ฌ์ค ์์ ๊ฐ์ด ๋ฐ์ํ๋ ๊ฒ์ ๋งค์ฐ ๊ฐ๋จํฉ๋๋ค.
๋ฆฌ์กํธ ์ปดํฌ๋ํธ๊ฐ ์ต์ ๋ฒ๋ธ์ด props์ธ ํ ํฌ์กฐ๋ฅผ ๋ฐ์๋ค์ผ ์ ์๋ค๋ฉด ์๊ฐ์ด ๋ ์ฌ์์ก์ ๊ฒ์ ๋๋ค. ์ง๊ธ์ผ๋ก์๋ ๋ถ๊ฐ๋ฅํ๋ฏ๋ก ์์์ ์ค๋ช ํ ๊ฒ์ด ์ฐ๋ฆฌ๊ฐ ์ ํํ ๋ฐฉ์์ ๋๋ค.
BTW MyFancyReactComponent๋ก ์ํํ ์์ ์ ๊ฐ๋ฅํ๋ฉฐ jsx๋ฅผ ์ง์ ์์ฑํ ์๋ ์์ง๋ง ์ผ๋ถ ๊ฒฝ์ฐ์๋ ์ค์ ๋ก ๊ทธ๋ ๊ฒ ํ์ต๋๋ค.
์ฃผ์ ์ ๊ด๋ จํ์ฌ - ๊ฒฐ๊ตญ React ๊ตฌ์ฑ ์์์์ ๋ฌด์์ด๋ ๋ ์์๋ ์ฒ๋ฆฌ๊ธฐ ๊ธฐ๋ฅ์ ์ฌ์ฉํ๊ณ ์๊ธฐ ๋๋ฌธ์ ์ ํจํ ๋ฐฉ๋ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค. ๋๋ ์ด๋ฒคํธ๋ฅผ ์์ ํ๋ ๋ด๋ถ ์ฃผ์ ๋ฅผ ์ฌ์ฉํ์ฌ ๊ตฌํํ๊ธฐ๋ก ์ ํํ์ง๋ง ๋ค๋ฅธ ์ฌ๋์ด ์ ํํ ์ ์์ต๋๋ค. ์ ์ฐํฉ๋๋ค.
๋ฆฌ์กํธ ์ปดํฌ๋ํธ๊ฐ ์ต์ ๋ฒ๋ธ์ด props์ธ ํ ํฌ์กฐ๋ฅผ ๋ฐ์๋ค์ผ ์ ์๋ค๋ฉด ์๊ฐ์ด ๋ ์ฌ์์ก์ ๊ฒ์ ๋๋ค. ์ง๊ธ์ผ๋ก์๋ ๋ถ๊ฐ๋ฅํ๋ฏ๋ก ์์์ ์ค๋ช ํ ๊ฒ์ด ์ฐ๋ฆฌ๊ฐ ์ ํํ ๋ฐฉ์์ ๋๋ค.
๊ด์ฐฐ ๊ฐ๋ฅํ ์ํ์ ์ฅ๊ธฐ์ ์ผ๋ก ์๋ฏธ๊ฐ ์์ต๋๋ค. ์ฌ์ค ๊ทธ๋ฐ ๋งฅ๋ฝ์์ ์ ํ ์๋ฏธ๊ฐ ์์ต๋๋ค..
Suspense(์บ์ + ์ปจํ ์คํธ)๊ฐ ์๋ ๋ค๋ฅธ ๋ชจ๋ธ๋ก ๋๋ ๊ฒ์ฒ๋ผ ๋ค๋ฆฝ๋๋ค. ์บ์ ์์ฒด๊ฐ ๊ตฌ๋ ์ ๋ํ ์ง์์ ๋ฐ์ ์ ์์ต๋๋ค. https://github.com/facebook/react/issues/13206 ์์ Suspense์ ๋จ์ ์์ ์ ์ถ์ ํ ์ ์์ต๋๋ค
๋ํ ๋ ๊ฒฉ๋ฆฌ๋ ์ฌ๋ก๋ฅผ ์ํ ๊ตฌ๋ ํจํค์ง๋ ์ ๊ณตํฉ๋๋ค.
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
๋๊ตฐ๊ฐ๊ฐ ์ด๋ฐ ์ข ๋ฅ์ API๋ฅผ ๊ฐ์ง๊ณ ๋๊ณ ์ถ๋ค๋ฉด
observe
์ ๋ํด ๊ณ ์ฐจ ๊ตฌ์ฑ ์์๋ก ์ ๋ง ๋ฉ์ฒญํ ํด๋ฆฌํ์ ๋ง๋ค์์ต๋๋ค.์ฉ๋ฒ: