์ฐ์ ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ฌ๋ฌ๋ถ์ด ์ฌ์ฉํ๊ณ ์๋ ํจํด์ด ๋ง์์ ๋ญ๋๋ค. ๐๐
redux๋ฅผ ์ฌ์ฉํ์ฌ isomorphic ์ฑ์ ๋น๋ํ๋ ค๊ณ ํฉ๋๋ค. ์ด๊ธฐ ํ์ด์ง ๋ก๋๋ฅผ ๋ฐํํ๊ธฐ ์ ์ ๋ด ์์ ์ด (์๋ฒ์์) ๋ก๋๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ๋ ๋ฐฉ๋ฒ์ ์์์ผ ํ๋ค๋ ์ ์ ์ ์ธํ๋ฉด ์ง๊ธ๊น์ง๋ ํ๋ฅญํ๊ฒ ์๋ํ๊ณ ์์ต๋๋ค. ์ด์์ ์ผ๋ก๋ ๋ก๋๊ฐ ์์ ์์ฒด์์ ๋ฐ์ํด์ผ ํ์ง๋ง dispatch(userActions.load())
ํธ์ถํ๋ฉด ์์ ์ด ์ ์ํ(์: return { ...state, loading: true };
)๋ฅผ ๋ฐํํด์ผ ํ๋ฏ๋ก ์ฝ์์ ๋ฐํํ ์ ์์ต๋๋ค. ๊ธฐ๋ค๋ฆฝ๋๋ค. dispatch()
๋ ์ด๋ค ์ด์ ๋ก ์ ๋ฌ๋ ์์
์ ๋ฐํํฉ๋๋ค. ๋๋ ์ ๋ง๋ก ๊ฐ์ ๊ฒ์ ์ํฉ๋๋ค ...
dispatch(someAsyncAction, successAction, failureAction) => Promise
...๋ค๋ฅธ ๋ ์์ ์ค ํ๋๊ฐ ์ ๋ฌ๋ ๋๊น์ง ์ฝ์์ด ํด๊ฒฐ๋์ง ์๋ ๊ฒฝ์ฐ.
๊ทธ๊ฒ์ด ๋ฏธ๋ค์จ์ด ํจํด์ผ๋ก ํ์ฑํ๋ ์ ์๋ ์ข ๋ฅ์ ๊ฒ์ ๋๊น?
๋๋ ์์ ํ ๊ธฐ๋ณธ์์ ๋ฒ์ด๋ ์๊ณ ์ด๋ฏธ ์ด๊ฒ์ ํ ์์๋ ๊ฐ๋จํ ๋ฐฉ๋ฒ์ด ์์ต๋๊น?
๊ฐ์ฌ ํด์.
ํค์ด, ๊ณ ๋ง์!
์ด์์ ์ผ๋ก๋ ๋งค์ฅ ์์ฒด์์ ๋ก๋ฉ์ด ์ด๋ฃจ์ด์ ธ์ผ ํฉ๋๋ค.
Redux๋ Stores๊ฐ ์์ ํ ๋๊ธฐํ๋๋๋ก ํฉ๋๋ค. ๋น์ ์ด ์ค๋ช ํ๋ ๊ฒ์ ๋์ ์ก์ ์์ฑ์์์ ๋ฐ์ํด์ผ ํฉ๋๋ค.
๊ธฐ๋ณธ ์ฝํฌ ๋ฏธ๋ค์จ์ด๋ก๋ ๊ฐ๋ฅํ๋ค๊ณ _์๊ฐ_ํฉ๋๋ค. ์ก์ ์์ฑ์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
export function doSomethingAsync() {
return (dispatch) => {
dispatch({ type: SOMETHING_STARTED });
return requestSomething().then(
(result) => dispatch({ type: SOMETHING_COMPLETED, result }),
(error) => dispatch({ type: SOMETHING_FAILED, error })
);
};
}
์คํ ์ด์์ ์ค์ (์ธ๋ถ์ ์ธ) ์์ ์ ์ฒ๋ฆฌํฉ๋๋ค.
์์ฉ๊ตฌ๋ฅผ ์ ๊ฑฐํ๊ธฐ ์ํด ์ฌ์ฉ์ ์ ์ ๋ฏธ๋ค์จ์ด๋ฅผ ์์ฑํ๋ ๊ฒ๋ ๊ฐ๋ฅํฉ๋๋ค.
์ฒ์ฌ! ๋๋ ๋ด๊ฐ ๋ช ๋ฐฑํ ๊ฒ์ ๊ฐ๊ณผํ๊ณ ์๋ค๊ณ ์๊ฐํ๋ค. ๋๋ _doing_๊ณผ _storing_์ ๋ถ๋ฆฌ๋ฅผ ์ข์ํฉ๋๋ค.
์ด๋ฏธ ์์ฑ๋ ์ํ์ด์ง๋ง ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ฑ์ฅํ๋ ๊ฒ์ ์ง์ผ๋ณด๊ธฐ๋ฅผ ๊ธฐ๋ํฉ๋๋ค. ๊ฑด๋ฐฐ @gaearon!
๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉ์ ์ ์ ๋ฏธ๋ค์จ์ด๋ฅผ ์์ฑํ ์๋ ์์ต๋๋ค.
export default function promiseMiddleware() {
return (next) => (action) => {
const { promise, ...rest } = action;
if (!promise) {
return next(action);
}
next({ ...rest, readyState: 'request' );
return promise.then(
(result) => next({ ...rest, result, readyState: 'success' }),
(error) => next({ ...rest, error, readyState: 'failure' })
);
};
}
๊ธฐ๋ณธ๊ฐ ๋์ ์ฌ์ฉํ์ญ์์ค.
์ด๋ ๊ฒ ํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ๋น๋๊ธฐ ์์ ์์ฑ๊ธฐ๋ฅผ ์์ฑํ ์ ์์ต๋๋ค.
function doSomethingAsync(userId) {
return {
type: SOMETHING,
promise: requestSomething(userId),
userId
};
}
๊ทธ๋ฆฌ๊ณ ๊ทธ๋ค์ด
{ type: SOMETHING, userId: 2, readyState: 'request' }
{ type: SOMETHING, userId: 2, readyState: 'success' }
{ type: SOMETHING, userId: 2, readyState: 'failure' }
์ค, ๊ทธ๊ฒ๋ ์ข๊ตฐ์. ๊ทธ๋ฆฌ๊ณ ์ ๊ฐ ์๋ ์ง๋ฌธ์ ํ ๋ ์ผ๋์ ๋์๋ ๊ฒ๋ณด๋ค ๋ ๋ง์ต๋๋ค. ์์ ๋ด๋ถ์ readyState
๋ฅผ ํ์ธํ๊ธฐ ์ํด if
๋ฅผ ์ถ๊ฐํ๋ ๋๊ฐ๋ก ์ก์
์์์ ์๋ฅผ ์ค์ด๋ ์ ์ถฉ์์ด ๋ง์์ ๋๋์ง ๋ชจ๋ฅด๊ฒ ์ต๋๋ค. ๋ด๊ฐ addtional ๊ฐ์ง ์ ํธ ํ ์๊ฐ _SUCCESS
๋ฐ _FAILURE
๋จ์ง ํผํ
ํผํ๊ธฐ ์ํด ๊ฐ ์์
์ ๋ฒ์ ์ if
, ์์ชฝ case
.
๊ทธ๋๋ ๊ณ ๋ง์.
๋ค, ๊ทธ๊ฒ์ ์ ์ ์ผ๋ก ๊ทํ์ ์ทจํฅ์ ๋ฌ๋ ค ์์ต๋๋ค. types: { request: ..., success: ..., failure: ... }
๋ฅผ ์์
์ผ๋ก ๋ฐ๊พธ๋ ์ ์ฌํ ๋ฒ์ ์ด ์์ ์ ์์ต๋๋ค. ์ด๊ฒ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ฒ ์ดํนํ๋ ๋์ ๋ฏธ๋ค์จ์ด๋ก ๋ง๋๋ ๊ฒ์
๋๋ค. ๋ชจ๋ ์ฌ๋์ ์ด๋ฌํ ํญ๋ชฉ์ ๋ํด ์์ ๋ง์ ์ทจํฅ์ ๊ฐ์ง๊ณ ์์ต๋๋ค.
// Middleware
export default function promiseMiddleware() {
return (next) => (action) => {
const { promise, types, ...rest } = action;
if (!promise) {
return next(action);
}
const [REQUEST, SUCCESS, FAILURE] = types;
next({ ...rest, type: REQUEST });
return promise.then(
(result) => next({ ...rest, result, type: SUCCESS }),
(error) => next({ ...rest, error, type: FAILURE })
);
};
}
// Usage
function doSomethingAsync(userId) {
return {
types: [SOMETHING_REQUEST, SOMETHING_SUCCESS, SOMETHING_FAILURE],
promise: requestSomething(userId),
userId
};
}
์ค, ๊ทธ ์๋ฃจ์
์ด ๋ง์์ ๋ญ๋๋ค. then()
๋ฐ dispatch()
๋ํ ์ถ๊ฐ ํธ์ถ์ ์ ์ํ ์ฒซ ๋ฒ์งธ ์๋ฃจ์
๊ณผ ๊ฐ์ด ์ฌ์ฉํ๋ ๊ฒ๋ณด๋ค ํจ์ฌ ์ข์ต๋๋ค. ๋ฏธ๋ค์จ์ด ๋ง์ธ!
์ด๋ป๊ฒ(๊ทธ๋ฆฌ๊ณ ;-) ์๋ํ๋์ง ์๋ ค์ฃผ์ญ์์ค!
์ฐ๋ฆฌ๋ ์ปค์คํ
๋ฏธ๋ค์จ์ด๋ฅผ ๋ง์ด ํ
์คํธํ์ง ์์์ต๋๋ค.
}
(-1ํฌ์ธํธ ๐)๋ฅผ ๋นผ๋จน์์ง๋ง ๋งค๋ ฅ์ฒ๋ผ ์๋ํ์ต๋๋ค! ์ฒ์์ผ๋ก.
:+1:
@erikras ์๋ฒ์์ ์ฝ์์ด ํด๊ฒฐ๋๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ฉด์ ๊ตฌํํ ๋ฐฉ๋ฒ์ด
์ด๊ฒ์ ๋จ์ง ์์ฌ ์ฝ๋์ด๋ฏ๋ก ์๋ฌด๋ฐ๋ ๋ถ์ฌ๋ฃ์ง ๋ง์ญ์์ค. ํ์ง๋ง ๋ค์๊ณผ ๊ฐ์ด react-router(๋์ API๊ฐ redux๋งํผ ๋น ๋ฅด๊ฒ ๋ณ๊ฒฝ๋จ)๋ฅผ ์ฌ์ฉํ๊ณ ์์ต๋๋ค.
app.get('/my-app', (req, res) => {
Router.run(routes, req.path, (error, initialState) => {
Promise.all(initialState.components
.filter(component => component.fetchData) // only components with a static fetchData()
.map(component => {
// have each component dispatch load actions that return promises
return component.fetchData(redux.dispatch);
})) // Promise.all combines all the promises into one
.then(() => {
// now fetchData() has been run on every component in my route, and the
// promises resolved, so we know the redux state is populated
res.send(generatePage(redux));
});
});
});
๊ทธ๊ฒ ํด๊ฒฐ์ด ๋๋์?
@ ๊ฐ์ฅ
Slack์์ ๋ฌธ์ ๋ฅผ ์ธ์ฉ:
๋๋ ๋ผ์ฐํธ ํธ๋ค๋ฌ๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
static async routerWillRun({dispatch}) { return await dispatch(UserActions.fooBar()); }
์ฌ๊ธฐ์
UserActions.fooBar()
๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.export function fooBar() { return dispatch => { doAsync().then(() => dispatch({type: FOO_BAR})); }; }
๊ทธ๋ฐ ๋ค์ ์๋ฒ ๋ ๋๋ง์์ ๋ค์์ ์ฐ์ถํ๊ณ ์์ต๋๋ค.
yield myHandler.routerWillRun({dispatch: redux.dispatch});
ํ์ง๋ง ์๋ํ์ง ์์ต๋๋ค.
์ฌ๊ธฐ์ ๋ฌธ์ ๋ fooBar
์ ์ค์ฒฉ ๋ฉ์๋์์ ์ค์ ๋ก ์๋ฌด ๊ฒ๋ ๋ฐํํ์ง ์๋๋ค๋ ๊ฒ์
๋๋ค.
์ค๊ดํธ๋ฅผ ์ ๊ฑฐํ๊ฑฐ๋:
export function fooBar() {
return dispatch =>
doAsync().then(() => dispatch({type: FOO_BAR}));
}
๋๋ ๋ช
์์ ์ธ return
๋ฌธ์ ์ถ๊ฐํฉ๋๋ค.
export function fooBar() {
return dispatch => {
return doAsync().then(() => dispatch({type: FOO_BAR}));
};
}
์ด๋ ์ชฝ์ด๋ ์์์ ์ ์ํ ๊ฒ์ฒ๋ผ ์ฌ์ฉ์ ์ง์ promise ๋ฏธ๋ค์จ์ด๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ๋ ์ฌ์ธ ์ ์์ต๋๋ค.
@erikras initialState.components
(Router.run์ ์ฝ๋ฐฑ์์)๋ก ๊ฐ์ง๊ณ ์๋ ๊ฒ์ ๋ํด fetchData ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ๋ง์ง๋ง ์๊ฒฌ๊ณผ ๊ด๋ จํ์ฌ ๊ตฌ์ฑ ์์ ์ฐธ์กฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๊ฐ์ฒด๋ ์ผ์นํ๋ ๊ฒฝ๋ก ํธ๋ค๋ฌ๋ง ๋ฐํํฉ๋๋ค. ์ผ์นํ๋ ๊ฒฝ๋ก ํธ๋ค๋ฌ๊ฐ ์๋ ์ ์๋ ๊ตฌ์ฑ ์์, ์ฆ ํ์ ๊ตฌ์ฑ ์์์ ๋๋ฌํ๋ ๊ฒ์ ๋ํ ๊ทํ์ ์๊ฐ์ ๋ฌด์์
๋๊น? ํ์ง๋ง ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์์ผ ํฉ๋๊น?
์ฌ๊ธฐ ๋ด๊ฐ ๋งํ๋ ๊ฒ์ ์๊ฐ ์์ต๋๋ค
import React from 'react';
import Router from 'react-router';
import {Route, RouteHandler, DefaultRoute} from 'react-router';
//imagine Bar needs some data
const Bar = React.createClass({
render(){
return(
<div>bar</div>);
}
});
const Foo = React.createClass({
render(){
return (
<div>
foo
<Bar/>
</div>);
}
});
const App = React.createClass({
render(){
return (
<div>
<RouteHandler />
</div>
);
}
});
const routes = (
<Route path="/" handler={App} name="App">
<DefaultRoute handler={Foo} name="Foo"/>
</Route>
);
Router.run(routes,'/',function(Root,state){
console.log(state);
});
์ฐ์ถ:
{ path: '/',
action: null,
pathname: '/',
routes:
[ { name: 'App',
path: '/',
paramNames: [],
ignoreScrollBehavior: false,
isDefault: false,
isNotFound: false,
onEnter: undefined,
onLeave: undefined,
handler: [Object],
defaultRoute: [Object],
childRoutes: [Object] },
{ name: 'Foo',
path: '/',
paramNames: [],
ignoreScrollBehavior: false,
isDefault: true,
isNotFound: false,
onEnter: undefined,
onLeave: undefined,
handler: [Object] } ],
params: {},
query: {} }
๋ฃจํธ์ ๋ฐ์ ์ก์ธ์คํ ์ ์์ต๋๋ค.
@erikras ํ์์ ์ ๋๋ค! ๋ด๊ฐ ๊ฐ๊ณ ์ถ์ ๊ธธ์ ๋ฐ๋ก ๊ทธ๋ฐ ๊ธธ์ด๋ค. ๊ณต์ ํด ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค.
@iest ์ผ์นํ๋ ๊ฒฝ๋ก๋ฅผ ๋ฐ๋ณตํ์ฌ ๋ง์ฅ๋์ด ์๋์ ์ธ "๊ฒฝ๋ก๋ฅผ ๋ฐ๋ผ ์ด๋"ํ๊ธฐ๋ฅผ ๋ฐ๋๋๋ค. :-)
@mattybow ์ฌ์ค์
๋๋ค. ๋ก๋ํ๊ธฐ ์ํด ๊ฒฝ๋ก์ ์๋ ๊ตฌ์ฑ ์์๊ฐ _์ ๋ง_ ํ์ํ ๊ฒฝ์ฐ ์ ์ผํ ์ต์
์ React.renderToString()
ํ ๋ฒ ์คํํ๊ณ (๊ฒฐ๊ณผ ๋ฌด์) componentWillMount()
์์ ๋ชจ๋ ๋ก๋๋ฅผ ์ํํ๊ณ ์ด๋ป๊ฒ๋ ์ฝ์์ ์ ์ฅํ์ญ์์ค. ์ด๊ฒ์ react-router
์๋ฒ ์ธก ๋ ๋๋ง์ ์ง์ํ๊ธฐ ์ ์ ์์ฒด ๊ฐ๋ฐํ ๋ผ์ฐํ
์๋ฃจ์
์ผ๋ก ์ํํ ์์
์
๋๋ค. ๋ก๋๋ฅผ ์ํํ๊ธฐ ์ํด ๋น๊ฒฝ๋ก ๊ตฌ์ฑ ์์๊ฐ ํ์ํ ๊ฒ์ ์ค๊ณ ๋ฌธ์ ์ ์ฆ์์ผ ์ ์๋ค๊ณ ์ ์ํฉ๋๋ค. ๋๋ถ๋ถ์ ์ฌ์ฉ ์ฌ๋ก์์ ๊ฒฝ๋ก๋ ๊ตฌ์ฑ ์์์ ํ์ํ ๋ฐ์ดํฐ๋ฅผ ์๊ณ ์์ต๋๋ค.
@erikras
์๋ฃจ์
์ ๋ํ ์ ์ฒด ์์ ๋ฅผ ๋ณผ ์ ์๋ ๊ณต๊ฐ ๋ฆฌํฌ์งํ ๋ฆฌ๊ฐ ์์ต๋๊น?
@transedward ๊ทธ๋ฌ์ผ๋ฉด ์ข๊ฒ ์ง๋ง ์ฌ๊ธฐ์์ ์์ธํ ์ค๋ช ํ๋ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ ์ง๊ธ๊น์ง ๋ด ๋ฌผ๊ฑด์ ์ฌ์ ํ โโ๋งค์ฐ ๋ฏธ์ํฉ๋๋ค. ์ฃ์กํฉ๋๋ค.
๊ณ ๊ธ ๋ํ ์์ ์์ +1
๋๋ ์ด๊ฒ์ด ์ด๋๋ก ๊ฐ๊ณ ์๋์ง ์ข์ํฉ๋๋ค!
@transedward ์ฌ๊ธฐ์ ๋ด๊ฐ ํจ๊ป ๋ง๋ ๋ชจ๋ ์ต์ฒจ๋จ ๊ธฐ์ ์ด ํฌํจ๋ ์ํ ํ๋ก์ ํธ๊ฐ ์์ต๋๋ค. https://github.com/erikras/react-redux-universal-hot-example/
@erikras ๊ต์ฅํฉ๋๋ค! ์ด README ๋ฐ React Hot Loader ๋ฌธ์์ "์คํํฐ ํคํธ" ์น์ ์ ์ถ๊ฐํ๊ธฐ ์ํด PR์ ์ ์ถํ ์ ์์ต๋๊น?
๊ฐ์ฌ ํด์! PR์ด ์ ์ถ๋์์ต๋๋ค.
@erikras ๊ทธ๋ ์ดํธ - ๊ฐ์ฌํฉ๋๋ค!
์ด ๋ํ์ ์ผ๋ถ ์์ด๋์ด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ฝ์์ ์ฒ๋ฆฌํ๋ ๋ฏธ๋ค์จ์ด๋ฅผ ๋ง๋ค์์ต๋๋ค. https://github.com/pburtchaell/redux-promise-middleware.
@pburtchaell๋ฟ๋ง ์๋๋ผ @acdliteํ์ฌ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ์๋ค. https://github.com/acdlite/redux-promise
์ด์ ๋ํ ๋ ๊ฐ์ง ์๊ฐ:
๊ทธ๋ฐ ๋ค์ ํ์ด์ง๋ฅผ ๋ ๋๋งํ ์ค๋น๊ฐ ๋์๋์ง ํ์ธํ๋ ค๋ฉด ๋ชจ๋ ์ฝ์์ด ์๋ฃ๋์๋์ง ํ์ธํ๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค. ์ ๋ฌ๋๋ ๋ชจ๋ ์ฝ์์ ํจ๊ป ์ฐ๊ฒฐํ๊ณ ๋ณด๋ฅ ์ค์ธ ์ฝ์์ด ์์ ๋๋ฅผ ์ํ ์ฝ์์ ์ ๊ณตํ๋ ๋ฏธ๋ค์จ์ด๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋ฉ์์ง 3์ ๋ ๋๋งํ๊ณ ์ถ๋ค๊ณ ๊ฐ์ ํ๋ฉด ๋ฉ์์ง ์ปจํ
์ด๋๋ <Message id={3}>
๋ ๋๋งํ๊ณ ๋ฉ์์ง ์ ํ๊ธฐ๋ state.msgs[3]
๊ฐ ์๋์ง ํ์ธํ๊ณ ์์ผ๋ฉด ๋ฉ์์ง ๋ก๋ฉ ์ฝ์์ ์ ๋ฌํฉ๋๋ค.
๋ฐ๋ผ์ ๋ ๊ฐ์ง๋ฅผ ๊ฒฐํฉํ๋ฉด ๊ตฌ์ฑ ์์๊ฐ ํ์ํ ๋ฐ์ดํฐ๋ฅผ ์๋ ์ ํํ๊ณ ์๋ฃ ์์ ์ ์ ์ ์์ต๋๋ค.
์ ๋ "์ง๋ ฌํํ ์ ์๋ ๊ฒ์ ์คํ ์ด๋ ์ก์ ์ ๋ฃ์ง ๋ง์ญ์์ค"๋ผ๊ณ ํ์ ํฉ๋๋ค. ๊ทธ๊ฒ์ ์ ์๊ฒ ์ ๋ง ์ ์๋ํ๋ ๋ถ๋ณ ์ค ํ๋์ด๋ฉฐ(์๋ฅผ ๋ค์ด ์๊ฐ ์ฌํ์ด ํ์ฉ๋จ) ๋ณ๊ฒฝ์ ๊ณ ๋ คํ _๋งค์ฐ_ ๊ฐ๋ ฅํ ์ด์ ๊ฐ ํ์ํฉ๋๋ค.
๊ทธ๋ฐ ๋ค์ ํ์ด์ง๋ฅผ ๋ ๋๋งํ ์ค๋น๊ฐ ๋์๋์ง ํ์ธํ๋ ค๋ฉด ๋ชจ๋ ์ฝ์์ด ์๋ฃ๋์๋์ง ํ์ธํ๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค. ์ ๋ฌ๋๋ ๋ชจ๋ ์ฝ์์ ํจ๊ป ์ฐ๊ฒฐํ๊ณ ๋ณด๋ฅ ์ค์ธ ์ฝ์์ด ์์ ๋๋ฅผ ์ํ ์ฝ์์ ์ ๊ณตํ๋ ๋ฏธ๋ค์จ์ด๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ด๊ฒ์ ์ค์ ๋ก ๊ฒฐ๊ตญ ์์ ์ ์ฝ์์ ํ ํ์๊ฐ ์์ผ๋ฉฐ ์ด๊ฒ์ด ๋ง์์ ๋ญ๋๋ค. ์ฐจ์ด์ ์ ๋์คํจ์น ์ฒด์ธ์ ๋์์ ์์ ์์ ์๋ ์ฝ์์ด ํฌํจ๋์ด ์์ง ์๋ค๋ ๊ฒ์ ๋๋ค. ๋์ ํด๋น ๋ฏธ๋ค์จ์ด์ ์ํด "์์ง"๋ฉ๋๋ค.
๋ด๊ฐ ํ๋ผ๋ฏธ์ค๋ก ์์ ํ ๋ ์์ฃผ ํ๋ ํ ๊ฐ์ง๋ ํ๋ผ๋ฏธ์ค์ ๋ํ ์ฐธ์กฐ๋ฅผ ์ ์งํ์ฌ ๋์ผํ ๊ฒ์ ๋ํ ๋ค๋ฅธ ์์ฒญ์ด ๋ค์ด์ฌ ๋ ๋จ์ํ ๋์ผํ ํ๋ผ๋ฏธ์ค๋ฅผ ๋ฐํํ์ฌ ๋๋ฐ์ด์ฑ์ ์ ๊ณตํ๋ ๊ฒ์ ๋๋ค. ๊ทธ๋ฐ ๋ค์ ์ฝ์์ด ์๋ฃ๋ ํ ์ผ๋ง ํ ์ฐธ์กฐ๋ฅผ ์ญ์ ํ์ฌ ๊ตฌ์ฑ ๊ฐ๋ฅํ ์บ์ฑ์ ์ ๊ณตํฉ๋๋ค.
Redux์์ ์ด๋ฌํ ์ฐธ์กฐ๋ก ๋ฌด์์ ํด์ผ ํ ์ง ๊ถ๊ธํ๊ธฐ ๋๋ฌธ์ ์ค์ ์ฑ์์ Redux๋ฅผ ์ฌ์ฉํ๊ธฐ ์์ํด์ผ ํฉ๋๋ค. actionCreator๋ฅผ stateless๋ก ๋ง๋ค๊ธฐ ์ํด(๋๋ ์ต์ํ ์ํ๋ฅผ ๋ช ์์ ์ผ๋ก ๋ง๋ค๊ธฐ) ์คํ ์ด์ ์ง์ด๋ฃ๊ณ ์ถ์ต๋๋ค. ์์ ์ ํตํด ์ฝ์์ ์ ๋ฌํ๋ ๊ฒ์ ๋ด๋ณด๋ด๋ ์ข์ ๋ฐฉ๋ฒ์ด์ง๋ง ๋์ค์ ์ด๋ป๊ฒ๋ ๋ค์ ๊ฐ์ ธ์์ผ ํฉ๋๋ค. ํ .
@wmertens ์ ๋ง์ง๋ง ์์ ์ ๋ํ ๋ต๋ณ์ด ์ ๋ง ๊ธฐ๋๋ฉ๋๋ค.
์ฌ๋ฌ ๊ฐ์ ๋์ ํธ์ถ์ ํผํ๋ ๊ฒ(๋๊ธฐ ์ค์ธ ๊ฒฝ์ฐ ์๋ฌด ๊ฒ๋ ํ์ง ์์)์ ์์ฃผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ์ด๋ฉฐ ์ด์ ๋ํ ์ต์ ์ ๋ฐฉ๋ฒ์ด ๋ฌด์์ธ์ง ํ์ ํ ์ ์์ต๋๋ค(actionCreator์์ ์ ์ฅ์์ ์ํ์ ์ก์ธ์คํ ์ ์๊ธฐ ๋๋ฌธ์).
actionCreator ์ฌ์ฉ์(๊ตฌ์ฑ ์์)๊ฐ ํด๋น ์์ ์ ์ ๋ฌํ ์ ์๋์ง ์ฌ๋ถ๋ฅผ ์ํ์์ ๋งค๋ฒ ํ์ธํด์ผ ํฉ๋๊น? ๊ทธ๋ด ๋๋ง๋ค ํด์ผ ํฉ๋๋ค. ์ด ์์ ์ ๋ํํ๋ ๊ณ ์ ํ @connect ์ฃผ์์ ๋์ ํด์ผ ํ ์๋ ์์ต๋๋ค.
actionCreator์์ ์คํ ์ด ์ํ์ ์ก์ธ์คํ ์ ์๊ธฐ ๋๋ฌธ์
์์? ์ฝํฌ ๋ฏธ๋ค์จ์ด ๋ฅผ ์ฌ์ฉํ๋ฉด ์ ํ ์ ์์ต๋๋ค.
function doSomething() {
return { type: 'SOMETHING' };
}
function maybeDoSomething() {
return function (dispatch, getState) {
if (getState().isFetching) {
return;
}
dispatch(doSomething());
};
}
store.dispatch(maybeDoSomething());
๊ทธ๊ฒ์ ๊ทธ๊ฒ์ ํด๊ฒฐํฉ๋๋ค!
๋๋ (์ด์ ์์ด) actionCreator์์ ์ํ์ ์ ๊ทผํ๋ ๊ฒ์ ๋์ ์ต๊ด์ด๋ผ๊ณ ์๊ฐํ์ต๋๋ค^^ ์ก์
์์ฑ์ ํธ์ถ์๊ฐ ์ํ์ ์ ๊ทผํ ์ ์๊ธฐ ๋๋ฌธ์ actionCreator๊ฐ ์ ๊ทผํ์ง ์์์ผ ํ๋ ์ด์ ๋ฅผ ๋ชจ๋ฅด๊ฒ ์ต๋๋ค. :)
@gaearon ๊ฐ์ฌ
@gaearon ์ http://gaearon.github.io/redux/docs/api/applyMiddleware.html ์์ ๋ต๋ณ๋ณด๋ค ์ ํธ๋ฉ๋๋ค.
๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉ์ ์ ์ ๋ฏธ๋ค์จ์ด๋ฅผ ์์ฑํ ์๋ ์์ต๋๋ค.
export default function promiseMiddleware() {
return (next) => (action) => {
const { promise, ...rest } = action;
if (!promise) {
return next(action);
}
next({ ...rest, readyState: 'request' );
return promise.then(
(result) => next({ ...rest, result, readyState: 'success' }),
(error) => next({ ...rest, error, readyState: 'failure' })
);
};
}
๊ธฐ๋ณธ๊ฐ ๋์ ์ฌ์ฉํ์ญ์์ค.
์ด๋ ๊ฒ ํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ๋น๋๊ธฐ ์์ ์์ฑ๊ธฐ๋ฅผ ์์ฑํ ์ ์์ต๋๋ค.
function doSomethingAsync(userId) {
return {
type: SOMETHING,
promise: requestSomething(userId),
userId
};
}
๊ทธ๋ฆฌ๊ณ ๊ทธ๋ค์ด
{ type: SOMETHING, userId: 2, readyState: 'request' }
{ type: SOMETHING, userId: 2, readyState: 'success' }
{ type: SOMETHING, userId: 2, readyState: 'failure' }
๋ํ,
๋๋ ๋ง์ง๋ง ๋ถ๋ถ์ ๋ํด ๋ค์์ ์๋ฏธํ๋ค๊ณ ์๊ฐํฉ๋๋ค.
{ type: SOMETHING, userId: 2, readyState: 'request' }
{ type: SOMETHING, userId: 2, result, readyState: 'success' }
{ type: SOMETHING, userId: 2, error, readyState: 'failure' }
์๋ ์์ฑ์ ์ฌ์ฉํ๋ ๋์ success
๋๋ failure
์ฝ์์ ์ฝ๋ฐฑ์ ๋ํด ๋ณ๋์ ์์
์ ์์ฑํ๋ ค๋์ง ์ฌ๋ถ์ ๋ฌ๋ ค ์๋ค๊ณ ์๊ฐํฉ๋๋ค.
๊ทํ์ ์ฝํฌ ์์์ :
function makeASandwichWithSecretSauce(forPerson) {
// Invert control!
// Return a function that accepts `dispatch` so we can dispatch later.
// Thunk middleware knows how to turn thunk async actions into actions.
return function (dispatch) {
return fetchSecretSauce().then(
sauce => dispatch(makeASandwich(forPerson, sauce)),
error => dispatch(apologize('The Sandwich Shop', forPerson, error))
);
};
}
์์ค๋ฅผ ๊ฐ์ ธ์ค๋ ๋ฐ ๋ค๋ฅธ ์ํฉ์ด ์์ ์ ์์ผ๋ฏ๋ก ๋น๋ฐ ์์ค ๊ฐ์ ธ์ค๊ธฐ ์คํจ์ ๋ํด ์ผ๋ฐ ์ค๋ฅ ์ฝ๋ฐฑ์ ์ฌ์ฉํ๋ ๊ฒ์ด ๋ฐ๋์ ์๋ฏธ๊ฐ ์๋ ๊ฒ์ ์๋๋๋ค.
๋ฐ๋ผ์ ์ฝํฌ ๋ชจ๋ธ์ ์ข ๋ ์ ์ฐํ๊ฒ ๋ณผ ์ ์์ต๋๋ค.
๋ก๊น ๋๋ "๋น๋๊ธฐ ์งํ ์ค ํ์๊ธฐ"์ ํ ๊ธ๊ณผ ๊ฐ์ ๊ฒ์ด ๋ฏธ๋ค์จ์ด์ ๋ ์ ์ ํ ์์ผ ์ ์์ต๋๊น?
@justin808
๋ ๋ค ๊ด์ฐฎ์ต๋๋ค. ๊ทํ์๊ฒ ๋ ์ฅํฉํ ๊ฒ๊ณผ ๊ทํ์ ํ๋ก์ ํธ์ ๋ ํจ๊ณผ์ ์ธ ๊ฒ์ ์ ํํ์ญ์์ค. ๋ด ์ ์์ ์ฝํฌ๋ฅผ ์ฌ์ฉํ์ฌ ์์ํ๊ณ ์ผ๋ถ ํจํด์ด ๋ฐ๋ณต๋๋ ๊ฒฝ์ฐ ์ฌ์ฉ์ ์ง์ ๋ฏธ๋ค์จ์ด๋ก ์ถ์ถํ๋ ๊ฒ์ ๋๋ค. ๋น์ ์ ๋ํ ๊ทธ๋ค์ ํผํฉ ํ ์ ์์ต๋๋ค.
ํธ๋ฆฌ๊ฑฐ๋ ์์ (๋ก๋, ์ฑ๊ณต, ์คํจ)์ ์ํ๋ฅผ ๋ค๋ฅธ ์ํ์ ๋ถ๋ฆฌํ๊ธฐ ์ํด ActionStore๋ฅผ ๋ง๋ค์์ต๋๋ค. ๊ทธ๋ฌ๋ ์ด๊ฒ์ด Redux/Flux์ ๊ธฐ๋ฐ์ ์๋ฐฐ๋๋์ง๋ ๋ชจ๋ฅด๊ฒ ์ต๋๋ค. ๋๋ ์ด๊ฒ์ ๋ํด stackoverflow ์ ๊ฒ์ํ์ต๋๋ค.
@gabrielgiussi ๋ด ์๊ฐ์๋ https://github.com/acdlite/redux-promise ๋ํ ์ํ์ ์ฝ์์ ์ ์ฅํ์ง ์๊ณ ๋ ์ํ๋ ๊ฒ์ ๋ฌ์ฑํ ์ ์๋ค๊ณ ์๊ฐํฉ๋๋ค. ์ํ๋ ํญ์ ์ง๋ ฌํ ๊ฐ๋ฅํด์ผ ํฉ๋๋ค.
@wmertens ์กฐ์ธ ๊ฐ์ฌํฉ๋๋ค. repo๋ฅผ ์ดํด๋ณด๊ฒ ์ง๋ง ๋ด ์ํ๊ฐ ์ง๋ ฌํ๋์ง ์๋ ์ด์ ๋ ๋ฌด์์ ๋๊น? ์๋๋ฉด ์ฐธ๊ณ ์ฉ์ผ๋ก๋ง ๋ง์ํ์๋๊ฑด๊ฐ์?
@gabrielgiussi ์์ธํ ๋ณด์ง๋ ์์์ง๋ง ๋น์ ์ด ์๋ ๊ฒ ๊ฐ์์ต๋๋ค
์์ ์ ์ฝ์์ด๋ ๊ธฐ๋ฅ์ ๋ฃ์ต๋๋ค. ์ด์จ๋ ๊ทธ ํ๋ก์ ํธ๋
๋ํ ์ ์๋ํด์ผ ํ๋ค๊ณ ์๊ฐํฉ๋๋ค.
2015๋ 8์ 10์ผ ์์์ผ 19์ 15๋ถ์ gabrielgiussi [email protected]์์ ๋ค์๊ณผ ๊ฐ์ด ์ผ์ต๋๋ค.
@wmertens https://github.com/wmertens ์กฐ์ธ ๊ฐ์ฌํฉ๋๋ค. ๊ทธ๋ด ๊ฒ์
repo๋ฅผ ์ดํด๋ณด์ง๋ง ๋ด ์ํ๊ฐ ์ง๋ ฌํ๋์ง ์๋ ์ด์ ๋ ๋ฌด์์ ๋๊น? ์๋๋ฉด ๋น์
์ฐธ๊ณ ๋ง ํ๋ผ๊ณ ?โ
์ด ์ด๋ฉ์ผ์ ์ง์ ๋ต์ฅํ๊ฑฐ๋ GitHub์์ ํ์ธํ์ธ์.
https://github.com/gaearon/redux/issues/99#issuecomment -129531103.
์ํธ.
(๋ชจ๋ฐ์ผ๋ก ํ์ดํ, ๊ฐ๊ฒฐํ ๋ณ๋ช
)
์ฌ์ค, ์คํ ์ด์์ ์ปค์คํ Action ๊ฐ์ฒด๋ฅผ ๋ฃ์๋๋ฐ, ๊ทธ๊ฒ๋ค์ ๋จ์ง Immutable.Record์ ๋จ์ํ ์์ฑ(id, state, payload)๊ณผ Promise๋ฅผ ์์ฑํ๊ณ ๋ฐํํ๋ ์ก์ ํธ๋ฆฌ๊ฑฐ๊ฐ ์๋ ๋ ์ฝ๋์ด๋ฏ๋ก ์คํ ์ด์ Promise๋ฅผ ๋์ง ์์ต๋๋ค. ํ์ง๋ง ์๋ง๋ ๋ค๋ฅธ ๊ณณ์์ ๋ฌด์ธ๊ฐ๋ฅผ ๊นจ๊ณ ์๋ ๊ฒ ๊ฐ์ต๋๋ค. @wmertens ๊ฐ์ฌํฉ๋๋ค.
@gabrielgiussi
Promise๋ฅผ ์์ฑํ๊ณ ๋ฐํํ๋ ์ก์ ํธ๋ฆฌ๊ฑฐ
์ง๋ ฌํํ ์ ์๋ ํจ์๋ ๋ค๋ฅธ ๊ฒ์ ์ํ์ ๋ฃ์ง ๋ง์ญ์์ค.
์ฃ์กํฉ๋๋ค. ๋๋ ๋งํ๋ ค๊ณ ๋ ธ๋ ฅํ๋ค
Promise๋ฅผ ์์ฑํ๊ณ ๋ฐํํ๋ ํจ์ ํธ๋ฆฌ๊ฑฐ
๋ด๊ฐ ์ค์ ๋ก ์์ ์ ๋ฃ๋ ๊ฒ์ Action ๊ฐ์ฒด์ ๋๋ค(์ด๋ฆ์ด ์ต๊ณ ๊ฐ ์๋์์ต๋๋ค).
export default class Action extends Immutable.Record({state: 'idle', api: null, type: null, payload: null, id: null}){
load(){
return this.set('state','loading');
}
succeed(){
return this.set('state','succeeded');
}
fail(){
return this.set('state','failed');
}
ended(){
return this.get('state') != 'loading' && this.get('state') != 'idle';
}
endedWithSuccess(){
return this.get('state') == 'succeeded';
}
endedWithFailure(){
return this.get('state') == 'failed';
}
trigger() {
return (dispatch) => {
dispatch({type: this.get('type') + '_START', action: this});
let payload = this.get('payload');
this.get('api').call({dispatch,payload}).then((result) => {
dispatch({type: this.get('type') + '_SUCCESS',id: this.get('id'), result: result.result});
}).catch((result) => {
dispatch({type: this.get('type') + '_FAIL',id: this.get('id'), result: result.result});
});
}
}
}
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ง๋ค์์ต๋๋ค(#539 ์ฐธ์กฐ). ๋ฏธ๋ค์จ์ด๊ฐ ๋ณด๋ฅ ์ค์ธ ์์ ์ ๋ํ ์ฝ์์ ๋ฐํํ๊ณ ๋ชจ๋ ์ฝ์์ด ํด๊ฒฐ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ๋ฉด ์๋ํฉ๋๋ค.
@gaearon ๋น์ ์ด ์์ฑํ ์ด ์ฝ๋๋ https://github.com/rackt/redux/issues/99#issuecomment -112212639,
์ด๊ฒ์ redux ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํฌํจ๋ ๊ฒ์ ๋๊น ์๋๋ฉด ์๋์ผ๋ก ๋ง๋ค์ด์ผ ํ๋ ๊ฒ์ ๋๊น? ์ด๊ฒ์ด ์๋ก์ด ์ง๋ฌธ์ด๋ผ๋ฉด ์ฃ์กํฉ๋๋ค. React / Flux(Redux)์ ๋ํด ์์๋ณด์ญ์์ค. ์ด ํํ ๋ฆฌ์ผ์ ์์ํ์ต๋๋ค. https://github.com/happypoulp/redux-tutorial
@banderson5144
ํฌํจ๋์ด ์์ง ์์ต๋๋ค. ๊ทธ๊ฒ์ ๋จ์ง ๋น์ ์ด ๋ฌด์์ ํ ์ ์๋์ง์ ๋ํ ์์ด๋์ด๋ฅผ ์ ๊ณตํ๊ธฐ ์ํ ๊ฒ์
๋๋ค. ๊ทธ๋ฌ๋ ๋น์ ์ ๊ทธ๊ฒ์ ๋ค๋ฅด๊ฒ ํ ์์ ๊ฐ ์์ต๋๋ค.
๋น์ทํ ๊ฒ์ด https://github.com/pburtchaell/redux-promise-middleware ๋ก ๊ฒ์๋์์ต๋๋ค
์ด ์ ์ฉํ ์ ๋ณด๋ฅผ ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค. ๋๋ ์์ ์ฌ์ค์ ์ ๋ํ ๋น์ ์ ๋๋๋ฅผ ์ ํํ๊ณ ์ถ์์ต๋๋ค -
์ด๋ป๊ฒ ํด๊ฒฐํ์ จ๋์?/์ด๋ป๊ฒ ์์ด๋์ด๊ฐ ์์ผ์ ๊ฐ์? ๊ฐ ์ฌ์ฉ์๋ฅผ ์ํ ์๋ก์ด ์์ ์ด ๋์ ์๋ํ ๊น์?
์๋ฒ ๋ ๋๋ง์ ๋ง์ํ์๋ ๊ฑด๊ฐ์? ๋ชจ๋ ์์ฒญ์ โโ๋ํด ์ ์ ์ฅ์๋ฅผ ๋ง๋ญ๋๋ค. ๋ฌธ์์ ์๋ฒ ๋ ๋๋ง์ ๋ํ ๊ฐ์ด๋๊ฐ ์์ต๋๋ค.
๊ฐ์ฌํฉ๋๋ค ๊ทธ๋ ๊ฒ ํ๊ฒ ์ต๋๋ค
์ดํดํ๋ ค๊ณ ๋ ธ๋ ฅํ ํ ...
๋๋ฌด ์์งํ๊ฐ์? (์๋ฌด๋ ์ด๋ ๊ฒ ํ์ง ์๋ ๊ฒ ๊ฐ์ต๋๋ค. ์ ์๊ฐ์๋)
// server.js
app.use(function (req, res) {
match({โฆ}, function (error, redirectLocation, renderProps) {
โฆ
if (renderProps) {
const store = configureStore();
const promises = renderProps.components.map(function (component, index) {
if (typeof component.fetchData !== 'function') {
return false;
}
return component.fetchData(store.dispatch);
});
Promise.all(promises).then(function () {
res.status(200).send(getMarkup(store, renderProps));
});
}
})
});
// home.js
export class Home extends Component {
static fetchData() {
return Promise.all([
dispatch(asyncAction);
]);
},
componentDidMount() {
const { dispatch } = this.props;
Home.fetchData(dispatch);
}
}
export default connect()(Home);
// action.js
export function asyncAction() {
return (dispatch, getState) => {
dispatch(request);
return fetch(โฆ)
.then(response => response.json())
.then(data => dispatch(requestSuccess(data)))
;
}
}
๋๋ ๋ํ @mattybow ์ ์ง๋ฌธ https://github.com/rackt/redux/issues/99#issuecomment -112980776(๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ๋ฅผ ๊ด๋ฆฌํ๋ ์ค์ฒฉ ๊ตฌ์ฑ ์์)์ ๋ํ ์๋ฃจ์
์ ์ฐพ์ผ๋ ค๊ณ ๋
ธ๋ ฅํ์ง๋ง ๊ทธ๋ฌํ ์ฑ๊ณต์ ์์์ต๋๋ค(๊ทธ๋ ์ง ์์์ต๋๋ค). componentWillMount
์์ ์ฝ์์ ์์งํ๋ ๋ฐฉ๋ฒ์ ๋ํด ํ์ ํฉ๋๋ค.
@chemoish ๋๋ ๋ํ ๋ฐ์ ๋ฐ redux๋ฅผ ์ฌ์ฉํ์ฌ ์๋ฒ ์ธก ๋ ๋๋ง์ ๋ํด ๋จธ๋ฆฌ๋ฅผ ์ฐ๋ ค๊ณ ๋ ธ๋ ฅํ๊ณ ์์ต๋๋ค. ๋ฌธ์์ ์์ ๋ ์ด ์ฌ์ฉ ์ฌ๋ก๋ฅผ ์ ๋ค๋ฃจ์ง ์์ต๋๋ค. ์๋ฒ์ ๋ชจ๋ API ์์ฒญ์ ๋ค์ ์ง์ ํ๊ณ ๊ตฌ์ฑ ์์์ ์ฐ๊ฒฐํ๊ณ ์ถ์ง ์์ต๋๋ค. ๊ตฌ์ฑ ์์๋ ํ์ํ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๋ฐฉ๋ฒ๋ง ์ง์ ํด์ผ ํฉ๋๋ค(๊ทธ๋ฐ ๋ค์ ์๋ฒ์์ ์ ํํด์ผ ํจ).
๊ทํ์ ์๋ฃจ์ ์ ์ด๋ฅผ ๋ฌ์ฑํ๊ธฐ์ ์์ฃผ ์ข์ ๋ณด์ ๋๋ค. ์ด๊ฒ์ด ๋น์ ์ ์ํด ์ผํ์ต๋๊น? ๊ฐ์ฌ ํด์
ํธ์ง: "componentDidMount"๊ฐ ์๋ฒ์์ ๋ ๋๋ง๋ ๋ ํด๋ผ์ด์ธํธ์์ ๋ค์ ํธ๋ฆฌ๊ฑฐ๋์ง ์๋๋ค๋ ๊ฒ์ด ๋ง์ต๋๊น?
@ms88privat ์์ง ์๋ฃจ์ ์ ๋ํ ํผ๋๋ฐฑ์ ๋ง์ด ๋ฐ์ง ๋ชปํ๊ณ ํ๊ณ๋ฅผ ํ ์คํธํ์ง๋ ์์์ต๋๋ค.
๊ทธ๋ฌ๋ ์์ ์ ์๋ ์๋ฃจ์ ์ ๊ฐ ํ์ด์ง๊ฐ ๋ชจ๋ ํ์ ๊ตฌ์ฑ ์์์ ๋ํ ๋ฐ์ดํฐ๋ฅผ ์์์ผ ํฉ๋๋ค. ์ค์ฒฉ๋ ๊ตฌ์ฑ ์์๊ฐ ๋ฐ์ดํฐ ๊ด๋ฆฌ ์์ฒด์ ๋ํด ๊ฑฑ์ ํ๋ ๊ฒ์ ๋ํด ๋ ๊น์ด ํ๊ณ ๋ค์ง ์์์ต๋๋ค(์ค์ฒฉ๋ ์ฝ์ ์์ง์ผ๋ก ์ธํด).
๋น์ ์ด ๊ธฐ๋ํ๋ ๋๋ก ํ๊ณ ์๋ ๊ฒ ๊ฐ์ผ๋, ์ง๊ธ์ผ๋ก์๋ ๊ทธ๊ฒ์ผ๋ก ์ถฉ๋ถํฉ๋๋ค.
componentDidMount
๊ฐ ๋ค์ ํธ๋ฆฌ๊ฑฐ๋ฉ๋๋ค(https://facebook.github.io/react/docs/component-specs.html#mounting-componentdidmount ์ฐธ์กฐ). ์ด ๋ฐฉ๋ฒ ๋๋ ํ์์ ๋ง๋ ๋ค๋ฅธ ์๋ช
์ฃผ๊ธฐ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์์ ์ด ์ด๋ฏธ ๊ฐ๋ ์ฐฌ ๊ฒฝ์ฐ(๋๋ ์ ํฉํ ๋น์ฆ๋์ค ๋ก์ง์ด ๋ฌด์์ด๋ ) fetch
์ฝ๋๊ฐ ์คํ๋์ง ์๋๋ก ํ์ฌ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํฉ๋๋ค.
๋ด๊ฐ ๋งํ๋ ๋ด์ฉ์ ๋ํ ์์ด๋์ด๋ https://github.com/reactjs/redux/blob/master/examples/async/actions/index.js#L47 ์ ์ดํด๋ณด์ญ์์ค.
@chemoish
์์ ์ด ์ด๋ฏธ ๊ฐ๋ ์ฐฌ ๊ฒฝ์ฐ ๊ฐ์ ธ์ค๊ธฐ ์ฝ๋๊ฐ ์คํ๋๋ ๊ฒ์ ๋ฐฉ์งํ์ฌ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํฉ๋๋ค.
์๊ฒ ์ต๋๋ค. ๊ฐ์ฌ ํด์.
๊ทธ๋ฌ๋ ์์ ์ ์๋ ์๋ฃจ์ ์ ๊ฐ ํ์ด์ง๊ฐ ๋ชจ๋ ํ์ ๊ตฌ์ฑ ์์์ ๋ํ ๋ฐ์ดํฐ๋ฅผ ์์์ผ ํฉ๋๋ค.
์ด์ฉ๋ฉด ๋ด๊ฐ ๋น์ ์ ์๋ฃจ์ ์ ์๋ชป ์ฝ์์ ์๋ ์์ง๋ง ์ด๊ฒ์ ์๋ฒ ์ธก ๋ ๋๋ง์ ๊ด๊ณ์์ด ํ์ํ ์๊ตฌ ์ฌํญ์ด ์๋๋๊น? (์: SPA์ธ ๊ฒฝ์ฐ์๋ ํ์ฌ ๊ฒฝ๋ก์์ ์๋ก ๊ณ ์นจํ๋ฉด ๋์ผํ ์ํ๋ฅผ ๋ ๋๋งํด์ผ ํจ)
๊ทธ๋ด ์๋ ์์ง๋ง ์ด๋ค ์ด์ ๋ก๋ ์ค์ฒฉ๋ ๊ตฌ์ฑ ์์๊ฐ ์์ฒด ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ๋ฅผ ๊ด๋ฆฌํ๊ธฐ๋ฅผ ์ํ ์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด ์ฌ๋ฌ ํ์ด์ง์์ ๋ฐ๋ณต๋๋ ๊ตฌ์ฑ ์์์ด์ง๋ง ๊ฐ ํ์ด์ง์๋ ๋ง์ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ๊ฐ ํ์ํ์ง ์์ต๋๋ค.
@chemoish ๊ฐ์ ํ์ด์ง์ ์๋์ง ์ ๋ชจ๋ฅด๊ฒ ์ต๋๋ค. ์ ๊ด์ ์ด ๋ฌด์์ธ์ง ์ค๋ช ํ๋ ค๊ณ ํฉ๋๋ค.
์๋ฅผ ๋ค์ด ์ธ ๊ฐ์ ์ค์ฒฉ ๊ตฌ์ฑ ์์๊ฐ ์์ต๋๋ค.
๊ทธ๋ค ๊ฐ๊ฐ์ ๊ณ ์ ํ dataFetching ์ ์ธ(์ ์ dataFetching ๋ฉ์๋๋ฅผ ํตํ ๋์คํจ์นญ ์์ )๊ณผ ํจ๊ป ๊ณ ์ ํ "componentDidMount" ๋ฉ์๋๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค.
๋ด๊ฐ ๋จ์ ์ธก ๋ ๋๋ง์ํ์ง ์์๋ ๋ด๊ฐ ํ์ฌ URL์ ์๋ก ๊ณ ์น๋ฉด ๋ด ๊ตฌ์ฑ ์์๋ฅผ ํ์ฌํ๊ณ ์ดํ์ ํ์ํ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ๋ก๋ํ๋ ๋ฐ ํ์ํ ๋ชจ๋ ์กฐ์น๋ฅผ ํธ๋ฆฌ๊ฑฐํฉ๋๋ค.
์๋ฒ ์ธก ๋ ๋๋ง์ ์ฌ์ฉํ๋ฉด match
ํจ์์ renderProps
๊ฐ ์ธ ๊ฐ์ง ๊ตฌ์ฑ ์์๋ฅผ ๋ชจ๋ ์ถ์ถํ๋ฏ๋ก ๋ชจ๋ ์ ์ dataFetching ๋ฉ์๋์ ์ก์ธ์คํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ฉด ํ์ํ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค. ์ด๊ธฐ ์๋ฒ ์ธก ๋ ๋๋ง?
์ ๊ณต๋ ์์์ match function
๋ํ ์ฐธ์กฐ๊ฐ ์์ต๋๊น? ๊ณ ๋ง์.
@ms88privat renderProps.components
๋ ๋ผ์ฐํฐ ๊ตฌ์ฑ ์์์ ๋ฐฐ์ด์ด๋ฉฐ, ๊ทธ ์ด์์ ๋์ง ์์ต๋๋ค. @chemoish ๋ ๊ทธ์ ๊ตฌํ์ผ๋ก ๋ ๊น์ ๊ตฌ์ฑ ์์์ ๋ํ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ์๊ตฌ ์ฌํญ์ ์ค๋ช
ํ ์ ์์์ ์๋ฏธํ์ต๋๋ค.
@DominicTobias thx, ์ด ๋ฌธ์ ์ ๋ํ ํด๊ฒฐ์ฑ ์ด ์์ต๋๊น? ๋ชจ๋ ์ค์ฒฉ ๊ตฌ์ฑ ์์๋ฅผ ๊ฐ์ ธ์ฌ ๊ฐ๋ฅ์ฑ์ด ์์ต๋๊น?
์๋ง๋ ์ด๊ฒ์ด ๋์์ด ๋ ์ ์์ต๋๊น? https://github.com/gaearon/react-side-effect
์ค์ฒฉ ์์์์ ๋ชจ๋ ๋ฉํ ํ๊ทธ๋ฅผ ์์งํ๋ ๋ฐ ์ฌ์ฉ: https://github.com/nfl/react-helmet
์ด ํ ๋ก ์ ๋ค์ ์์ํด์ ์ฃ์กํ์ง๋ง ์ต๊ทผ์ ๋น๋๊ธฐ ์์ ์ผ๋ก ์ํ๋ฅผ ๋ฏธ๋ฆฌ ์ฑ์ฐ๋ ๋์ผํ ๋ฌธ์ ์ ๋ถ๋ช์ณค์ต๋๋ค.
@erikras๊ฐ ์์ฉ๊ตฌ ํ๋ก์ ํธ๋ฅผ redux-async-connect ๋ก ์ฎ๊ฒผ์์ ์ ์ ์์ต๋๋ค . ๋๊ตฐ๊ฐ ๋ค๋ฅธ ํด๊ฒฐ์ฑ ์ ์ฐพ์๋์ง ๊ถ๊ธํฉ๋๋ค.
@vtambourine ์ ๋ https://github.com/markdalgleish/redial ์ ๋ณด๊ณ ์์์ต๋๋ค. ๊ฝค ๋์์ด ๋ฉ๋๋ค.
์, ์ดํด๋ณด์์ต๋๋ค. ํ์ง๋ง ๋ฐ์ดํฐ๋ฅผ ํ์ธํ๋ ๋ฐฉ๋ฒ์ ์์ง ๋ชปํ์ต๋๋ค.
ํํฌ ๊ฐ์ ธ์ค๊ธฐ๋ ์ฝ๋๋ฅผ n์ผ๋ก ์ฌ์ด๊ธฐํํ ํ ๋ ๋ฒ์งธ๋ก ์คํ๋์ง ์์ต๋๋ค.
๊ณ ๊ฐ.
On ะั, 18 ะผะฐััะฐ 2016 ะณ. 22:54์์ Sean Matheson [email protected]
์ผ๋ค:
@vtambourine https://github.com/vtambourine ๋ด๊ฐ ๋ณด๊ณ ์๋
๊ฝค ๋์์ด ๋๋ https://github.com/markdalgleish/redialโ
๋น์ ์ด ์ธ๊ธ๋์๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ ๋ฐ๋ ๊ฒ์ ๋๋ค.
์ด ์ด๋ฉ์ผ์ ์ง์ ๋ต์ฅํ๊ฑฐ๋ GitHub์์ ํ์ธํ์ธ์.
https://github.com/reactjs/redux/issues/99#issuecomment -198517067
๋ํ ๋๊ตฐ๊ฐ๊ฐ ์ด ๋ฌธ์ ์ ๋ํ ์์ ์ ์ธ ์๋ฃจ์ ์ ์ฐพ์๋์ง ๊ถ๊ธํฉ๋๋ค. @erikras ์ ์์ฉ๊ตฌ๋ฅผ ์ข์ํ์ง๋ง @vtambourine์ด ์ธ๊ธํ๋ฏ์ด ์์ ์ ์ธ ์ฅ๊ธฐ ์๋ฃจ์ ์ด ์๋ ๊ฒ์ฒ๋ผ ๋ณด์ด๋ redux-async-connect๋ก ์ด๋ํ์ต๋๋ค. #81 redux-async-connect๊ฐ ์ฃฝ์์ต๋๊น? .
@vtambourine https://github.com/makeomatic/redux-connect ์์ ์ฌ์ฉํ ์ ์๋ ํฌํฌ๊ฐ ์์ผ๋ฉฐ ์ ๊ด๋ฆฌ๋์ด ์์ต๋๋ค. ์ฝ๊ฐ์ ๋ณ๊ฒฝ ์ฌํญ์ด ์๋ ์ ์ฌํ API๊ฐ ์์ต๋๋ค. ๊ด์ฌ ์๋ ๊ฒฝ์ฐ ํ์ธํ์ญ์์ค.
@gaearon์ด ์ธ๊ธํ ๋ฏธ๋ค์จ์ด๊ฐ ์๋ redux ์๋ฃจ์ ์ ๊ด์ฌ์ด ์๋ ์ฌ๋๋ค์ ์ํด ์ด ๊ธฐ์ ์ ๊ตฌํํ๊ณ ๊ตฌ์ฑ ์์ ์์ฒด๊ฐ ์๋ฒ ์ธก์์ ํ์ํ ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ ์ ์๋๋ก ํ๋ ์์ ํ๋ก์ ํธ๊ฐ ์์ต๋๋ค.
https://github.com/peter-mouland/react-lego-2016#redux -with-promise-middleware
์ด ์ ๊ทผ ๋ฐฉ์์ผ๋ก ์์ ์์ฑ์๋ฅผ ๋จ์ ํ ์คํธํ๋ ๋ฐฉ๋ฒ์ ๋ฌด์์ ๋๊น?
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ