๋ก๊ทธ์ธ ์ฑ๊ณต / ์ค๋ฅ ํ๋ฆ์ ๋ง๋ค๋ ค๊ณ ํ์ง๋ง ๋ด ์ฃผ์ ๊ด์ฌ์ฌ๋์ด ๋ ผ๋ฆฌ๋ฅผ ๋ฃ์ ์์๋ ์์น์ ๋๋ค.
ํ์ฌ ์ ๋ actions -> reducer (switch case with action calling API) -> success/error on response triggering another action
์์ต๋๋ค.
์ด ์ ๊ทผ ๋ฐฉ์์ ๋ฌธ์ ์ ์ API ํธ์ถ์์ ์์ ์ ํธ์ถ ํ ๋ ๊ฐ์๊ธฐ๊ฐ ์๋ํ์ง ์๋๋ค๋ ๊ฒ์ ๋๋ค.
๋ด๊ฐ ๋ญ๊ฐ๋ฅผ ๋์น๊ณ ์์ต๋๊น?
๊ฐ์๊ธฐ
import { LOGIN_ATTEMPT, LOGGED_FAILED, LOGGED_SUCCESSFULLY } from '../constants/LoginActionTypes';
import Immutable from 'immutable';
import LoginApiCall from '../utils/login-request';
const initialState = new Immutable.Map({
email: '',
password: '',
}).asMutable();
export default function user(state = initialState, action) {
switch (action.type) {
case LOGIN_ATTEMPT:
console.log(action.user);
LoginApiCall.login(action.user);
return state;
case LOGGED_FAILED:
console.log('failed from reducer');
return state;
case LOGGED_SUCCESSFULLY:
console.log('success', action);
console.log('success from reducer');
break;
default:
return state;
}
}
ํ์
import { LOGIN_ATTEMPT, LOGGED_FAILED, LOGGED_SUCCESSFULLY } from '../constants/LoginActionTypes';
export function loginError(error) {
return dispatch => {
dispatch({ error, type: LOGGED_FAILED });
};
}
/*
* Should add the route like parameter in this method
*/
export function loginSuccess(response) {
return dispatch => {
dispatch({ response, type: LOGGED_SUCCESSFULLY });
// router.transitionTo('/dashboard'); // will fire CHANGE_ROUTE in its change handler
};
}
export function loginRequest(email, password) {
const user = {email: email, password: password};
return dispatch => {
dispatch({ user, type: LOGIN_ATTEMPT });
};
}
API ํธ์ถ
// Use there fetch polyfill
// The main idea is create a helper in order to handle success/error status
import * as LoginActions from '../actions/LoginActions';
const LoginApiCall = {
login(userData) {
fetch('http://localhost/login', {
method: 'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: userData.email,
password: userData.password,
}),
})
.then(response => {
if (response.status >= 200 && response.status < 300) {
console.log(response);
LoginActions.loginSuccess(response);
} else {
const error = new Error(response.statusText);
error.response = response;
LoginActions.loginError();
throw error;
}
})
.catch(error => { console.log('request failed', error); });
},
};
export default LoginApiCall;
์ด๊ฒ์ ๊ฑฐ์ ๋ง์ง๋ง ๋ฌธ์ ๋ _ ์์ํ ์ก์ ์ ์์๋ฅผ ๋ถ๋ฌ์ ์ผ์ด ์ผ์ด๋ ๊ฒ์ด๋ผ๊ณ ๊ธฐ๋ํ ์ ์๋ค๋ ๊ฒ์ ๋๋ค. ์ก์ ์์ฑ์๋ _what_์ด ๋ฐ์ก๋์ด์ผ ํจ์ ์ง์ ํ๋ ํจ์์ผ๋ฟ์์ ์์ง ๋ง์ญ์์ค.
// CounterActions
export function increment() {
return { type: INCREMENT }
}
// Some other file
import { increment } from './CounterActions';
store.dispatch(increment()); <--- This will work assuming you have a reference to the Store
increment(); <---- THIS DOESN'T DO ANYTHING! You're just calling your function and ignoring result.
// SomeComponent
import { increment } from './CounterActions';
@connect(state => state.counter) // will inject store's dispatch into props
class SomeComponent {
render() {
return <OtherComponent {...bindActionCreators(CounterActions, this.props.dispatch)} />
}
}
// OtherComponent
class OtherComponent {
handleClick() {
// this is correct:
this.props.increment(); // <---- it was bound to dispatch in SomeComponent
// THIS DOESN'T DO ANYTHING:
CounterActions.increment(); // <---- it's just your functions as is! it's not bound to the Store.
}
}
์ด์ ์๋ฅผ ๋ค์ด ๋ณด๊ฒ ์ต๋๋ค. ๊ฐ์ฅ ๋จผ์ ๋ช
ํํํ๊ณ ์ถ์ ๊ฒ์ ๋น๋๊ธฐ์ dispatch => {}
์์์ด ํ์ํ์ง ์๋ค๋ ๊ฒ์
๋๋ค. ๋จ ํ๋์ ์์
์ ๋ ๊ธฐ์ ์ผ๋ก ์ ๋ฌํ๊ณ ๋ถ์์ฉ์ด์๋ ๊ฒฝ์ฐ ( loginError
๋ฐ loginRequest
๊ฒฝ์ฐ true)
์ด:
import { LOGIN_ATTEMPT, LOGGED_FAILED, LOGGED_SUCCESSFULLY } from '../constants/LoginActionTypes';
export function loginError(error) {
return dispatch => {
dispatch({ error, type: LOGGED_FAILED });
};
}
export function loginSuccess(response) {
return dispatch => {
dispatch({ response, type: LOGGED_SUCCESSFULLY });
// router.transitionTo('/dashboard');
};
}
export function loginRequest(email, password) {
const user = {email: email, password: password};
return dispatch => {
dispatch({ user, type: LOGIN_ATTEMPT });
};
}
๋ค์๊ณผ ๊ฐ์ด ๋จ์ํ ํ ์ ์์ต๋๋ค.
import { LOGIN_ATTEMPT, LOGGED_FAILED, LOGGED_SUCCESSFULLY } from '../constants/LoginActionTypes';
export function loginError(error) {
return { error, type: LOGGED_FAILED };
}
// You'll have a side effect here so (dispatch) => {} form is a good idea
export function loginSuccess(response) {
return dispatch => {
dispatch({ response, type: LOGGED_SUCCESSFULLY });
// router.transitionTo('/dashboard');
};
}
export function loginRequest(email, password) {
const user = {email: email, password: password};
return { user, type: LOGIN_ATTEMPT };
}
๋์งธ, ๊ฐ์๊ธฐ๋ _ ๋ถ์์ฉ์ด์๋ ์์ํ ๊ธฐ๋ฅ _์ด์ด์ผํฉ๋๋ค. ๊ฐ์๊ธฐ์์ API๋ฅผ ํธ์ถํ์ง ๋ง์ญ์์ค.
์ด:
const initialState = new Immutable.Map({
email: '',
password: '',
isLoggingIn: false,
isLoggedIn: false,
error: null
}).asMutable(); // <---------------------- why asMutable?
export default function user(state = initialState, action) {
switch (action.type) {
case LOGIN_ATTEMPT:
console.log(action.user);
LoginApiCall.login(action.user); // <------------------------ no side effects in reducers! :-(
return state;
case LOGGED_FAILED:
console.log('failed from reducer');
return state;
case LOGGED_SUCCESSFULLY:
console.log('success', action);
console.log('success from reducer');
break;
default:
return state;
}
์๋ง๋ ๋ ๋น์ทํ๊ฒ ๋ณด์ผ ๊ฒ์ ๋๋ค
const initialState = new Immutable.Map({
email: '',
password: '',
isLoggingIn: false,
isLoggedIn: false,
error: null
});
export default function user(state = initialState, action) {
switch (action.type) {
case LOGIN_ATTEMPT:
return state.merge({
isLoggingIn: true,
isLoggedIn: false,
email: action.email,
password: action.password // Note you shouldn't store user's password in real apps
});
case LOGGED_FAILED:
return state.merge({
error: action.error,
isLoggingIn: false,
isLoggedIn: false
});
case LOGGED_SUCCESSFULLY:
return state.merge({
error: null,
isLoggingIn: false,
isLoggedIn: true
});
break;
default:
return state;
}
๋ง์ง๋ง์ผ๋ก ๋ก๊ทธ์ธ API ํธ์ถ์ ์ด๋์ ๋ฃ์ต๋๊น?
์ด๊ฒ์ด ๋ฐ๋ก dispatch => {}
์ก์
ํฌ๋ฆฌ์์ดํฐ์ ๋ชฉ์ ์
๋๋ค. ๋ถ์์ฉ!
๋ ๋ค๋ฅธ ์ก์ ํฌ๋ฆฌ์์ดํฐ ์ผ๋ฟ์ ๋๋ค. ๋ค๋ฅธ ์์ ๊ณผ ํจ๊ป ์ฌ์ฉํ์ญ์์ค.
import { LOGIN_ATTEMPT, LOGGED_FAILED, LOGGED_SUCCESSFULLY } from '../constants/LoginActionTypes';
export function loginError(error) {
return { error, type: LOGGED_FAILED };
}
export function loginSuccess(response) {
return dispatch => {
dispatch({ response, type: LOGGED_SUCCESSFULLY });
router.transitionTo('/dashboard');
};
}
export function loginRequest(email, password) {
const user = {email: email, password: password};
return { user, type: LOGIN_ATTEMPT };
}
export function login(userData) {
return dispatch =>
fetch('http://localhost/login', {
method: 'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: userData.email,
password: userData.password,
}),
})
.then(response => {
if (response.status >= 200 && response.status < 300) {
console.log(response);
dispatch(loginSuccess(response));
} else {
const error = new Error(response.statusText);
error.response = response;
dispatch(loginError(error));
throw error;
}
})
.catch(error => { console.log('request failed', error); });
}
๊ตฌ์ฑ ์์์์
this.props.login(); // assuming it was bound with bindActionCreators before
// --or--
this.props.dispatch(login()); // assuming you only have dispatch from Connector
๋ง์ง๋ง์ผ๋ก, ์ด์ ๊ฐ์ ๋๊ท๋ชจ ์ก์ ์์ฑ์๋ฅผ ์์ฃผ ์์ฑํ๋ ๊ฒฝ์ฐ, ๋น๋๊ธฐ์ ์ฌ์ฉํ๋ ์ฝ์๊ณผ ํธํ๋๋ ๋น๋๊ธฐ ํธ์ถ์์ํ ์ฌ์ฉ์ ์ง์ ๋ฏธ๋ค์จ์ด ๋ฅผ ์์ฑํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
์์์ ์ค๋ช
ํ ๊ธฐ์ ( dispatch => {}
์๋ช
์ด์๋ ์ก์
์์ฑ์)์ ํ์ฌ Redux์ ํฌํจ๋์ด ์์ง๋ง 1.0์์๋ redux-thunk ๋ผ๋ ๋ณ๋์ ํจํค์ง๋ก๋ง ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋น์ ์ด ๊ทธ๊ฒ์์๋ ๋์ ๋น์ ์ redux-promise-middleware ๋๋ redux-promise๋ฅผ ํ์ธํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
@gaearon : ๋ฐ์ : ๋๋ผ์ด ์ค๋ช ์ด์์ต๋๋ค! ;) ํ์คํ ๋ฌธ์๋ก ๋ง๋ค์ด์ผํฉ๋๋ค.
@gaearon ๊ต์ฅํ ์ค๋ช ! :ํธ๋กํผ:
@gaearon ์ด๋ค API ํธ์ถ์ ํธ์ถํด์ผํ๋์ง ๊ฒฐ์ ํ๊ธฐ ์ํด ๋ก์ง์ ์ํํด์ผํ๋ ๊ฒฝ์ฐ ์ด๋ป๊ฒํด์ผํฉ๋๊น? ํ๊ณณ์ ์์ด์ผํ๋ ๋๋ฉ์ธ ๋ก์ง์ด ์๋๊ฐ? In Action ์ ์์๋ฅผ ์ ์งํ๋ ๊ฒ์ ์ง์ค์ ๋จ์ผ ์์ค๋ฅผ ๊นจ๋ ๊ฒ์ฒ๋ผ ๋ค๋ฆฝ๋๋ค. ๊ฒ๋ค๊ฐ, ๋๋ถ๋ถ์ ์ ํ๋ฆฌ์ผ์ด์ ์ํ์ ๊ฐ์ผ๋ก API ํธ์ถ์ ๋งค๊ฐ ๋ณ์ํํด์ผํฉ๋๋ค. ์ด๋ป๊ฒ ๋ ๋ ผ๋ฆฌ๋ฅผ ํ ์คํธํ๊ณ ์ถ์ ๊ฐ๋ฅ์ฑ์ด ํฝ๋๋ค. ๋ฆฌ๋์ (์์ ํ๋ญ์ค)์์ API ํธ์ถ์ ๋ง๋๋ ๊ฒ์ ๋๊ท๋ชจ ํ๋ก์ ํธ์์ ๋งค์ฐ ์ ์ฉํ๊ณ ํ ์คํธ ํ ์ ์์์ ๋ฐ๊ฒฌํ์ต๋๋ค.
๋ฆฌ๋์ (์์ ํ๋ญ์ค)์์ API ํธ์ถ์ ๋ง๋๋ ๊ฒ์ ๋๊ท๋ชจ ํ๋ก์ ํธ์์ ๋งค์ฐ ์ ์ฉํ๊ณ ํ ์คํธ ํ ์ ์์์ ๋ฐ๊ฒฌํ์ต๋๋ค.
์ด๋ก ์ธํด ๊ธฐ๋ก / ์ฌ์์ด ์ค๋จ๋ฉ๋๋ค. ๋ถ์์ฉ์ด์๋ ํจ์๋ ์ ์์ ์์ ํจ์๋ณด๋ค ํ ์คํธํ๊ธฐ๊ฐ ๋ ์ด๋ ต์ต๋๋ค. Redux๋ฅผ ์ด์ ๊ฐ์ด ์ฌ์ฉํ ์ ์์ง๋ง ๋์์ธ์ ์์ ํ ๋ฐ๋๋ฉ๋๋ค. :-)
In Action ์ ์์๋ฅผ ์ ์งํ๋ ๊ฒ์ ์ง์ค์ ๋จ์ผ ์์ค๋ฅผ ๊นจ๋ ๊ฒ์ฒ๋ผ ๋ค๋ฆฝ๋๋ค.
"๋จ์ผ ์ง์ค ์์ค"๋ ๋ฐ์ดํฐ ๊ฐ ํ ๊ณณ์ ์กด์ฌํ๊ณ ๋ ๋ฆฝ์ ์ธ ์ฌ๋ณธ์ด ์์์ ์๋ฏธ
ํธ์ถํด์ผํ๋ API ํธ์ถ์ ๊ฒฐ์ ํ๊ธฐ ์ํด ๋ช ๊ฐ์ง ๋ ผ๋ฆฌ๋ฅผ ์ํํด์ผํ๋ ๊ฒฝ์ฐ ์ด๋ป๊ฒํด์ผํฉ๋๊น? ํ๊ณณ์ ์์ด์ผํ๋ ๋๋ฉ์ธ ๋ก์ง์ด ์๋๊ฐ?
๋ฆฌ๋์๋ ๋์์ ์ํด ์ํ๊ฐ ์ด๋ป๊ฒ ๋ณํ๋๋์ง ์ง์ ํฉ๋๋ค. ๊ทธ๋ค์ ์ด๋ฌํ ํ๋์ด ์ด๋์ ์์๋์๋์ง์ ๋ํด ๊ฑฑ์ ํ ํ์๊ฐ ์์ต๋๋ค. ๊ตฌ์ฑ ์์, ์ก์ ์ ์์, ๊ธฐ๋ก ๋ ์ฐ์ ์ธ์ ๋ฑ์์ ์ฌ ์ ์์ต๋๋ค. ์ด๊ฒ์ด ์ก์ ์ฌ์ฉ ๊ฐ๋ ์ ์๋ฆ๋ค์์ ๋๋ค.
๋ชจ๋ API ํธ์ถ (๋๋ ํธ์ถ๋๋ API๋ฅผ ๊ฒฐ์ ํ๋ ๋ก์ง)์ ๋ฆฌ๋์๋ณด๋ค ๋จผ์ ๋ฐ์ํฉ๋๋ค. ์ด๊ฒ์ด Redux๊ฐ ๋ฏธ๋ค์จ์ด๋ฅผ ์ง์ํ๋ ์ด์ ์ ๋๋ค. ์์์ ์ค๋ช ํ Thunk ๋ฏธ๋ค์จ์ด๋ฅผ ์ฌ์ฉํ๋ฉด ์กฐ๊ฑด๋ฌธ์ ์ฌ์ฉํ๊ณ ์ํ์์ ์ฝ์ ์๋ ์์ต๋๋ค.
// Simple pure action creator
function loginFailure(error) {
return { type: LOGIN_FAILURE, error };
}
// Another simple pure action creator
function loginSuccess(userId) {
return { type: LOGIN_SUCCESS, userId };
}
// Another simple pure action creator
function logout() {
return { type: LOGOUT };
}
// Side effect: uses thunk middleware
function login() {
return dispatch => {
MyAwesomeAPI.performLogin().then(
json => dispatch(loginSuccess(json.userId)),
error => dispatch(loginFailure(error))
)
};
}
// Side effect *and* reads state
function toggleLoginState() {
return (dispatch, getState) => {
const { isLoggedIn } = getState().loginState;
if (isLoggedIn) {
dispatch(login());
} else {
dispatch(logout());
}
};
}
// Component
this.props.toggleLoginState(); // Doesn't care how it happens
์ก์
ํฌ๋ฆฌ์์ดํฐ์ ๋ฏธ๋ค์จ์ด๋ ๋ถ์์ฉ์ ์ํํ๊ณ ์๋ก๋ฅผ ๋ณด์ํ๋๋ก _ ์ค๊ณ๋์์ต๋๋ค _.
๊ฐ์๊ธฐ๋ ์ํ ๋จธ์ ์ผ ๋ฟ์ด๋ฉฐ ๋น๋๊ธฐ์ ๊ด๋ จ์ด ์์ต๋๋ค.
๋ฆฌ๋์๋ ๋์์ ์ํด ์ํ๊ฐ ์ด๋ป๊ฒ ๋ณํ๋๋์ง ์ง์ ํฉ๋๋ค.
์ด๊ฒ์ ์ฐธ์ผ๋ก ์ ํจํ ํฌ์ธํธ์ ๋๋ค. ๊ฐ์ฌํฉ๋๋ค.
์ด ๋ฒ์ ์ด ๋ฌธ์์ ํฌํจ๋ ๋๊น์ง ํ์์ ์ํด ๋ค์ ์ด๊ฒ ์ต๋๋ค.
: +1 :
๋ฆฌ๋์๋ ์ํ ๋จธ์ ์ด์ง๋ง ์ผ๋ฐ์ ์ผ๋ก ์ก์ ์์ฑ์๋ ๊ทธ๋ ์ต๋๋ค (ํ์ง๋ง ์์ ์ ์ผ๋ก).
์ฌ์ฉ์๊ฐ "์ ์ถ"๋ฒํผ์ ๋ ๋ฒ ํด๋ฆญํ๋ค๊ณ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค. ์ฒ์์๋ HTTP ์์ฒญ์ ์๋ฒ (์ก์ ์์ฑ๊ธฐ)์ ๋ณด๋ด๊ณ ์ํ๋ฅผ "์ ์ถ ์ค"(๋ฆฌ๋์์์)์ผ๋ก ๋ณ๊ฒฝํฉ๋๋ค. ๋ ๋ฒ์งธ๋ก ๊ทธ๋ ๊ฒํ๊ณ ์ถ์ง ์์ต๋๋ค.
ํ์ฌ ๋ชจ๋ธ์์ ์ก์ ์ ์์๋ ํ์ฌ ์ํ์ ๋ฐ๋ผ ์ ๋ฌํ ์ก์ ์ ์ ํํด์ผํฉ๋๋ค. ํ์ฌ "์ ์ถ"ํ์ง ์์ ๊ฒฝ์ฐ-HTTP ์์ฒญ์ ๋ณด๋ด๊ณ ํ๋์ ์์ ์ ์ ๋ฌํฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์๋ฌด ์์ ๋ ์ํํ์ง ์๊ฑฐ๋ ๊ฒฝ๊ณ ์ ๊ฐ์ ๋ค๋ฅธ ์์ ์ ์ ๋ฌํฉ๋๋ค.
๋ฐ๋ผ์ ์ ์ด ํ๋ฆ์ ํจ๊ณผ์ ์ผ๋ก ๋ ๊ฐ์ ์ํ ๋จธ์ ์ผ๋ก ๋ถํ ๋๊ณ ๊ทธ์ค ํ๋๋ ์์ ์ ์ด๋ฉฐ ๋ถ์์ฉ์ผ๋ก ๊ฐ๋ ์ฐจ ์์ต๋๋ค.
์ด Flux ์ ๊ทผ ๋ฐฉ์์ ์ผ๋ฐ์ ์ธ ์น ์ฑ์ ๋๋ถ๋ถ์ ์ฌ์ฉ ์ฌ๋ก๋ฅผ ๋งค์ฐ ์ ์ฒ๋ฆฌํ๋ค๊ณ ๋งํ๊ณ ์ถ์ต๋๋ค. ๊ทธ๋ฌ๋ ๋ณต์กํ ์ ์ด ๋ก์ง์ด ์์ผ๋ฉด ๋ฌธ์ ๊ฐ ๋ ์ ์์ต๋๋ค. ๊ธฐ์กด์ ๋ชจ๋ ์์ ์๋ ๋ณต์กํ ์ ์ด ๋ก์ง์ด ์๊ธฐ ๋๋ฌธ์์ด ๋ฌธ์ ๋ ๋ค์ ์จ๊ฒจ์ ธ ์์ต๋๋ค.
https://github.com/Day8/re-frame ์ ์ ์ผํ FSM ์ญํ ์ํ๋ ๋จ์ผ ์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ์๋ ๋ค๋ฅธ ์ ๊ทผ ๋ฐฉ์์ ์์ ๋๋ค.
๊ทธ๋ฌ๋ ๊ฐ์๊ธฐ๋ ๋ถ์์ฉ์ด ์์ต๋๋ค. ๋ฐ๋ผ์ ์ด๋ฌํ ๊ฒฝ์ฐ "์ฌ์"๊ธฐ๋ฅ์ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ด ํฅ๋ฏธ ๋กญ์ต๋๋ค. https://github.com/Day8/re-frame/issues/86 ์์ ์ง๋ฌธํ์ต๋๋ค.
์ผ๋ฐ์ ์ผ๋ก ์ด๊ฒ์ด ์ง์ง ๋ฌธ์ ๋ผ๊ณ ์๊ฐํ๋ฉฐ ๊ณ์ํด์ ๋ํ๋๋ ๊ฒ์ ๋๋ผ์ด ์ผ์ด ์๋๋๋ค. ๊ฒฐ๊ตญ ์ด๋ค ์๋ฃจ์ ์ด ๋์ฌ์ง ๋ณด๋ ๊ฒ์ ํฅ๋ฏธ ๋กญ์ต๋๋ค.
ํ๋ ์ ๋ณ๊ฒฝ ๋ฐ ๋ถ์์ฉ์ ๋ํด ๊ณ์ ์๋ ค์ฃผ์ธ์!
๋ด ์ฑ ์๋ ๊ด์ฐฎ์ Redux ์น ์ฑ์๋ 3 ๊ฐ์ง ์ํ ์ ํ์ด ์์ต๋๋ค.
1) ๊ตฌ์ฑ ์์๋ณด๊ธฐ (React this.state). ์ด๊ฒ์ ํผํด์ผํ์ง๋ง ๋๋ก๋ Redux์ ๋ ๋ฆฝ์ ์ผ๋ก ๊ตฌ์ฑ ์์๋ฅผ ์ฌ์ฌ์ฉํ์ฌ ์ฌ์ฌ์ฉ ํ ์์๋ ์ผ๋ถ ๋์์ ๊ตฌํํ๊ณ ์ถ์ต๋๋ค.
2) ์ฑ ๊ณต์ ์ํ, ์ฆ Redux.state. ๋ณด๊ธฐ ๊ณ์ธต์ด ์ฌ์ฉ์์๊ฒ ์ฑ์ ์ ๊ณตํ๊ณ ๋ณด๊ธฐ ๊ตฌ์ฑ ์์๊ฐ์ด๋ฅผ ์ฌ์ฉํ์ฌ ์๋ก๊ฐ์ "ํต์ "ํ๋ ๋ฐ ์ฌ์ฉํ๋ ์ํ์ ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ด ์ํ๋ ๊ฒฐ์ ์ด์ด ์ํ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง ์ ์์ผ๋ฏ๋ก ActionCreators, Middleware, ๋ทฐ๊ฐ์ "ํต์ "ํ๋ ๋ฐ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ฐ๋ผ์ "๊ณต์ "๊ฐ ์ค์ํฉ๋๋ค. ํ์ง๋ง ์์ ํ ์ฑ ์ํ ์ผ ํ์๋ ์์ต๋๋ค. ๋๋ ๋ชจ๋ ๊ฒ์ ์ด๋ฌํ ์ ํ์ ์ํ๋ก ๊ตฌํํ๋ ๊ฒ์ด ๋น์ค์ฉ์ ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค (ํ๋ ์ธก๋ฉด์์).
3) ๋ค๋ฅธ ๋ถ์์ฉ์ ์ผ์ผํค๋ ๋ณต์กํ ๋ชจ๋ / libs / ์๋น์ค๊ฐ ๋ณด์ ํ๋ ์ํ. ๋ธ๋ผ ๋ค๋ฅด๊ฐ ์ค๋ช ํ๋ ์๋๋ฆฌ์ค๋ฅผ ๋ค๋ฃจ๊ธฐ ์ํด ์ด๊ฒ์ ์ธ ๊ฒ์ ๋๋ค. ๋๋ ๋ฐ์ ๋ผ์ฐํฐ๊ฐ ๋ ๋ค๋ฅธ ์์ ๋๋ค. ์์ฒด ์ํ๊ฐ์๋ ๋ธ๋ ๋ฐ์ค๋ก ์ทจ๊ธํ๊ฑฐ๋ react-router ์ํ์ ์ผ๋ถ๋ฅผ ์ฑ ๊ณต์ ์ํ (Redux.state)๋ก ์ ํํ๋๋ก ๊ฒฐ์ ํ ์ ์์ต๋๋ค. ๋ชจ๋ ์์ฒญ๊ณผ ํ์ด๋ฐ์ ์๋ฆฌํ๊ฒ ์ฒ๋ฆฌํ๋ ๋ณต์กํ HTTP ๋ชจ๋์ ์์ฑํ๋ค๋ฉด ์ผ๋ฐ์ ์ผ๋ก Redux.state์ ์์ฒญ ํ์ด๋ฐ ์ธ๋ถ ์ ๋ณด์ ๊ด์ฌ์ด ์์ต๋๋ค. ActionCreators / Middlewares์์ด ๋ชจ๋ ๋ง Redux.state์ ํจ๊ป ์ฌ์ฉํ์ฌ ์ Redux.state๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
๋ด ์์ฒญ์ ํ์ด๋ฐ์ ๋ณด์ฌ์ฃผ๋ ๋ทฐ ์ปดํฌ๋ํธ๋ฅผ ์์ฑํ๋ ค๋ฉด์ด ์ํ๋ฅผ Redux.state๋ก ๊ฐ์ ธ์์ผํฉ๋๋ค.
@vladar AC / MW๊ฐ ์์ ์ ์ํ ๋จธ์ ์ด๋ผ๋ ์๋ฏธ์ ๋๊น? ์์ฒด์ ์ผ๋ก ์ํ๋ฅผ ์ ์งํ์ง๋ ์์ง๋ง ์ฌ์ ํ ๋ค๋ฅธ ๊ณณ์์๋ ์ํ์ ์์กดํ๊ณ ์์ผ๋ฉฐ์ด ์ํ๊ฐ ์๊ฐ์ ๋ฐ๋ผ ์ด๋ป๊ฒ ์งํํ๋์ง ์ ์ด ๋ ผ๋ฆฌ๋ฅผ ์ ์ ํ ์ ์๊ธฐ ๋๋ฌธ์ ๋๊น? ์ด๋ค ๊ฒฝ์ฐ์๋ ์ฌ์ ํ ํด๋ก์ ๋ก ๊ตฌํ๋๊ณ ์์ฒด ์ํ๋ฅผ ์ ์งํ์ฌ ๋ช ์ ์ ์ํ ๋จธ์ ์ด ๋ ์ ์๋ค๊ณ ์๊ฐํฉ๋๋ค.
๋๋ Redux.state๋ฅผ "๊ณต๊ฐ ์ํ"๋ผ๊ณ ๋ถ๋ฅด๊ณ ๋ค๋ฅธ ์ํ๋ ๋น๊ณต๊ฐ๋ผ๊ณ ํ ์ ์์ต๋๋ค. ๋ด ์ฑ์ ๋์์ธํ๋ ๋ฐฉ๋ฒ์ ๋ฌด์์ ๋น๊ณต๊ฐ ์ํ๋ก ์ ์งํ๊ณ ๋ฌด์์ ๊ณต๊ฐ ์ํ๋ก ์ ์งํ ์ง ๊ฒฐ์ ํ๋ ํ์์ ๋๋ค. ์บก์ํ์ ๋ํ ์ข์ ๊ธฐํ์ฒ๋ผ ๋ณด์ด๋ฏ๋ก ์๋ก ์ํฅ์ ๋ฏธ์น๋ ๋ฐฉ์์ด ์ง์ฅ์ด๋์ง ์๋ ํ ์ํ๋ฅผ ์ฌ๋ฌ ์ฅ์๋ก ๋๋๋ ๊ฒ์ด ๋ฌธ์ ๊ฐ๋์ง ์์ต๋๋ค.
๋ธ๋ผ ๋ค๋ฅด
๊ทธ๋ฌ๋ ๊ฐ์๊ธฐ๋ ๋ถ์์ฉ์ด ์์ต๋๋ค. ๊ทธ๋์ ๊ทธ๋ค์ด ๊ทธ๋ฐ ๊ฒฝ์ฐ์ "์ฌ์"๊ธฐ๋ฅ์ ๋ค๋ฃจ๋ ๋ฐฉ๋ฒ์ด ํฅ๋ฏธ ๋กญ์ต๋๋ค
์ฝ๊ฒ ์ฌ์ํ๋ ค๋ฉด ์ฝ๋๊ฐ ๊ฒฐ์ ์ ์ด์ด์ผํฉ๋๋ค. Redux๊ฐ ์์ํ ๊ฐ์๊ธฐ๋ฅผ ์๊ตฌํจ์ผ๋ก์จ ๋ฌ์ฑ ํ ๊ฒ์ ๋๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก Redux.state๋ ์ฑ์ ๋น ๊ฒฐ์ ์ (๋น๋๊ธฐ) ๋ฐ ๊ฒฐ์ ์ ๋ถ๋ถ์ผ๋ก ๋๋๋๋ค. ๋ณด๊ธฐ ๊ตฌ์ฑ ์์์์ ๋ฏธ์น ์ง์ํ์ง ์๋๋ค๊ณ ๊ฐ์ ํ๋ฉด Redux.state ์์์ bahavior๋ฅผ ์ฌ์ํ ์ ์์ต๋๋ค. ๊ฒฐ์ ๋ก ์ ์ฝ๋๋ฅผ ๋ฌ์ฑํ๊ธฐ์ํ ์ฒซ ๋ฒ์งธ ์ค์ํ ๋ชฉํ๋ ๋น๋๊ธฐ ์ฝ๋๋ฅผ ๋ฉ๋ฆฌ ์ด๋ํ๊ณ ์์ ๋ก๊ทธ๋ฅผ ํตํด ๋๊ธฐ ์ฝ๋๋ก ๋ณํํ๋ ๊ฒ์ ๋๋ค. Flux ์ํคํ ์ฒ๊ฐ ์ผ๋ฐ์ ์ผ๋กํ๋ ์ผ์ ๋๋ค. ๊ทธ๋ฌ๋ ์ผ๋ฐ์ ์ผ๋ก ์ถฉ๋ถํ์ง ์์ผ๋ฉฐ ๋ค๋ฅธ ๋ถ์์ฉ ๋๋ ๋ณํ ์ฝ๋๋ ์ฌ์ ํ ๊ฒฐ์ ๋ก ์ ์ฒ๋ฆฌ๋ฅผ ์ค๋จ์ํฌ ์ ์์ต๋๋ค.
๋ถ์์ฉ ๋ฆฌ๋์๋ก ์ฌ์ ๊ฐ๋ฅ์ฑ์ ๋ฌ์ฑํ๋ ๊ฒ์ ๋นํ์ค์ ์ผ๋ก ์ด๋ ต๊ฑฐ๋ ๋ถ๊ฐ๋ฅํ๊ฑฐ๋ ์ค์ ํจ๊ณผ๊ฐ ๊ฑฐ์์๋ ๋ง์ ์ฝ๋ ์ผ์ด์ค์์ ๋ถ๋ถ์ ์ผ๋ก ๋ง ์๋ํฉ๋๋ค.
์ฌ์ด ์๊ฐ ์ฌํ์ ๋ฌ์ฑํ๊ธฐ ์ํด Redux์์ ์ํ ํ ๊ฒ์ฒ๋ผ ์์ (ํญ์ ์ด๋ ต์ต๋๋ค)์ ์ฌ์ํ๋ ๋์ ์ฑ ์ํ์ ์ค๋ ์ท์ ์ ์ฅํฉ๋๋ค.
์ฌ์ด ์๊ฐ ์ฌํ์ ๋ฌ์ฑํ๊ธฐ ์ํด Redux์์ ์ํ ํ ๊ฒ์ฒ๋ผ ์์ (ํญ์ ์ด๋ ต์ต๋๋ค)์ ์ฌ์ํ๋ ๋์ ์ฑ ์ํ์ ์ค๋ ์ท์ ์ ์ฅํฉ๋๋ค.
Redux DevTools ๋ ์ค๋ ์ท๊ณผ ์์ ์ ๋ชจ๋ ์ ์ฅํฉ๋๋ค. ์์ ์ด ์์ผ๋ฉด ๊ฐ์๊ธฐ๋ฅผ ๋ค์๋ก๋ ํ ์ ์์ต๋๋ค. DevTools๊ฐ ์ง์ํ๋ ์ํฌ ํ๋ก์ ๊ฐ์ฅ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ ๋๋ค.
์๊ฐ ์ฌํ์ _ ํ๊ฒฌ ๋ (์ต์ข ) ์์ ์์ ์์ค์์ ๋ฐ์ํ๊ธฐ ๋๋ฌธ์ ๋ถ์ํ ์์ ์ ์์์๊ฒ ์ ์๋ํฉ๋๋ค _. ์ด๋ค์ ์ผ๋ฐ ๊ฐ์ฒด์ด๋ฏ๋ก ์์ ํ ๊ฒฐ์ ์ ์ ๋๋ค. ์, API ํธ์ถ์ "๋กค๋ฐฑ"ํ ์๋ ์์ง๋ง ๋ฌธ์ ๋ ์์ต๋๋ค. ์์ฑ ๋ ์์ ์์ ์ ๋กค๋ฐฑ ํ ์ ์์ต๋๋ค.
์์ฒด์ ์ผ๋ก ์ํ๋ฅผ ์ ์งํ์ง๋ ์์ง๋ง ์ฌ์ ํ ๋ค๋ฅธ ๊ณณ์์๋ ์ํ์ ์์กดํ๊ณ ์์ผ๋ฉฐ์ด ์ํ๊ฐ ์๊ฐ์ ๋ฐ๋ผ ์ด๋ป๊ฒ ์งํํ๋์ง ์ ์ด ๋ ผ๋ฆฌ๋ฅผ ์ ์ ํ ์ ์๊ธฐ ๋๋ฌธ์ ๋๊น?
๊ทธ๋, ๊ทธ๊ฒ ๋ฐ๋ก ๋ด๊ฐ ์๋ฏธํ๋ ๋ฐ์ผ. ๊ทธ๋ฌ๋ ์ ์ด ๋ก์ง์ด ์ค๋ณต ๋ ์๋ ์์ต๋๋ค. ๋ฌธ์ ๋ฅผ ์ค๋ช ํ๋ ์ผ๋ถ ์ฝ๋ (์์ ์์ ์์ ๋ ๋ฒ ์ ์ถ ํด๋ฆญ).
function submit(data) {
return (dispatch, getState) => {
const { isSubmitting } = getState().isSubmitting;
if (!isSubmitting) {
dispatch(started(data));
MyAPI.submit(data).then(
json => dispatch(success(json)),
error => dispatch(failure(error))
)
}
}
}
function started(data) {
return { type: SUBMIT_STARTED, data };
}
function success(result) {
return { type: SUBMIT_SUCCESS, result };
}
function failure(error) {
return { type: SUBMIT_FAILURE, error };
}
๊ทธ๋ฐ ๋ค์ ๊ฐ์๊ธฐ๊ฐ "isSubmitting"์ํ๋ฅผ ๋ค์ ํ์ธํฉ๋๋ค.
const initialState = new Immutable.Map({
isSubmitting: false,
pendingData: null,
error: null
});
export default function form(state = initialState, action) {
switch (action.type) {
case SUBMIT_STARTED:
if (!state.isSubmitting) {
return state.merge({
isSubmitting: true,
pendingData: action.data
});
} else {
return state;
}
}
}
๋ฐ๋ผ์ ๋ ๊ณณ์์ ๋์ผํ ๋ ผ๋ฆฌ์ ๊ฒ์ฌ๋ฅผ ๋ฐ๊ฒ๋ฉ๋๋ค. ๋ถ๋ช ํ์ด ์์ ์์ ์ค๋ณต์ ์ต์ํ๋์ง๋ง ๋ ๋ณต์กํ ์๋๋ฆฌ์ค์์๋ ์์์ง ์์ ์ ์์ต๋๋ค.
๋ง์ง๋ง ์์์ ์ฒดํฌ๋ ๊ฐ์๊ธฐ ์์ ์์ด์ผํ๋ค๊ณ ์๊ฐํฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ๋น ๋ฅด๊ฒ ๋ถ์ผ์น๋ก ๋ด๋ ค๊ฐ ์ ์์ต๋๋ค.
(๊ทธ๊ฒ ๋น์ ์ด ๋ง๋๋ ์์ ์ด๋ผ๋ฉด ์ฃ์กํฉ๋๋ค ;-)
SUBMIT_STARTED ์ก์ ์ด ์ ๋ฌ๋์๋ค๋ ์ฌ์ค์! isSubmitting์ด ์ด๋ฏธ ์ธ์ฝ๋ฉ๋์ด ์๊ธฐ ๋๋ฌธ์ gaeron์ ๋์ํฉ๋๋ค. ์ก์ ์ด ์ด๋ค ๋ก์ง์ ๊ฒฐ๊ณผ ์ผ ๋ ๊ทธ ๋ก์ง์ด ๋ฆฌ๋์์์ ๋ณต์ ๋์ด์๋ ์๋ฉ๋๋ค. ๊ทธ๋ ๋ค๋ฉด ๊ฐ์๊ธฐ ์ฑ ์์ SUBMIT_STARTED๋ฅผ ์์ ํ ๋๋ง๋ค ๋ค๋ฅธ ์ฌ๋์ด SUBMIT_STARTED๋ฅผ ๊ฒฐ์ ํ๋ ์ฑ ์์ ์ก๊ธฐ ๋๋ฌธ์ ์๊ฐํ์ง ์๊ณ ์ก์ ํ์ด๋ก๋๋ก ์ํ๋ฅผ ์ ๋ฐ์ดํธํ๋ ๊ฒ์ ๋๋ค.
ํ๋์ ๊ฒฐ์ ์ ๋ํด ์ฑ ์์์ง๋ ๊ฒ์ด ํ๋๋ผ๋ ๊ฒ์ ํญ์ ๋ชฉํ๋กํด์ผํฉ๋๋ค.
๊ฐ์๊ธฐ๋ SUBMIT_STARTED ์ฌ์ค์ ์ถ๊ฐ๋ก ๋น๋ํ๊ณ ์ถ๊ฐ ๋ก์ง์ผ๋ก ํ์ฅ ํ ์ ์์ง๋ง์ด ๋ก์ง์ ๋ฌ๋ผ์ผํฉ๋๋ค. Fe :
case SUBMIT_STARTED:
if (goodMood) loading...
else nothing_happens
๋๊ฐ ๋ฌด์์ ์ฑ ์ ์ ธ์ผํ๋์ง ๊ฒฐ์ ํ๋ ๊ฒ์ด ๋๋๋ก ๊น๋ค๋ก์ธ ์ ์๋ค๊ณ ์์ํ ์ ์์ต๋๋ค. ActionCreator, ๋ฏธ๋ค์จ์ด, ๋ ๋ฆฝํ ๋ณตํฉ ๋ชจ๋, ๊ฐ์๊ธฐ?
๊ฐ์๊ธฐ์์ ๊ฐ๋ฅํ ํ ๋ง์ ๊ฒฐ์ ์ ๋ด๋ฆฌ๊ณ ์์ํ๊ฒ ์ ์งํ๋ ๊ฒ์ ๋ชฉํ๋ก ํ ๊ฒ์ ๋๋ค. ๋ถ์์ฉ / ๋น ๋๊ธฐํ์ ๋ํ ๊ฒฐ์ ์ด ํ์ํ ๊ฒฝ์ฐ AC / MW / somewhere_else๋ก ์ด๋ํฉ๋๋ค. ์ฝ๋ ์ฌ์ฌ์ฉ, ์ฆ ๋ฆฌ๋์ ๋ ๋ฏธ๋ค์จ์ด์ ๊ด๋ จํ์ฌ ๋ชจ๋ฒ ์ฌ๋ก๊ฐ ์ด๋ป๊ฒ ๋ฐ์ ํ๋์ง์ ๋ฐ๋ผ ๋ฌ๋ผ์ง ์ ์์ต๋๋ค.
AC๋ state.isSubmitting์ ์ง์ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค. ๋ฐ๋ผ์ ๋ ผ๋ฆฌ๊ฐ ๊ทธ๊ฒ์ ์์กดํ๋ ๊ฒฝ์ฐ AC๋ state.isSubmitting์ด ๋ ผ๋ฆฌ์ ๋๊ธฐํ๋๋๋ก ๋ณด์ฅํด์ผํฉ๋๋ค. AC ๋ก์ง์ด ์ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ state.isSubmitted๋ฅผ true๋ก ์ค์ ํ๊ณ ์ฝ๊ธฐ๊ฐ ๋์์๋ค๋ฉด ๊ทธ ์์ฒด๋ก ์ค์ ๋ ๊ฒ์ผ๋ก ์์ํฉ๋๋ค. ์ ์ฌ์ ์ผ๋ก์ด ์ ์ ๋ฅผ ๋ณ๊ฒฝํ๋ ๋ค๋ฅธ ๋ ผ๋ฆฌ๊ฐ ์์ด์๋ ์๋ฉ๋๋ค. ACTION์ ๋๊ธฐํ ๊ธฐ๋ณธ ์์ ์์ฒด์ ๋๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก ํ๋์ ํ๋กํ ์ฝ์ ์ ์ํ๊ณ ํ๋กํ ์ฝ์ ๋ช ํํ๊ณ ๋ช ํํ๊ฒ ์ ์๋์ด์ผํฉ๋๋ค.
ํ์ง๋ง ๋๋ ๋น์ ์ด ๋ฌด์จ ๋ง์ ํ๋ ค๋์ง ์๊ณ ์๋ค๊ณ ์๊ฐํฉ๋๋ค. Redux.state๋ ๊ณต์ ์ํ์ ๋๋ค. ๊ณต์ ์ํ๋ ํญ์ ๊น๋ค ๋กญ์ต๋๋ค. AC ๋ก์ง์ ์ํด ์์์น ๋ชปํ ๋ฐฉ์์ผ๋ก ์ํ๋ฅผ ๋ณ๊ฒฝํ๋ ๊ฐ์๊ธฐ์์ ์ฝ๋๋ฅผ ์์ฑํ๋ ๊ฒ์ ์ฝ์ต๋๋ค. ๋ฐ๋ผ์ ๋งค์ฐ ๋ณต์กํ ์๋๋ฆฌ์ค์์ AC์ ๊ฐ์๊ธฐ ์ฌ์ด์ ๋ ผ๋ฆฌ๋ฅผ ๋๊ธฐํํ๋ ๊ฒ์ด ์ด๋ ค์ธ ์ ์๋ค๊ณ ์์ํ ์ ์์ต๋๋ค. ์ด๋ก ์ธํด ์ถ์ ๋ฐ ๋๋ฒ๊น ์ด ์ด๋ ค์ธ ์์๋ ๋ฒ๊ทธ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. ์ด๋ฌํ ์๋๋ฆฌ์ค์ ๊ฒฝ์ฐ ๋ ผ๋ฆฌ๋ฅผ AC / ๋ฏธ๋ค์จ์ด๋ก ์ถ์ํ๊ณ ๋ฆฌ๋์๊ฐ ๋ ผ๋ฆฌ๊ฐ ์๊ฑฐ๋ ๊ฑฐ์์๋ ์ ์ ์ ๋ ๋์์ ๊ธฐ๋ฐ์ผ๋ก ์ด๋ฆฌ์๊ฒ ๋ง ์๋ํ๋๋กํ๋ ๊ฒ์ด ํญ์ ๊ฐ๋ฅํ๋ค๊ณ ์๊ฐํฉ๋๋ค.
๋๊ตฐ๊ฐ๋ ํญ์ ์ค๋๋ ์ข ์ AC๋ฅผ ๋๋ ์๋ก์ด ๊ฐ์๊ธฐ๋ฅผ ์ถ๊ฐ ํ ์ ์์ต๋๋ค. AC๋ฅผ Redux ์ํ์ ์ข ์์ํค๊ธฐ ์ ์ ๋ ๋ฒ ์๊ฐํด์ผํฉ๋๋ค.
์ฌ์ฉ์ ์๊ฒฉ ์ฆ๋ช ๊ณผ ํจ๊ป API ์์ฒญ์์ ๋ฐํ ๋ ์ธ์ฆ ํ ํฐ์ด ํ์ํ ์์ ์์ฑ์๊ฐ ์์ต๋๋ค. ์ด ํ ํฐ์๋ ์๊ฐ ์ ํ์ด ์์ผ๋ฉฐ ๋ฌด์ธ๊ฐ์ ์ํด ์๋ก ๊ณ ์ณ์ง๊ณ ๊ด๋ฆฌ๋์ด์ผํฉ๋๋ค. ๋น์ ์ด ์ ์ํ๋ ๊ฒ์์ด ์ํ๊ฐ Redux.state์ ์ํ์ง ์๋๋ค๋ ๊ฒ์ ๋ํ๋ด๋ ๊ฒ ๊ฐ์ต๋๋ค.
์ด๋๋ก ๊ฐ์ผํ๋์? ๊ฐ๋ ์ ์ผ๋ก Redux ์ ์ฅ์์ ์์ฑ์์ ๋ถ๋ณ์ ์ธ๋ถ ์ํ๋ก ์ ๋ฌ๋ฉ๋๊น?
๋ฐ๋ผ์ ๋งค์ฐ ๋ณต์กํ ์๋๋ฆฌ์ค์์ AC์ ๊ฐ์๊ธฐ ์ฌ์ด์ ๋ ผ๋ฆฌ๋ฅผ ๋๊ธฐํํ๋ ๊ฒ์ด ์ด๋ ค์ธ ์ ์๋ค๊ณ ์์ํ ์ ์์ต๋๋ค.
๋ค. ๋๋ ๊ทธ๊ฒ์ด ์ผ ์คํ ํผ๋ผ๋ ๋ง์ ์๋์ง๋ง ์ผ๊ด์ฑ์ด ์์ ์ ์์ต๋๋ค. ์ํ ๋จธ์ ์ ์์ ์ ๋ํ๋๋ ์์์ ๊ด๊ณ์์ด ์ด๋ฒคํธ์ ๋ฐ์ํ๊ณ ์ผ๊ด์ฑ์ ์ ์งํ๋ ๊ฒ์ ๋๋ค.
AC์์ ์ด๋ฒคํธ์ ์ ์ ํ ์์์ ์์กดํ๋ ๊ฒฝ์ฐ ์์ ์ ์ผ๋ก ์ํ ์์ง์ ์ผ๋ถ๋ฅผ AC๋ก ์ด๋ํ๊ณ ๊ฐ์๊ธฐ์ ๊ฒฐํฉํฉ๋๋ค.
์๋ง๋ ๊ทธ๊ฒ์ ์ ํธ์ ๋ฌธ์ ์ผ ์๋ ์์ง๋ง ์คํ ์ด / ๋ฆฌ๋์๊ฐ ํญ์ ์ผ๊ด๋๊ฒ ์๋ํ๊ณ ๋ค๋ฅธ ๊ณณ์์ ์ผ๊ด์ฑ์ ์ ์งํ๊ธฐ ์ํด ์ธ๋ถ์ ์์กดํ์ง ์์ ๋ ํจ์ฌ ๊ธฐ๋ถ์ด ์ข์ต๋๋ค.
AC๋ฅผ Redux ์ํ์ ์ข ์์ํค๊ธฐ ์ ์ ๋ ๋ฒ ์๊ฐํด์ผํฉ๋๋ค.
๋ณต์กํ ๊ฒฝ์ฐ์๋ ํผํ ์ ์๋ค๊ณ ์๊ฐํฉ๋๋ค (๋ถ์์ฉ์ ๊ฐ์๊ธฐ / ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ก ์ฎ๊ธฐ์ง ์๊ณ ๋).
"ํซ ๋ฆฌ๋ก๋ฉ ๋๋ ๋ฆฌํ๋ ์ด ๊ธฐ๋ฅ ์ญ์ "์ "ํ ๊ณณ์์ ์ํ ๊ด๋ฆฌ"๋ผ๋ ์ ์ถฉ์ ์ธ ๊ฒ ๊ฐ์ต๋๋ค. ๋์ค์ ๊ฒฝ์ฐ re-frame ์ ์๊ณผ ๊ฐ์ ์ค์ FSM ๋๋ Statecharts๋ฅผ ์์ฑํ ์ ์์ผ๋ฉฐ, ์ ์์ ๊ฒฝ์ฐ ํ์ฌ Flux์์์ ๊ฐ์ด ๋ ์์์ ์ธ ์ ์ด ๋ก์ง์ ๋๋ค.
Re-frame์ ํตํด (๋๋ฌด ๋นจ๋ฆฌ) ์ฝ์์ผ๋ฉฐ Redux์ ๊ฐ์ ์ข ๋ฅ์ ๊ตฌํ ์ธ๋ถ ์ฌํญ ์ฐจ์ด๊ฐ ์์ต๋๋ค. Re-frame view ์ปดํฌ๋ํธ๋ Observable์ ๊ธฐ๋ฐ์ผ๋กํ๊ณ , Events๋ Actions, Re-frame์ ์์ฑ์๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ๊ฐ์ฒด (๋ทฐ ์ปดํฌ๋ํธ์์ ๊ตฌ์ฑ๋จ)๋ก ์ง์ ์ด๋ฒคํธ (์ก์ )๋ฅผ ์ ๋ฌํฉ๋๋ค. Event Handler๋ ์์ํ๋ฉฐ Redux์ ๋์ผํฉ๋๋ค. ๊ฐ์๊ธฐ.
๋ถ์์ฉ ์ฒ๋ฆฌ๋ ๋ง์ด ๋ ผ์๋์ง ์์๊ฑฐ๋ ๊ทธ๊ฒ์ ๋์ณค์ต๋๋ค. ๊ทธ๋ฌ๋ ์ ๊ฐ ๊ฐ์ ํ๊ณ ์๋ ๊ฒ์ ๊ทธ๊ฒ๋ค์ด ๋ฏธ๋ค์จ์ด์์ ์ฒ๋ฆฌ๋๋ค๋ ๊ฒ์ ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ฃผ์ ์ฐจ์ด์ ์ด ์์ต๋๋ค. ๋ฏธ๋ค์จ์ด๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ (๋ฆฌ๋์)๋ฅผ ๊ฐ์ธ๊ณ ์ธ๋ถ์์ ๊ตฌ์ฑํ๋ ๋ฐ๋ฉด Redux ๋ฏธ๋ค์จ์ด๋ ๋ฆฌ๋์๋ฅผ ๊ฐ์ธ์ง ์์ต๋๋ค. ์ฆ, Re-frame์ ์์ํ ๊ฐ์๊ธฐ์ ์ง์ ๋ถ์์ฉ์ ๊ตฌ์ฑํ๋ ๋ฐ๋ฉด Redux๋ ๋ถ๋ฆฌ ๋ ์ํ๋ก ์ ์งํฉ๋๋ค.
๊ทธ๊ฒ์ Re-frame ์ด๋ฒคํธ๋ฅผ ๊ธฐ๋กํ๊ณ ์ฝ๊ฒ ์ฌ์ํ ์ ์๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
๊ฐ๋ฅํ ๋ถ์ผ์น์ ๋ํด ์ด์ผ๊ธฐ ํ ๋ ๊ณต์ ์ํ๋ฅผ ๊ทผ๋ณธ ์์ธ์ผ๋ก ์๊ฐํ๊ณ Re-frame์ด ๋์ผํ ์ํ์ ๊ฐ์ง๊ณ ์๋ค๊ณ ์๊ฐํฉ๋๋ค.
์ฐจ์ด์ ์ ๋ฏธ๋ค์จ์ด์ ๊ฐ์๊ธฐ๋ฅผ ๊ฒฐํฉํ๋ ๊ฒ์ ๋๋ค. ๋ฏธ๋ค์จ์ด๊ฐ Re-frame์์ ์๋ฃ๋๋ฉด ๊ฒฐ๊ณผ๋ฅผ ์ด๋ฒคํธ ํธ๋ค๋ฌ (๋ฆฌ๋์)์ ์ง์ ์ ๋ฌํฉ๋๋ค.์ด ๊ฒฐ๊ณผ๋ ์ด๋ฒคํธ / ์ก์ ์ผ๋ก ๊ธฐ๋ก๋์ง ์์ผ๋ฏ๋ก ์ฌ์ํ ์ ์์ต๋๋ค. ๋๋ Redux๊ฐ ํ๋์ ํํ๋ก ๊ทธ ์ฌ์ด์ ํํฌ๋ฅผ ๋ฃ์ ๋ฟ์ด๋ผ๊ณ ๋งํ๊ณ ์ถ์ต๋๋ค. ๋ฐ๋ผ์ ๋ ๋ง์ ํ์ดํ (์ก์ ์์ฑ)์ ํฌ์ํ๋ฉด์ ๋ ๋ง์ ์ ์ฐ์ฑ๊ณผ ์๋ง๋ ๊ทธ๊ฒ์ ํ ์์๋ ๋ ๋ง์ ๊ณต๊ฐ์ผ๋ก ๋ฆฌ ํ๋ ์์ดํ๋ ๊ฒ๊ณผ ๊ฐ์ ๊ฒ์ ๊ธฐ์ ์ ์ผ๋ก ๋ฌ์ฑ ํ ์ ์๋ค๊ณ ๋ฏฟ์ต๋๋ค. ์๋ชป๋.
๊ฒฐ๊ตญ Redux๊ฐ Re-frame๊ณผ ๋๊ฐ์ ์ ๊ทผ ๋ฐฉ์์ ๊ตฌํํ๋ ๊ฒ์ ๋ง๋ ๊ฒ์ ์์ต๋๋ค. ๊ฐ์๊ธฐ๋ฅผ ๋งค๊ฐ ๋ณ์๋ก ์ฌ์ฉํ๋ ๋ชจ๋ ํจ์๋ฅผ ์์ฑํ๊ณ , ๊ทธ ์์ ์ผ๋ถ ์ฒ๋ฆฌ๋ฅผ ํ ๋ค์ ๊ฒฐ๊ณผ์ ํจ๊ป ๊ฐ์๊ธฐ ํจ์๋ฅผ ์ง์ ํธ์ถํ๊ณ Reducer Middlewares ๋ฑ์ผ๋ก ํธ์ถ ํ ์ ์์ต๋๋ค. DevTools๋ฅผ ์์ด ๋ฒ๋ฆฌ๊ณ ๋ ๋ง์ ์ปคํ ๋ง์ํ๋ฉด์ ์ข ๋ ์ฝ๊ฒ ๋ง๋ค๊ณ ์ถ์ ๋์ ๋๋ค.
์ผ๋ถ ๋จ์ํ (์ก์ ๊ฐ์)๋ณด๋ค Re-frame ์ ๊ทผ ๋ฐฉ์์ ์๋นํ ์ด์ ์ด ์๋ค๋ฉด ๋ ๋ง์ด ์๊ฐํด์ผํฉ๋๋ค. ๋๋ ๊ทธ๊ฒ์ ๋นจ๋ฆฌ ์ฝ์๋ค ๊ณ ๋งํ๋ฏ์ด ๋ด๊ฐ ํ๋ ธ๋ค๋ ๊ฒ์ ์ฆ๋ช ํ๊ธฐ ์ํด ์ด๋ ค ์์ต๋๋ค.
์ฌ์ค ๋๋ ์ฝ๊ฐ ํ๋ ธ๋ค. ์ฐจ์ด์ ์ Redux์ Re-frame ๊ตฌํ์ด ์๋๋ผ ์ค์ ๋ก "๋ถ์์ฉ์ ๋ฃ๋ ์์น"์ ์์ต๋๋ค.
์ด๋ฒคํธ ํธ๋ค๋ฌ (๋ฆฌ๋์)์์์ด ์์ ์ ์ํํ๊ณ ์ก์ ์์ฑ์๊ฐ ์ ์ด ํ๋ฆ์ ์ํฅ์์ฃผ๋ ๊ฒ์ ํ์ฉํ์ง ์์ผ๋ฉด ๊ธฐ์ ์ ์ผ๋ก ์ฐจ์ด๊ฐ ์์ต๋๋ค. Redux์์๋ fsm / statecharts๋ฅผ ์ฌ์ฉํ๊ณ ์ ์ด ํ๋ฆ์ ํ๊ณณ์ ๋ ์ ์์ต๋๋ค.
๊ทธ๋ฌ๋ ์ค์ ๋ก๋ ์ฐจ์ด๊ฐ ์์ต๋๋ค. @gaearon์ ๊ทธ๊ฒ์ ์์ฃผ ์ ์ค๋ช ํ์ต๋๋ค : Redux๋ ๋น์ ์ ๊ฐ์๊ธฐ๊ฐ ์์ํ๊ธฐ๋ฅผ ๊ธฐ๋ํฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์ฌ์ ๊ธฐ๋ฅ์ด ์ค๋จ๋ฉ๋๋ค. ๋ฐ๋ผ์ Redux ๋์์ธ์ ์๋ฐฐ๋๋ฏ๋ก ๊ทธ๋ ๊ฒํด์๋ ์๋ฉ๋๋ค (๊ฐ์๊ธฐ์ ๋ถ์์ฉ์ ๋ฃ๋ ๊ฒ).
Re-frame์ ๋ํ ์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ ์์ํ๋ค๊ณ ๋งํ์ง๋ง Readme์์๋ HTTP ์์ฒญ์ด ์ด๋ฒคํธ ํธ๋ค๋ฌ์์ ์์๋๋ค๊ณ ์ธ๊ธํฉ๋๋ค. ๊ทธ๋์ ์ด๊ฒ์ ์ ์๊ฒ ์ฝ๊ฐ ๋ถ๋ถ๋ช ํ์ง๋ง ๊ทธ๋ค์ ๊ธฐ๋๋ ๋ค๋ฅธ ๊ฒ ๊ฐ์ต๋๋ค. ์ด๋ฒคํธ ์ฒ๋ฆฌ์์๊ฒ ๋ถ์์ฉ์ ๋ฃ์ ์ ์์ต๋๋ค.
๊ทธ๋ฐ ๋ค์ ๊ทธ๋ค์ด ์ฌ์์ ์ ๊ทผํ๋ ๋ฐฉ๋ฒ์ด ํฅ๋ฏธ ๋กญ์ต๋๋ค (https://github.com/Day8/re-frame/issues/86์์ ์์ฒญํ ๊ฒ์ ๋๋ค).
์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ ๋ถ์์ฉ์ ๊ฐ์ง ์์์ ๋์ด๋ฅผ ์ํํ๋ ์ ์ผํ ๋ฐฉ๋ฒ์ @ tomkis1์ด ์ธ๊ธ ํ ๊ฒ์ ๋๋ค. ๋ชจ๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ์์ ๋ฐํ ๋ ์ํ๋ฅผ ๊ธฐ๋กํ๋ ๊ฒ์ ๋๋ค (๋ชจ๋ ์ด๋ฒคํธ์์ ๊ฐ์๊ธฐ๋ฅผ ๋ค์ ์คํํ์ง ์์).
ํซ ๋ฆฌ๋ก๋ฉ์ "๊ณผ๊ฑฐ"์ด๋ฒคํธ์ ์ํฅ์ ์ค ์ ์๋ค๋ ์ ์ ์ ์ธํ๊ณ ๋ ์ฌ์ ํ ์๋ ํ ์ ์์ต๋๋ค. ์๊ฐ์ ๋ฐ๋ผ ์ผ๋ถ ์๋ก์ด ์ํ ๋ถ๊ธฐ ๋ง ์์ฑํฉ๋๋ค.
๊ทธ๋์ ๋์์ธ์ ์ฐจ์ด๋ ๋ฏธ๋ฌํ์ง๋ง ์ ์๊ฒ๋ ์ค์ํฉ๋๋ค.
๋๋ ๊ทธ๋ค์ด ๋ถ์์ฉ์ ์ผ์ผํค๋ ๋ฏธ๋ค์จ์ด๋ก ์์ํ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ๊ตฌ์ฑํจ์ผ๋ก์จ HTTP ์์ฒญ์ํ๋ค๊ณ ์๊ฐํฉ๋๋ค. ์ด ๊ตฌ์ฑ์ ๋ ์ด์ ์์ํ์ง ์์ง๋ง ๋ด๋ถ๋ ์์ํ๊ฒ ์ ์ง๋๋ ์๋ก์ด ์ด๋ฒคํธ ์ฒ๋ฆฌ๊ธฐ๋ฅผ ๋ฐํํฉ๋๋ค. ๋๋ ๊ทธ๋ค์ด app-db (์ํ) ๋์ฐ๋ณ์ด์ ๋ถ์์ฉ์ ํผํฉํ๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ๋ง๋ค ๊ฒ์ ์ ์ํ์ง ์๋๋ค๊ณ ์๊ฐํฉ๋๋ค. ์ฝ๋๋ฅผ๋ณด๋ค ์ฝ๊ฒ โโํ ์คํธ ํ ์ ์์ต๋๋ค.
์ด๋ฒคํธ ํธ๋ค๋ฌ์ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋กํ๋ ๊ฒฝ์ฐ ํซ ๋ฆฌ๋ก๋ ๊ฐ๋ฅ์ผ๋ก ๋ง๋ค ์ ์์ผ๋ฏ๋ก ์ฆ์ ์ฝ๋๋ฅผ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค. ๋ฏธ๋ค์จ์ด์ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋กํด์ผํ๊ณ ๊ทธ๊ฒ์ Redux๊ฐํ๋ ๊ฒ๊ณผ ๋๊ฐ์ ๊ฒ์ ๋๋ค-์ด ๊ฒฐ๊ณผ๋ฅผ ์ก์ ์ผ๋ก ๊ธฐ๋กํ๊ณ ๊ทธ๊ฒ์ ๊ฐ์๊ธฐ์ ์ ๋ฌํ์ญ์์ค (๋ฃ๊ธฐ).
Re-frame ๋ฏธ๋ค์จ์ด๋ ๋ฅ๋์ ์ด๋ผ๊ณ ๋งํ ์ ์์ง๋ง Redux๋ ๋ฐ์์ฑ์ ํ์ฉํฉ๋๋ค (๋ชจ๋ ์ ๋ํน ๊ฐ์๊ธฐ๋ ๋ฏธ๋ค์จ์ด / ac์ ๊ฒฐ๊ณผ๋ฅผ๋ค์ ์ ์์ต๋๋ค). ์ ๊ฐ ๊นจ๋ซ๊ธฐ ์์ํ ํ ๊ฐ์ง๋ Flux์ ๋ฏธ๋ค์จ์ด์์ ์ฃผ๋ก ์ฌ์ฉ๋๋ AC๋ ์ปจํธ๋กค๋ฌ์ ๋์ผํ๋ค๋ ๊ฒ์ ๋๋ค.
๋ด๊ฐ ์ดํดํ๋ฏ์ด @ tomkis1 ์ ๋ชจ๋ ๋จ์ผ ๋์ฐ๋ณ์ด์ ๋ํด ์ํ๋๋ฉด ์ฑ๋ฅ์ ์ํฅ์ ๋ฏธ์น ์ ์๋ค๊ณ ๊ฐ์ ํ๋ฏ๋ก ์ฃผ์ด์ง ๊ฐ๊ฒฉ์ผ๋ก ์ ์ฅ ์ํ๋ฅผ ํตํด ์๊ฐ
์ข์์, ๊ฐ์๊ธฐ / ์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ ์์ ํ ์๋ก์ด ์ํ๋ฅผ ๋ฐํํ๋ค๋ ๊ฒ์ ๊นจ๋ฌ์์ผ๋ฏ๋ก ๋์ผํ๊ฒ ๋งํ์ต๋๋ค.
@merk ์ฃผ๋ง์๋ ์ฌ๊ธฐ์ ์ค์ง ์๊ธฐ ๋๋ฌธ์ ์๋ง๋ ์์์ผ์ ๊ทธ๊ฒ์ ๋ํ ์๊ฐ์ ์ฐ๋ ค๊ณ ๋ ธ๋ ฅํ ๊ฒ์ ๋๋ค.
Re-frame ๋ฌธ์๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ์์ ์๋ฒ์ ๋ํ ํ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค : https://github.com/Day8/re-frame#talking -to-a-server
๊ทธ๋์ ์ด๊ฒ์ด Redux์ ๋ค๋ฅธ ๊ณณ์ ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ด ์ฐจ์ด๋ ์ธ๋ป๋ณด๊ธฐ๋ณด๋ค ๋ ๊น์ต๋๋ค.
ํ , Redux์์ ์ฐจ์ด์ ์ ๋ณด์ง ๋ชปํ์ต๋๋ค.
์์ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ ์ด๋ฌํ HTTP ์์ฒญ์ ๋ํ on-success ๋๋ on-fail ํธ๋ค๋ฌ๊ฐ ๋จ์ํ ์ ์ด๋ฒคํธ๋ฅผ ์ ๋ฌํ๋๋ก ๊ตฌ์ฑํด์ผ ํฉ๋๋ค. ์ ๋๋ก app-db๋ฅผ ์ง์ ์์ ํด์๋ ์๋ฉ๋๋ค. ๊ทธ๊ฒ์ ํญ์ ํธ๋ค๋ฌ์์ ์ํ๋ฉ๋๋ค.
์ด๋ฒคํธ๋ฅผ Action์ผ๋ก ๋ฐ๊ฟ๋๋ค. Redux๋ ์์ํ ์ด๋ฒคํธ ํธ๋ค๋ฌ์ ๋ํ ํน๋ณํ ์ด๋ฆ ์ธ ๊ฐ์๊ธฐ๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค. ์ด๋ฒ ์ฃผ๋ง์ ๋ญ๊ฐ ๋น ์ก๊ฑฐ๋ ๋๊ฐ ๋ค์ด ๋ ๊ฒ ๊ฐ์์.
์ด๋ฒคํธ๊ฐ ์คํ๋๋ ๋ฐฉ์ (๋๊ธฐ์ด ๋ฐ ๋น๋๊ธฐ)์์ ๋ ํฐ ์ฐจ์ด๋ฅผ ๋๋ ์ ์์ต๋๋ค. Redux๋ ์ํ ์ผ๊ด์ฑ์ ๋ณด์ฅํ๊ธฐ ์ํด ์์ ๋ณ๋ก ์์ ๋๊ธฐํ ๋ฐ ์ ๊ธ ๋จ๊ณ ์์ ์ ์คํํ๋ค๊ณ ์๊ฐํฉ๋๋ค. ์ด๋ฒคํธ๋ฅผ ์ ์ฅํ๊ณ ๋ฐ๋ณตํด์ ์ฌ์ํ๋ ๊ฒ์ด ๋์ผํ ์ข ๋ฃ ์ํ๊ฐ ๋ ์ง ํ์คํ์ง ์๊ธฐ ๋๋ฌธ์ ์ฌ์์ฑ์ ๋ ์ํฅ์ ๋ฏธ์น ์ ์์ต๋๋ค. ์ก์ ์ด ํญ์ ์์ํ ์ฝ๋๋ฅผ ํธ๋ฆฌ๊ฑฐํ๋ Redux์ ๋ฌ๋ฆฌ ์ด๋ค ์ด๋ฒคํธ๊ฐ ๋ถ์์ฉ์ ์ ๋ฐํ๋์ง ๋ชจ๋ฅด๊ธฐ ๋๋ฌธ์ ๊ทธ๋ ๊ฒ ํ ์๋ ์์ต๋๋ค.
@vladap ๋ด๊ฐ ๋ณธ ์ฐจ์ด์ ์ ์์ฝํ๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
1.
2.
์ผ.
๊ฐ๋ฐ ๊ฒฝํ์ ์ฐจ์ด์ ๊ดํด์๋ ๋น๋๊ธฐ ํญ๋ชฉ (ํ์ด๋จธ, ๋ณ๋ ฌ http ์์ฒญ, ์น ์์ผ ๋ฑ)์ด ๋ง์ ๊ฒฝ์ฐ์๋ง ๋ํ๋ฉ๋๋ค. ๋๊ธฐํ ํญ๋ชฉ์ ๊ฒฝ์ฐ ๋ชจ๋ ๋์ผํฉ๋๋ค (AC์๋ ์ ์ด ํ๋ฆ์ด ์๊ธฐ ๋๋ฌธ์).
๋ด ์์ ์ ๋ ๋ช ํํ๊ฒํ๊ธฐ ์ํด ์ด๋ฌํ ๋ณต์กํ ์๋๋ฆฌ์ค์ ์ค์ ์ฌ๋ก๋ฅผ ์ค๋นํด์ผํ๋ค๊ณ ์๊ฐํฉ๋๋ค.
๋ด๊ฐ ๋น์ ์ ๋ฏธ์น๊ฒ ํ ์๋ ์์ต๋๋ค. ์ฃ์กํ์ง๋ง ์ฐ๋ฆฌ๋ ๊ธฐ๋ณธ์ ์ธ ๊ฒ์ ๋์ํ์ง ์์ต๋๋ค. ๋ฆฌ ํ๋ ์ ์์ ์ฝ๋๋ฅผ ์ฝ์ด์ผ ํ ์๋ ์๊ณ ์ธ์ ๊ฐ Clojure๋ฅผ ๋ฐฐ์ธ ๊ฒ์ ๋๋ค. ์๋ง๋ ๋น์ ์ ๊ทธ๋ฌ์ ๊ฒ์ด๋ฏ๋ก ๋ ๋ง์ด ์๊ณ ์์ต๋๋ค. ๋ ธ๋ ฅํด ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค.
1.
Redux์์๋ ์์ฑ์์์ ์๋ฒ ์์ฒญ์ ์์ํฉ๋๋ค (์ด ๋ฌธ์ ์ ์๋ ์ง๋ฌธ์ ๋ํ @gaearon ์๋ต ์ฐธ์กฐ). ๊ฐ์๊ธฐ๋ ์์ํด์ผํฉ๋๋ค
Re-frame์์๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ (reducer)์์ ์ํํฉ๋๋ค. ์ด๋ฒคํธ ํธ๋ค๋ฌ (๊ฐ์ ์)๋ ๋ถ์์ฉ์ด์์ ์ ์์ต๋๋ค.
๋ด๊ฐ ๊ตต๊ฒ ๋ง๋ ๋ฌธ์๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ์์ webapi ํธ์ถ์ ์์ํ ๋ค์ ์ฑ๊ณต์ ์ด๋ฒคํธ๋ฅผ ์ ๋ฌํด์ผํ๋ค๊ณ ๋ช ์ ์ ์ผ๋ก ๋งํฉ๋๋ค. ๋์ผํ ์ด๋ฒคํธ ์ฒ๋ฆฌ๊ธฐ์์์ด ์ ๋ฌ ๋ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌ ํ ์์๋ ๋ฐฉ๋ฒ์ ์ดํดํ์ง ๋ชปํฉ๋๋ค. ์ด ์ฑ๊ณต ์ด๋ฒคํธ๋ ๋ผ์ฐํฐ (๋ด ์๊ฐ์ ๋์คํจ์ฒ์ ๋ฑ์)๋ก ์ ๋ฌ๋๋ฉฐ ์ฒ๋ฆฌ ํ ๋ ๋ค๋ฅธ ์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ ํ์ํฉ๋๋ค. ์ด ๋ ๋ฒ์งธ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ ์์ํ๊ณ Redux ๊ฐ์๊ธฐ์ ๋์ผํ๋ฉฐ ์ฒซ ๋ฒ์งธ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ ActionCreator์ ๋์ผํฉ๋๋ค. ๋์๊ฒ ๊ทธ๊ฒ์ ๋๊ฐ๊ฑฐ๋ ์ค์ํ ํต์ฐฐ๋ ฅ์ ๋ถ๋ช ํ ๋์น ๊ฒ์ ๋๋ค.
๊ฐ๋ฐ ๊ฒฝํ์ ์ฐจ์ด์ ๊ดํด์๋ ๋น๋๊ธฐ ํญ๋ชฉ (ํ์ด๋จธ, ๋ณ๋ ฌ http ์์ฒญ, ์น ์์ผ ๋ฑ)์ด ๋ง์ ๊ฒฝ์ฐ์๋ง ๋ํ๋ฉ๋๋ค. ๋๊ธฐํ ํญ๋ชฉ์ ๊ฒฝ์ฐ ๋ชจ๋ ๋์ผํฉ๋๋ค (AC์๋ ์ ์ด ํ๋ฆ์ด ์๊ธฐ ๋๋ฌธ์).
์ฐ๋ฆฌ๋ ์ด๊ฒ์ ๋์ํ์ง ์์ต๋๋ค. ๋น๋๊ธฐ ์์ ์ ์ค์ ๋ก ์ค์ํ์ง ์์ผ๋ฉฐ Redux์์ ์ฌ์ํ ์ ์์ผ๋ฏ๋ก ์ฌ๊ธฐ์์ ๊ฐ๋ฐ ๊ฒฝํ์ด ์์ต๋๋ค. ๋ณต์กํ ์์ ๊ฐ์๊ธฐ๊ฐ ๋ง์ ๋ ์ฐจ์ด๊ฐ ๋ํ๋ฉ๋๋ค. Redux์์ ์ํ A, ์ผ๋ถ ์์ ์ํ์ค, ๋ฆฌ๋์, ์ฌ์ ๋ฐ ์ํ B๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค. ๋ชจ๋ ๊ฒ์ ๋์ผํ๊ฒ ์ ์งํ์ง๋ง ์ฝ๋๋ฅผ ๋ฆฌ๋์๋ก ๋ณ๊ฒฝํ๊ณ ํซ ๋ฆฌ๋ก๋ํ๊ณ ์ํ A์์ ๋์ผํ ์์ ์ํ์ค๋ฅผ ์ฌ์ํ๋ฉด ์ํ C๋ฅผ ๊ฐ์ ธ ์์ ์ฝ๋ ๋ณ๊ฒฝ์ ์ํฅ์ ์ฆ์ ํ์ธํฉ๋๋ค. @ tomkis1 ์ ๊ทผ ๋ฐฉ์์ผ๋ก๋ ํ ์ ์์ต๋๋ค.
๊ทธ ์์ ํ ์คํธ ์๋๋ฆฌ์ค๋ฅผ ๊ตฌ์ถ ํ ์๋ ์์ต๋๋ค. ์ด๊ธฐ ์ํ๋ฅผ ์ ์ฅํ๊ณ , ์์ ์ํ์ค๋ฅผ ์ ์ฅํ๊ณ , ์์ ์ํ์ค๋ฅผ ์ํ A๋ก ์ค์ด๊ณ , ์ํ B๋ฅผ ๊ฐ์ ธ ์์ ์ฃผ์ฅํฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ ๋์ผํ ์ํ B๊ฐ ๋ ๊ฒ์ผ๋ก ์์๋๋ ์ฝ๋๋ฅผ ๋ณ๊ฒฝํ๊ณ ํ ์คํธ ์๋๋ฆฌ์ค๋ฅผ ์ฌ์ํ์ฌ ์ด๊ฒ์ด ์ฌ์ค์ด๋ฉฐ ๋ณ๊ฒฝ ์ฌํญ์ผ๋ก ์ธํด ์ฑ์ด ์ค๋จ๋์ง ์์ต๋๋ค. ๋๋ ์ด๊ฒ์ด ์ต์ ์ ํ ์คํธ ์ ๊ทผ ๋ฐฉ์์ด๋ผ๊ณ ๋งํ์ง๋ ์์ง๋ง ํ ์ ์์ต๋๋ค.
์ค์ ๋ก Haskellers์ฒ๋ผ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์ ํ๋ ์ค๋ฌด์๋ผ๊ณ ์๊ฐํ๋ Clojurists๊ฐ ๋ถ์์ฉ์ ์ต์ํ ์ด๋ ์ ๋์ ๊ตฌ์ฑ ์์ด๋ ์์ ํ ์์๋ ์ฝ๋์ ํผํฉํ๋๋ก ๊ถ์ฅํ๋ค๋ฉด ์๋นํ ๋๋ ๊ฒ์ ๋๋ค.
์ง์ฐ ํ๊ฐ / ๋ฐ์์ฑ์ ๋ค๋ฅธ ์์ํ ์ฝ๋์์ ๊ฐ๋ฅํ ํ ๋ถ์์ฉ์ด์๋ ์ฝ๋๋ฅผ ์ด๋ํ๋ ๊ธฐ๋ณธ์ ์ธ ๊ธฐ์ ์ ๋๋ค. ๊ฒ์ผ๋ฅธ ํ๊ฐ๋ ํ์ค์ผ์ด ๋ง์นจ๋ด ์ค์ฉ์ ์ด์ง ์์ ๊ธฐ๋ฅ์ ์๋ ๊ฐ๋ ์ ์ ์ฉํ์ฌ ์ค์ฉ์ ์ธ ๊ฒ์ํ๋ ํ๋ก๊ทธ๋จ์ ์ป๋ ๋ฐฉ๋ฒ์ ๋๋ค. ์์ ํ ์์ํ ํ๋ก๊ทธ๋จ์ ๋ง์ ๊ฒ์ ํ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค. ๋ชจ๋ ๋ ๊ตฌ์ฑ ๋ฐ ๊ธฐํ๋ฅผ ์ฌ์ฉํ์ฌ ์ ์ฒด ํ๋ก๊ทธ๋จ์ด ๋ฐ์ดํฐ ํ๋ฆ์ผ๋ก ์์ฑ๋๊ณ ํ์ดํ ๋ผ์ธ์ ๋ง์ง๋ง ๋จ๊ณ๋ฅผ ์์ํ๊ฒ ์ ์งํ๊ณ ์ฝ๋์์ ์ค์ ๋ก ๋ถ์์ฉ์ ํธ์ถํ์ง ์๊ธฐ ์ํด ํ๋ก๊ทธ๋จ์ ์ํํด์ผ ํ ์์ ์ ๋ํ ์ค๋ช ์ ๋ฐํํฉ๋๋ค. ๋๋ฆฌ๊ฒ ์คํ๋๋ ๋ฐํ์์ผ๋ก ์ ๋ฌ๋ฉ๋๋ค. ๋ช ๋ นํ ํธ์ถ๋ก ์คํ์ ํธ๋ฆฌ๊ฑฐํ์ง ์์ต๋๋ค. ์ ์ด๋ ๊ทธ๊ฒ์ ๋ด๊ฐ ์กฐ๊ฐ๋์์ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์ ์ดํดํ๋ ๋ฐฉ๋ฒ์ ๋๋ค. ActionCreators ๋ฐ ๋ฐ์์ฑ์ผ๋ก ์๋ฎฌ๋ ์ด์ ํ๋ ๊ทธ๋ฐ ๋ฐํ์์ด ์์ต๋๋ค. ๋ฉด์ฑ ์กฐํญ, ๊ทธ๊ฒ์ ๋น์ฐํ๊ฒ ์ฌ๊ธฐ์ง ๋ง์ญ์์ค. FP์ ๋ํด ๊ทธ๋ ๊ฒ ๋ง์ด ์ฝ์ง ์์์ ์ฌ๊ธฐ์์ ์ด๋ค ์ข ๋ฅ์ ๊ถ์๊ฐ ๋ ์ ์๋ค๊ณ ์ดํดํ์ต๋๋ค. ๋๋ ๋จ์ด์ ธ ์์์ง ๋ชจ๋ฅด์ง๋ง ์ค์ ๋ก ๋ด๊ฐ ๊ทธ ์์ ์ ์ดํดํ๋ค๊ณ ๋ฏฟ์ต๋๋ค.
๋์ผํ ์ด๋ฒคํธ ์ฒ๋ฆฌ๊ธฐ์์์ด ์ ๋ฌ ๋ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌ ํ ์์๋ ๋ฐฉ๋ฒ์ ์ดํดํ์ง ๋ชปํฉ๋๋ค.
๋๋ ๊ทธ๊ฒ์ ๋งํ๋ ๊ฒ์ด ์๋๋ค. "๋ถ์์ฉ"์ด๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ (๋ฆฌ๋์)์์ ์์๋ HTTP ์์ฒญ์ ์๋ฏธํฉ๋๋ค. IO๋ฅผ ์ํํ๋ ๊ฒ์ ํจ์ ๋ฐํ์ ์ํฅ์์ฃผ์ง ์๋๋ผ๋ ๋ถ์์ฉ์ ๋๋ค. ์ฑ๊ณต / ์ค๋ฅ ์ฒ๋ฆฌ๊ธฐ์์ ์ํ๋ฅผ ์ง์ ์์ ํ๋ ์ธก๋ฉด์์ "๋ถ์์ฉ"์ ์๋ฏธํ์ง๋ ์์ต๋๋ค.
์ด ๋ ๋ฒ์งธ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ ์์ํ๊ณ Redux ๊ฐ์๊ธฐ์ ๋์ผํ๋ฉฐ ์ฒซ ๋ฒ์งธ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ ActionCreator์ ๋์ผํฉ๋๋ค.
์ฒซ ๋ฒ์งธ๋ Action Creator์ ๋๋ฑํ๋ค๊ณ ์๊ฐํ์ง ์์ต๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์์ด ์์ ์ ์ํํ๊ธฐ ์ํด ์ก์ ํฌ๋ฆฌ์์ดํฐ๊ฐ ํ์ํฉ๋๊น? ๊ฐ์๊ธฐ์์๋ ๋๊ฐ์ด ํ ์ ์๋ค๋ฉด?
@ tomkis1 ์ ๊ทผ ๋ฐฉ์์ผ๋ก๋ ํ ์ ์์ต๋๋ค.
๋์ํ๋ค. ์ด๊ฒ์ด ์ ๊ฐ "๋ค๋ฅธ (์๋ง๋ ๋ ๊ฐ๋ ฅํ) ์ต์ "์ ์ผ์ ๋ ์๋ฏธํ๋ ๊ฒ์ ๋๋ค.
์ฒซ ๋ฒ์งธ๋ Action Creator์ ๋๋ฑํ๋ค๊ณ ์๊ฐํ์ง ์์ต๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์์ด ์์ ์ ์ํํ๊ธฐ ์ํด ์ก์ ํฌ๋ฆฌ์์ดํฐ๊ฐ ํ์ํฉ๋๊น? ๊ฐ์๊ธฐ์์๋ ๋๊ฐ์ด ํ ์ ์๋ค๋ฉด?
ActionCreators๋ ์์ ์ฑ (๋ค์ ์ฌ์ํ ์ ์์)์์ ๋ถ์์ฉ์ ๋ถ๋ฆฌํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. Redux๊ฐ ์ค๊ณ ๋์๊ธฐ ๋๋ฌธ์ ๊ฐ์๊ธฐ์์ ๋ถ์์ฉ์ ์ํ ํ ์ ์์ต๋๋ค (์๋ฉ๋๋ค). ๋ถ์์ฉ ์ฝ๋๋ฅผ ๋ฐฐ์น ํ ์์๋ ๋ ๋ค๋ฅธ ๊ตฌ์กฐ๊ฐ ํ์ํฉ๋๋ค. Redux์์ ์ด๋ฌํ ๊ตฌ์ฑ์ AC ๋๋ ๋ฏธ๋ค์จ์ด์ ๋๋ค. ๋ฆฌ ํ๋ ์์์ ๋ด๊ฐ ๋ณผ ์์๋ ์ ์ผํ ์ฐจ์ด์ ์ ๋ฏธ๋ค์จ์ด๊ฐํ๋ ์ผ๊ณผ ํธ๋ค๋ฌ๊ฐ ํธ๋ฆฌ๊ฑฐ๋๊ธฐ ์ ์ ์ด๋ฒคํธ (์ก์ )๋ฅผ ๋ณํํ๋ ๋ฏธ๋ค์จ์ด๊ฐ ์๋ค๋ ๊ฒ์ ๋๋ค.
AC / ๋ฏธ๋ค์จ์ด ๋์ ์ค์ ๋ก ์ฌ์ฉํ ์์๋ ๋ชจ๋ ๊ฒ-util ๋ชจ๋, ์๋น์ค (์ : Angular ์๋น์ค), AC ๋๋ ๋ฏธ๋ค์จ์ด๋ก ์ธํฐํ์ด์คํ๊ณ API๋ฅผ ์์ ์ผ๋ก ๋ณํํ๋ ๋ณ๋์ lib๋ก ๋น๋ ํ ์ ์์ต๋๋ค. AC๋์ด ์ฝ๋๋ฅผ ๋ฐฐ์นํ๊ธฐ์ ์ ํฉํ ์ฅ์๊ฐ ์๋๋๋ค. AC๋ ์ธ์์์ ์ก์ ๊ฐ์ฒด๋ฅผ ๊ตฌ์ฑํ๋ ๋จ์ํ ์์ฑ์ / ํฉํ ๋ฆฌ ์ผ๋ฟ์ ๋๋ค. ๋ด๊ฐ ์์ ์ฃผ์์๊ฐ๋๊ณ ์ถ๋ค๋ฉด ๋ถ์์ฉ ์ฝ๋๋ฅผ ์๊ฒฉํ๊ฒ ๋ฏธ๋ค์จ์ด์ ๋ฐฐ์นํ๋ ๊ฒ์ด ๋ซ์ต๋๋ค. ActionCreator๋ ์ผ์ข ์ ์ปจํธ๋กค๋ฌ ์ฑ ์์ ๋ํ ์๋ชป๋ ์ฉ์ด์ ๋๋ค. ๊ทธ๋ฌ๋์ด ์ฝ๋๊ฐ ํ ์ค์ง๋ฆฌ webapi ํธ์ถ์ด๋ฉด ๊ฐ๋จํ AC ๋ด๋ถ์ ๋ฃ๋ ๊ฒฝํฅ์ด ์์ผ๋ฉฐ ๊ฐ๋จํ ์ฑ์ ๊ฒฝ์ฐ ๊ด์ฐฎ์ ์ ์์ต๋๋ค.
AC, ๋ฏธ๋ค์จ์ด, ํ์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์๋น์ค ๊ณ์ธต์ด๋ผ๊ณ ๋ถ๋ฅด๋ ๊ณ์ธต์ ํ์ฑํฉ๋๋ค. ๊ธฐ์กด Facebook WebApiUtils๋ react-router๋ฅผ ์ฌ์ฉํ๊ณ ๋ณ๊ฒฝ ์ฌํญ์ ๋ฃ๊ณ Redux.state๋ฅผ ์ ๋ฐ์ดํธํ๋ ์์ ์ผ๋ก ๋ณํํ๋ ๊ฒ์ฒ๋ผ์ด ๊ณ์ธต์ ์ผ๋ถ๊ฐ๋ฉ๋๋ค. Relay๋ ์๋น์ค ๊ณ์ธต์ผ๋ก ์ฌ์ฉ๋ ์ ์์ต๋๋ค (์ฑ /๋ณด๊ธฐ์ Redux๋ฅผ ์ฌ์ฉํ๋ ๊ฒ๋ณด๋ค ์ํ). ๋๋ถ๋ถ์ ํ์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ํ์ฌ ํ๋ก๊ทธ๋๋ฐ๋์ด ์๊ธฐ ๋๋ฌธ์ ์ฌ์์ด ์๋์ง ์์ต๋๋ค. ๋ถ๋ช ํ ๋๋ โโ๋ชจ๋ ๊ฒ์ ์ฒ์๋ถํฐ ๋ค์ ์์ฑํ๊ณ ์ถ์ง ์์ต๋๋ค. ๋ด๊ฐ ์๊ฐํ๋ ๋ฐฉ๋ฒ์ ์ด๋ฌํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ, ์๋น์ค, ์ ํธ๋ฆฌํฐ ๋ฑ์ด ๋ธ๋ผ์ฐ์ ํ๊ฒฝ์ ํ์ฅํ์ฌ ์ฌ์ ๊ฐ๋ฅํ ์ฑ์ ๋น๋ ํ ์์๋ ํ๋ซํผ์ ํจ๊ป ํ์ฑํ๋ค๋ ๊ฒ์ ๋๋ค. ์ด ํ๋ซํผ์ ๋ถ์์ฉ์ผ๋ก ๊ฐ๋ ์ฐจ ์์ต๋๋ค. ์ค์ ๋ก ์ ๊ฐ ์๋์ ์ผ๋ก ๋ถ์์ฉ์ ์ฎ๊ธฐ๋ ๊ณณ์ ๋๋ค. ์ด ํ๋ซํผ API๋ฅผ ์์ ์ผ๋ก ๋ณํํ๊ณ ๋ด ์ฑ์ ์ด๋ฌํ ์์ ๊ฐ์ฒด๋ฅผ ์์ ํ์ฌ์ด ํ๋ซํผ์ ๊ฐ์ ์ ์ผ๋ก ์ฐ๊ฒฐํฉ๋๋ค (์์ ๊ฒ์๋ฌผ์์ ์ค๋ช ํ๋ ค๊ณ ํ Haskell ์ ๊ทผ ๋ฐฉ์์ ์๋ฎฌ๋ ์ด์ ํ๋ ค๊ณ ์๋ ํจ). ์ด๊ฒ์ ์์์ฑ์ ๋ฌ์ฑํ๋ ๋ฐฉ๋ฒ (์๋ง๋ ์ ๋์ ์ธ ํ๋ฌธ์ ์๋ฏธ๊ฐ ์๋ ์๋ ์์)์ ๋ฌ์ฑํ์ง๋ง ๋ถ์์ฉ์ ์ ๋ฐํ๋ ๋ฐฉ๋ฒ์ ๋ํ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์ ์ผ์ข ์ ํดํน์ ๋๋ค.
ํท๊ฐ๋ฆฌ๋ ๋ ๋ค๋ฅธ ๊ฒ์ด ์์ง๋ง ์คํด ํ ์ ์์ต๋๋ค. ๋ณต์กํ ๋ ผ๋ฆฌ์ ๊ฒฝ์ฐ ๋ชจ๋ ๊ฒ์ ํ๊ณณ์ ๋๋ ๊ฒ์ด ์ ์ตํ๋ค๊ณ ๋ง์ํ์ ๊ฒ ๊ฐ์ต๋๋ค. ๋๋ ์๋นํ ๋ฐ๋๋ผ๊ณ ์๊ฐํฉ๋๋ค.
์ด ์ ์ฒด ์ก์ ๋น์ฆ๋์ค๋ ๊ฐ๋ ์ ์ผ๋ก DOM ์ด๋ฒคํธ์ ์ ์ฌํฉ๋๋ค. ๋ด ๋น์ฆ๋์ค ์ฝ๋๋ฅผ fe ๋ธ๋ผ์ฐ์ ๊ฐ mousemove ์ด๋ฒคํธ๋ฅผ ๊ฐ์งํ๋ ์ฝ๋์ ํผํฉํ๊ณ ์ถ์ง๋ ์์ง๋ง ์ฌ๋ฌ๋ถ๋ ๋ง์ฐฌ๊ฐ์ง์ ๋๋ค. ๋คํํ๋ ๋๋ ์ด๋ฌํ ์ฑ ์์ด ์ ๋ถ๋ฆฌ๋์ด ์๊ธฐ ๋๋ฌธ์ addListener ( 'mousemove', ...) ์์์ ์์ ํ๋ ๋ฐ ์ต์ํฉ๋๋ค. ์์ ์ ๋ด ๋น์ฆ๋์ค ๋ก์ง์ ๋ํ ์ฐ๋ ค๋ฅผ ์ ๋ถ๋ฆฌํ๋ ๊ฒ์ ๋๋ค. ActionCreators, ๋ฏธ๋ค์จ์ด๋์ด๋ฅผ์ํ ๋๊ตฌ์ ๋๋ค.
๋ด ๋น์ฆ๋์ค ์๊ตฌ์ ์ ๋ง์ง ์๋ ๊ตฌ์ webapi์ ๋ํด ์ฑ์ ์์ฑํ๋ค๊ณ ์์ํด๋ณด์ญ์์ค. ํ์ํ ๋ฐ์ดํฐ๋ฅผ ์ป์ผ๋ ค๋ฉด ๋ช ๊ฐ์ ๋์ ์ ํธ์ถํ๊ณ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์ ํธ์ถ์ ๋ง๋ ๋ค์ ๋ชจ๋ ๊ฒฐ๊ณผ๋ฅผ Redux.state์์ ์ฌ์ฉํ ํ์ค ํ์์ผ๋ก ๋ณํฉํด์ผํฉ๋๋ค. ์ด ๋ ผ๋ฆฌ๋ ๋ด ๊ฐ์๊ธฐ์ ๋์ถ๋์ง ์์ผ๋ฏ๋ก ๊ฐ์๊ธฐ์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ๋ณตํด์ ๋ณํ ํ ํ์๊ฐ ์์ต๋๋ค. ๋ฏธ๋ค์จ์ด์์์ ๊ฒ์ ๋๋ค. ํจ๊ณผ์ ์ผ๋ก ๋๋ ์ง์ ๋ถํ ๊ตฌ์ API๋ฅผ ๊ฒฉ๋ฆฌํ๊ณ ๋ฉ์ง API์ ๋ํด ์์ฑ๋๋ ๋ด ๋น์ฆ๋์ค ์ฑ์ ๊ฐ๋ฐํ ๊ฒ์ ๋๋ค. ์ผ๋จ ์๋ฃ๋๋ฉด webapi๋ฅผ ๋ค์ ๋น๋ํ๊ธฐ ์ํด ๋ณ๊ฒฝ ํ ๋ค์ ๋ฏธ๋ค์จ์ด๋ฅผ ๋ค์ ์์ฑํฉ๋๋ค.
๋ฐ๋ผ์ ๋ชจ๋ ๊ฒ์ ํ๊ณณ์ ๋ชจ์ ๋๋ ๊ฒ์ ์ฌ์ด ์ฑ์ผ๋ก ๋ณด์ ๋๋ค. ๊ทธ๋ฌ๋ ๋ณต์กํ ์ผ๊ณผ๋ ์ ๋ฐ๋๋ก ์ข์ ๋ถ๋ฆฌ๊ฐ ์ ์ตํ๋ค๊ณ ์๊ฐํฉ๋๋ค. ๊ทธ๋ฌ๋ ๋น์ ์ด ์ธ๊ธ ํ ๋น์ ์ ์์ ์ด๋ ์ฌ์ฉ ์ฌ๋ก๋ฅผ ์ดํดํ์ง ๋ชปํ์ ์๋ ์์ต๋๋ค.
์ค์ ๋ก, ์๋ง๋ ๋๋ ์ผ๋ฐ์ ์ผ๋ก ์์ํ์ด ์ฝ๋์ ๋ํ ์ฌ์ ๋ฐ ํ ์คํธ ๊ฐ๋ฅ์ฑ์ ์ ๊ณตํ๊ธฐ ๋๋ฌธ์ ๋ฆฌ๋์๋ก ๋ฐ์ดํฐ ๋ณํ์ ํ์ค ํ์์ผ๋ก ์ฎ๊ธฐ๊ณ ๊ฐ์๊ธฐ ๊ตฌ์ฑ์ ๋์ ์ฌ์ฉํ ๊ฒ์ ๋๋ค.
๋์ผํ ์ด๋ฒคํธ ์ฒ๋ฆฌ๊ธฐ์์์ด ์ ๋ฌ ๋ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌ ํ ์์๋ ๋ฐฉ๋ฒ์ ์ดํดํ์ง ๋ชปํฉ๋๋ค.
๋๋ ๊ทธ๊ฒ์ ๋งํ๋ ๊ฒ์ด ์๋๋ค.
webapi ํธ์ถ์ ๊ฐ์๊ธฐ ๋ ผ๋ฆฌ์ ํผํฉํ์ฌ ํ๊ณณ์๋๊ธฐ๋ฅผ ์ํ๋ค๊ณ ์๊ฐํ์ต๋๋ค. ๋ด๊ฐ ๋งํ๋ ๊ฒ์ ์ฑ๊ณต์ ์ด๋ฒคํธ๋ฅผ ๋ฐ์กํ ๊ฒ์ ์ ์ํ๊ธฐ ๋๋ฌธ์ ๋ค์ ํ๋ ์์์ํ์ง ์๋๋ค๋ ๊ฒ์ ๋๋ค.
webapi-> ๋ง์ ๋ ผ๋ฆฌ-> webapi-> ๋ง์ ๋ ผ๋ฆฌ-> ...-> ๊ฐ์๊ธฐ์ ๋ํ ๊ฒฐ๊ณผ, ํ ๋ฒ์ ํด๋ฆญ์ผ๋ก ์ ์ฒด ์ฒด์ธ์ด ํธ๋ฆฌ๊ฑฐ๋๋ ์ํฉ์ด์์ ์ ์์ต๋๋ค. ์ด๋ฌํ ๊ฒฝ์ฐ ๋๋ถ๋ถ์ ๋ ผ๋ฆฌ๋ ์๋ง๋ AC์์์ ๊ฒ์ด๋ฉฐ ๋ชจ๋ ๋ถ์์ฉ์ด ๋๋ ๋๊น์ง ๋๋์ง ์์ ๊ฒ์ ๋๋ค. ์ด๊ฒ์ด ๋น์ ์ด ๋งํ๋ ๊ฒ์ ๋๊น?
์ฌ๊ธฐ์ ํ ์์๋ ์ต์ ์ ๋ฐฉ๋ฒ์ ํ ์คํธ ๊ฐ๋ฅ์ฑ์ ์ํด ๋ ผ๋ฆฌ๋ฅผ ์์ ํจ์๋ก ์ฎ๊ธฐ๋ ๊ฒ์ด์ง๋ง AC ๋ฒ์์์ ํธ์ถ๋ฉ๋๋ค.
๊ฐ์ ์ ์ผ๋ก ์ฐ๊ฒฐ๋ ์ผ๋ จ์ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ก ํ ์์๋ ๊ฐ๋ฅ์ฑ์ ์ข์ํ์ง ์๋๋ค๊ณ ์๊ฐํฉ๋๋ค. Promise ๋๋ Observable ์ฒด์ธ ์ผ ๊ฒ์ ๋๋ค.
๊ฒฝํ ๋ง์ Reduxers๋ ๊ทธ ์๊ฐ์ ๋ํด ๋ค๋ฅธ ์๊ฒฌ์ ๊ฐ์ง ์ ์์ต๋๋ค ( @gaearon , @johanneslumpe , @acdlite , @emmenko ...)
@vladap ๋๋์ด ๋ํ ๊ฐ์ด ๋ฌธ์ ์ ์ฃผ์ ์์ ๋๋ฌด ๋ฉ๋ฆฌ ๋จ์ด์ง ๊ฒ ๊ฐ์ต๋๋ค. ์ด๋ฏธ ์ฌ๊ธฐ์์ ๋ด ์๊ฒฌ์ ์์ ์ ์ธ๊ธํ์ต๋๋ค.
๋ฐ๋ผ์ ๋งค์ฐ ๋ณต์กํ ์๋๋ฆฌ์ค์์ AC์ ๊ฐ์๊ธฐ ์ฌ์ด์ ๋ ผ๋ฆฌ๋ฅผ ๋๊ธฐํํ๋ ๊ฒ์ด ์ด๋ ค์ธ ์ ์๋ค๊ณ ์์ํ ์ ์์ต๋๋ค.
๋น ๋ฅธ ์ :
์ํฉ 1 : ํ์ด์ง ์ด๋๊ฐ์ ์์ 10 ๋ช ์ ๋ธ๋ก๊ทธ ์์ฑ์ ๋ชฉ๋ก์ด ์์ต๋๋ค. ์ด์ ๋ธ๋ก๊ทธ์์ ๊ฒ์๋ฌผ ๋ฒ์ฃผ๋ฅผ ์ญ์ ํ์ต๋๋ค. ์ฑ๊ณต์ ์ผ๋ก ์ญ์ ๋๋ฉด ์๋ฒ์์์ด ์์ฑ์ ๋ชฉ๋ก์ ์ ๋ฐ์ดํธํ์ฌ ์ต์ ์ํ๋ก ๋ง๋ค์ด์ผํฉ๋๋ค.
์ํฉ 2 : ๋น์ ์ ๋ค๋ฅธ ํ์ด์ง์ ์์ต๋๋ค. ์์ฑ์ ๋ชฉ๋ก์ ์์ง๋ง ์์ 10 ๊ฐ ๋๊ธ ๋ชฉ๋ก์ด ์์ต๋๋ค. ๋ธ๋ก๊ทธ ๊ฒ์๋ฌผ์ ์ผ๋ถ ์นดํ ๊ณ ๋ฆฌ๋ฅผ ์ญ์ ํ ์๋ ์์ผ๋ฉฐ ์ฑ๊ณต์ ์ผ๋ก ์ญ์ ๋๋ฉด ๋๊ธ ๋ชฉ๋ก์ ์ ๋ฐ์ดํธํด์ผํฉ๋๋ค.
๊ทธ๋ ๋ค๋ฉด ์ํ ์์ง ์์ค์์ ์ด๊ฒ์ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ ๊น์? (๋ํ ๋์์ ๋ฐ๊ธฐ ์ํด React ํํฌ๋ฅผ ์ฌ์ฉํ ์ ์์ง๋ง ์ข์ ์ํ ์์ง์ ์์ฒด์ ์ผ๋ก ์ผ๊ด์ฑ์ ์ ์งํ ์ ์์ด์ผํฉ๋๋ค)
์ต์
:
A)์ด ๋
ผ๋ฆฌ๋ฅผ AC์ ๋ฃ์ต๋๋ค. ๊ทธ๋ฐ ๋ค์ AC๋ CategoryApi
(์ญ์ )๋ฅผ ํฐ์นํ๊ณ userList
์ฃผ ๋ฐ commentList
์ฃผ (ํ์ฌ ์ฃผ์์๋ ๋ชฉ๋ก ํ์ธ)๋ฅผ ์ฝ๊ณ UserListApi
์ ๋ํํฉ๋๋ค. CommentListApi
(๋ชฉ๋ก ์๋ก ๊ณ ์นจ) + TOP_AUTHORS_UPDATED
๋ฐ / ๋๋ TOP_COMMENTS_UPDATED
๋์คํจ์น. ๋ฐ๋ผ์ ๊ธฐ๋ณธ์ ์ผ๋ก 3 ๊ฐ์ ๋ค๋ฅธ ๋๋ฉ์ธ์ ํฐ์นํฉ๋๋ค.
B) ์ด๋ฒคํธ ํธ๋ค๋ฌ userList
๋ฐ commentList
๋ฃ์ต๋๋ค. ์ด๋ฌํ ํธ๋ค๋ฌ๋ ๋ชจ๋ DELETE_CATEGORY_SUCCESS
์ด๋ฒคํธ๋ฅผ ์์ ํ ๋ค์ API ์๋น์ค๋ฅผ ํธ์ถํ๊ณ TOP_AUTHORS_UPDATED
/ TOP_COMMENTS_UPDATED
์ด๋ฒคํธ๋ฅผ ์ ๋ฌํฉ๋๋ค. ๋ฐ๋ผ์ ๊ฐ ํธ๋ค๋ฌ๋ ์์ฒด ๋๋ฉ์ธ์ ์๋น์ค / ์ํ ๋ง ํฐ์นํฉ๋๋ค.
์ด ์์ ๋ ์๋ง๋ ๋๋ฌด ๋จ์ ํ ์ ์์ง๋ง,์ด ์์ค์์๋ AC์์ API ํธ์ถ์ ์ฌ์ฉํ๋ฉด ์ํฉ์ด ๋ ์๋ป์ง๋๋ค.
์ฐจ์ด์ ์ ๋ฆฌ ํ๋ ์์ ์ด๋ฒคํธ ํธ๋ค๋ฌ์ ๋ฌ๋ฆฌ ActionCreators๊ฐ ๋น์ฆ๋์ค ๋ก์ง์ ์ฌ์ ์ ์ฒ๋ฆฌํ๋ค๋ ์ฌ์ค์์ ๋น๋กฏ๋ฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ DOM ์ด๋ฒคํธ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ๋์ AC ๋ง ์คํํ ์ ์์ต๋๋ค. ์ด ์ต์์ AC๋ ๋ค๋ฅธ AC๋ฅผ ํธ์ถ ํ ์ ์์ต๋๋ค. UserListApi ๋ฐ CommentListApi์ ๋ํด ๋ณ๋์ AC๊ฐ์์ ์ ์์ผ๋ฏ๋ก ๋๋ฉ์ธ์ด ๋ ์ ๋ถ๋ฆฌ๋๋๋ก ํ ์ ์์ง๋ง ํญ์์ด๋ฅผ ์ฐ๊ฒฐํ๋ AC (์ปจํธ๋กค๋ฌ์ ๊ฐ์)๊ฐ ์์ด์ผํฉ๋๋ค. ์ด ๋ถ๋ถ์ ๊ฝค ๊ณ ์ ์ ์ธ ๋ช ๋ น ์ฝ๋์ด๋ฉฐ re-frame์ ์์ ํ ์ด๋ฒคํธ ๊ธฐ๋ฐ์ ๋๋ค. ์ฝ๊ฐ์ ์์ ์ ํตํด ์ ํธํ๋ ์ ๊ทผ ๋ฐฉ์, ์ด๋ฒคํธ ๊ธฐ๋ฐ, ๊ด์ฐฐ ๊ฐ๋ฅ ํญ๋ชฉ, cps ๋ฑ์ผ๋ก ๋์ฒด ํ ์ ์์ต๋๋ค.
@vladap ๋ค๋ฅธ ์ ๊ทผ ๋ฐฉ์์ด ์คํ ๊ฐ๋ฅํ์ง ํ์ธํ๋ ๊ฒ์ ํฅ๋ฏธ๋ก์ธ ๊ฒ์ ๋๋ค. ๋ฆฌ๋์๊ฐ ๋ถ์์ฉ์ ๊ฐ์ง ์ ์์ง๋ง ๋ฆฌํ๋ ์ด์์ ๋ฌด์ ๋ ์ ์๋๋ก ๋ถ๋ฆฌ ํ ์๋ ์์ต๋๋ค.
๊ฐ์๊ธฐ ์๋ช
์ด ๋ค์๊ณผ ๊ฐ์ด ๋ณ๊ฒฝ๋๋ค๊ณ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค. (state, action) => (state, sideEffects?)
์ฌ๊ธฐ์ sideEffects๊ฐ ํด๋ก์ ์
๋๋ค. ๊ทธ๋ฐ ๋ค์ ์ปจํ
์คํธ ํ๋ ์ ์ํฌ์ ๋ฐ๋ผ ์ด๋ฌํ sideEffect๋ฅผ ํ๊ฐํ๊ฑฐ๋ ๋ฌด์ํ ์ ์์ต๋๋ค (์ฌ์์ ๊ฒฝ์ฐ).
๊ทธ๋ฌ๋ฉด ์๋ ๋ฌธ์ ์ค๋ช ์ ์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
export default function user(state = initialState, action) {
switch (action.type) {
case LOGIN_ATTEMPT:
return [state, () => {LoginApiCall.login(action.user)}];
case LOGGED_FAILED:
// do something
return state;
case LOGGED_SUCCESSFULLY:
// do something else
return state;
default:
return state;
}
}
(๋ค๋ฅธ ๋ชจ๋ ๊ฒ์ ๊ฑฐ์ ๋์ผํ๊ฒ ์ ์ง๋ฉ๋๋ค)
์ต์ํ ์ ์ด ํ๋ฆ์ด ํ๊ณณ์ ์๊ณ ๋ถ์์ฉ์ ํญ์ ๊ฐ๋จํฉ๋๋ค (๋น๋๊ธฐ ์ฒ๋ฆฌ๊ธฐ์์ ๋ค๋ฅธ ์์ / ์ด๋ฒคํธ๋ฅผ ๋ง๋ค๊ณ ๋ก์ง์ด ๊ฐ์๊ธฐ์ ๋จ์ ์๊ธฐ ๋๋ฌธ์ ๋ ๋ง์ ์ฝ๋๊ฐ ์ฌ์๋๊ธฐ ๋๋ฌธ์ ๋๋ค).
์ผ๋ฐ FSM ๋๋ Statechart์ ์ ์ฌํ ์ฝ๋๋ฅผ ์์ฑํ ์๋ ์์ต๋๋ค (๊ฐ์๊ธฐ / ์ด๋ฒคํธ ์ฒ๋ฆฌ๊ธฐ ๊ตฌ์ฑ ํฌํจ).
๋ํ ์ก์ ์์ฑ์์์ ๋ฏธ๋ฆฌ ์ ์ ๋ ์๋ช ์ผ๋ก ํด๋ก์ ๋ฅผ ๋ฐํ ํ ํ์๊ฐ ์์ต๋๋ค.
์ด ์ ๊ทผ ๋ฐฉ์์ด ์ ์ฌ์ ์ผ๋ก ์ด๋ค ๋ฌธ์ ๋ฅผ ์ผ์ผํฌ ์ ์๋์ง๋ ํ์คํ์ง ์์ง๋ง, ๋๋ก์๋ ๊ทธ๋ด ๊ฐ์น๊ฐ ์์ต๋๋ค.
๊ฐ์๊ธฐ ์๊ทธ๋์ฒ๊ฐ ๋ค์๊ณผ ๊ฐ์ด ๋ณ๊ฒฝ๋๋ค๊ณ ๊ฐ์ ํฉ๋๋ค. (state, action) => (state, sideEffects?) ์ฌ๊ธฐ์ sideEffects๋ ํด๋ก์ ์ ๋๋ค. ๊ทธ๋ฐ ๋ค์ ์ปจํ ์คํธ ํ๋ ์ ์ํฌ์ ๋ฐ๋ผ ์ด๋ฌํ sideEffect๋ฅผ ํ๊ฐํ๊ฑฐ๋ ๋ฌด์ํ ์ ์์ต๋๋ค (์ฌ์์ ๊ฒฝ์ฐ).
์ด๊ฒ์ ์ค์ ๋ก Elm์ด (State, Action) => (State, Request?)
ํ๋ ๊ฒ๊ณผ ๋น์ทํฉ๋๋ค. ๋๋ ์์ง ์ด๋ค ์๋ ๋ณด์ง ๋ชปํ์ง๋ง ๋๊ตฐ๊ฐ ์ด๊ฒ์ ํ๊ตฌํ๊ณ ์ถ๋ค๋ฉด ์์ ๋กญ๊ฒ ๋๋ผ์ญ์์ค.
์๊ฐ์ ์ป์ ์์๋ ๋ ๋ค๋ฅธ ์ ๊ทผ๋ฒ์ Actor ๋ชจ๋ธ ( Akka Persistance , PersistentFSM) ์์ ์ด๋ฒคํธ ์์ฑ์ ๊ตฌํํ๋ ๊ฒ์ ๋๋ค. ๋๋ ๊ทธ๊ฒ์ด ๋ ๋ซ๋ค๊ณ ๋งํ์ง๋ ์์ง๋ง ๋ค๋ฅธ ์๋๋ฅผ ์๋ ๊ฒ์ด ๋์์ง ์์ต๋๋ค. ์กํฐ๋ ๋ถ์์ฉ์ ์ฌ์ฉํ ์ ์์ง๋ง ์ฌ๋ฐ๋ฅด๊ฒ ๊ธฐ์ตํ๋ ๊ฒฝ์ฐ ์ฌ์ ๋ฐฉ๋ฒ์ ๋ช ์์ ์ธ ์ฝ๋๋ก ์์ฑํด์ผํ๋ ๊ฒฝ์ฐ๊ฐ ์์ต๋๋ค.
์ฌ์ ๊ธฐ๋ฅ์ด ์ฝ๋๊ฐ ์ํ ๊ณณ์ ๊ฒฐ์ ์ ์๊ณก ํ ์ ์์ต๋๋ค. ์ฐ๋ฆฌ๊ฐ ์๊ฐํ๊ธฐ ์์ํ๋ ๊ฒ ๊ฐ์ต๋๋ค. "๋๋์ด ๋ฆฌ ํ๋ ์ด์ด ๋ธ์ ์ํ๋ฏ๋ก ๊ฐ์๊ธฐ๋ก ๊ฐ์ผํฉ๋๋ค". ์ฑ ์ / ์ญํ ์ ๋ฐ๋ผ ๋ถํ ํ์ง ์๊ณ ๋น์ฆ๋์ค ๋ก์ง์ ์ธ์์ ์ผ๋ก ๋ถํ ํ์ฌ ์ฌ์ ๊ฐ๋ฅํ๊ฒ ๋ง๋๋ ๊ฒฝํฅ์ด ์๊ธฐ ๋๋ฌธ์ ๊ฒฝ๊ณ๊ฐ ๋ช ํํ์ง ์์ ์ฝ๋๋ก ์ด์ด์ง ์ ์์ต๋๋ค.
์ฌ์ ๊ธฐ๋ฅ์ ์ ์ณ๋๊ณ ๋น์ฆ๋์ค ์ฝ๋๋ฅผ ์์ฑํ๋ ๋ฐฉ๋ฒ์ ๋ฌด์์ ๋๊น? ๋๋ ๋ด ๋น์ฆ๋์ค ๋ก์ง์ ์ก์ ๋ก๊ทธ ์์๋๊ณ ํ๊ณณ์ ๋๋ ๊ฒ์ ๋ชฉํ๋กํฉ๋๋ค. ๋น์ฆ๋์ค ๋ก์ง ์ํ ๋จธ์ ๋๋ ๋ด๊ฐ ์ฌ์ฉํ๋ ๋ชจ๋ ๊ฒ์ ๋ณต์กํ ๊ฒฐ์ ์ ๋ชจ๋ ์ํํ์ฌ ์ด๋ฏธ ํด๊ฒฐ ๋ FACTS (์ก์ ) ์คํธ๋ฆผ์ ์์ฑํฉ๋๋ค. Reducer๋ ์ผ๋ฐ์ ์ผ๋ก ๊ฐ๋จํ ์ ๋ฐ์ดํธ ํ๋ก๊ทธ๋จ์ด๋ฉฐ ์ฃผ์ ์ฑ ์์ Redux.state์ ์์ ํ์ด๋ก๋๋ฅผ ์ ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋๋ค. ๊ทธ๋ค์ ๋ช ๊ฐ์ง ๋ ผ๋ฆฌ๋ฅผ ๊ฐ์ง ์ ์์ง๋ง ์ฌ์ค์ ๋ค๋ฅด๊ฒ ํด์ํ์ฌ ์ฌ์ค (์ก์ ) ์คํธ๋ฆผ์ ๋ํ ๋ ๋ค๋ฅธ ์ข ๋ฅ์ ๊ด์ ์ ์ป์ด ์ฌ์ฉ์์๊ฒ ์ ๊ณต ํ ์ ์์ต๋๋ค.
์ฑ ์์ ๋ถ๋ดํ๊ธฐ ์ํด ์ ๋ ์ด๋ฐ ์์ผ๋ก ์๊ฐํ๊ณ ์ถ์ต๋๋ค. ์๋ฒ์์ ์ฌ ๊ตฌํํ๊ธฐ ์ํด ์ ์ฌ์ ์ผ๋ก ์ด๋ค ์ฝ๋๋ฅผ ์์ฒญํ ์ ์์ต๋๊น? Fe๋ ๊ณ์ฐ ๋น์ฉ์ด ๋ง์ด ๋๋ ๋น์ฆ๋์ค ๋ ผ๋ฆฌ, ๋ณด์์์ ์ด์ , ์ธํ ๋ฆฌ์ ์ค ์์ฑ์ ์จ๊ธฐ๋ ๋ฐฉ์์ผ๋ก ๋๋ฆฐ ์ฅ์น๋ฅผ ๋ ์ ์ง์ํฉ๋๋ค. ๋ทฐ ๋ ์ด์ด์ ๋ฐ์ธ๋ฉ๋์ด ์๊ธฐ ๋๋ฌธ์ ๋ฆฌ๋์์์ ์๋ฒ๋ก ๋ก์ง์ ์ฝ๊ฒ ์ด๋ํ ์ ์์ต๋๋ค. ๋ณต์กํ ๋น์ฆ๋์ค ๋ก์ง์ด ์์ ๋ก๊ทธ ์์ ์์ฑ๋๋ฉด ๋์ผํ ์์ ์คํธ๋ฆผ์ผ๋ก ๋ณํ๋๋ REST ํธ์ถ๋ก ๋์ฒด ํ ์ ์์ผ๋ฉฐ ๋ด ๋ทฐ ๋ ์ด์ด๊ฐ ์๋ํด์ผํฉ๋๋ค (์๋ง๋).
๋จ์ ์ Akka Persistance์ ๋ฌ๋ฆฌ์ด ์ฝ๋๋ฅผ ์ฌ์ํ๋ ๋ฐฉ๋ฒ์ด ์๋ค๋ ๊ฒ์ ๋๋ค.
์ธ์ ๊ฐ๋ Elm์ ๋ํด ์์ธํ ์ดํด๋ณด๊ณ ๊ทํ์ ์ ์์ด ์ด๋ป๊ฒ ์๋ํ๋์ง ์ดํดํด์ผํฉ๋๋ค.
@gaearon Elm์ //gist.github.com/evancz/44c90ac34f46c63a27ae- ๋น์ทํ ์์ด๋์ด (ํ์ง๋ง ํจ์ฌ ๋ ๊ณ ๊ธ).
์์ (http, db ๋ฑ) ๋ฐ ํจ๊ณผ (์์ ๋๊ธฐ์ด)์ ๊ฐ๋ ์ ์๊ฐํฉ๋๋ค. ๋ฐ๋ผ์ "๋ฆฌ๋์"๋ ์ค์ ๋ก ์๋ก์ด ์ํ์ ํจ๊ณผ๋ฅผ ๋ฐํ ํ ์ ์์ต๋๋ค.
์ด๊ฒ์ ๋ํ ๋ฉ์ง ์ ์ (๊ทธ๋ฆฌ๊ณ ์ ๋ ์ด๋ฐ ์์ผ๋ก ์๊ฐํ์ง ์์์ต๋๋ค)-๊ฐ์๊ธฐ๋ฅผ ์ฐ๊ฒฐํ๋ฉด์ ์์ ์ ์์ง ํ ์ ์๋ค๋ฉด-๋์ค์์ด ๋ชฉ๋ก์ ์ผ๋ถ ๊ธฐ๋ฅ์ ์ ์ฉ ํ ์ ์๋ค๋ ๊ฒ์ ๋๋ค. http ์์ฒญ์ ์ผ๊ด ์ฒ๋ฆฌํ๊ณ DB ์ฟผ๋ฆฌ๋ฅผ ํธ๋์ญ์ ์ผ๋ก ๋ํ ํ ์ ์๋ค๊ณ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค.
๋๋ ํจ๊ณผ์ ๋ํ ๋ฉ์ฒญ์ด ์ธ "์ฌ์ ๊ด๋ฆฌ์"๋ผ๊ณ ๋งํ ์ ์์ต๋๋ค.
@merk ๋๋ ๋๋ถ๋ถ์ด ์ด๋ฏธ ์์ฑ๋์๋ค๊ณ ์๊ฐํฉ๋๋ค. ์ด๋ฐ ์ข ๋ฅ์ ์์จ์ ์ธ ๋ถ์์ฉ ์ฝ๋๊ฐ ์๋ง๋ ๊ฐ์ฅ ๊น๋ค๋ก์ธ ๊ฒ์ ๋๋ค. ์๊ฐ ์ฌํ์ด ๋์ผํ ์ฝ๋์์ ์คํ๋๊ณ ๊ฐ๊ฒฉ์ด ์ฌ์ ๋ชจ๋์์๋ ์์๋๋ค๊ณ ๊ฐ์ ํ๋ฉด ๊ฐ๊ฒฉ์ด ์๊ฐ ์ฌํ๊ณผ ๋๊ธฐํ๋์ง ์๊ธฐ ๋๋ฌธ์ ์ฌ์์ ํผ๋์ ์ผ์ผํฌ ์ ์์ต๋๋ค.
์ผ๋ฐ์ ์ธ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฌ์ฉ์์๊ฒ ์ ๊ณต๋๋ ํ ํฐ ๋ฐ ๋ง๋ฃ ์นด์ดํธ ๋ค์ด์ด ํ์ํ์ง ์์ผ๋ฏ๋ก ๊ธฐ์ ์ ์ผ๋ก Redux.state์์์ ํ์๊ฐ ์์ต๋๋ค. ๊ด๋ฆฌ์ ์ฑ์ ํ์ํ ์ ์์ต๋๋ค. ๋ฐ๋ผ์ ์์ ์๊ฒ ๋ง๋ ๋ฐฉ์์ผ๋ก ๊ตฌํํ ์ ์์ต๋๋ค.
ํ ๊ฐ์ง ์ต์ ์ ๋ก๊ทธ์ธ AC์์ ๋ง๋ฃ ์นด์ดํธ ๋ค์ด์ ์์ํ๋ ๊ฒ์ด๋ฉฐ ๋์์ด ์คํ๋๊ณ ์ฑ๊ณผ ํจ๊ป ์ฃฝ๊ฑฐ๋ ๋ก๊ทธ ์คํ๊ฐ์ด๋ฅผ ์ ๋ฆฌํด์ผํ๋ค๊ณ ๊ฐ์ ํฉ๋๋ค. ๊ฐ๊ฒฉ์ด ํธ๋ฆฌ๊ฑฐ๋๋ฉด ํ ํฐ์ ํ์ธํ๋ ๋ฐ ํ์ํ ์์ ์ ์ํํ๊ณ ๋ง๋ฃ๋๋ฉด LOGIN_EXPIRED ์์ ์ ์ ๋ฌํ๊ณ ์์ ๊ฐ์๊ธฐ๊ฐ ์ฌ์ฉ์ ์ธ์ ์ ์ง์ฐ๊ณ ์์น๋ฅผ ๋ณ๊ฒฝํ์ฌ ๋ผ์ฐํฐ ์ ํ์ / login์ผ๋ก ํธ๋ฆฌ๊ฑฐํฉ๋๋ค.
๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ํ์ฌ lib๋ฅผ ์ฌ์ฉํ๊ณ ์ด์ ๋ํ ์ฐ๋ ค๋ฅผ ์์ํ๊ณ ํด๋น API๋ฅผ LOGIN_EXPIRED ์์ ์ผ๋ก ๋ณํํ๋ ๊ฒ์ ๋๋ค. ๋๋ ๋ทฐ ๋ ์ด์ด์์ ํ์ํ์ง ์์ ๊ฒฝ์ฐ ์ง์ ์์ฑํ๊ณ ์ฌ๊ธฐ์ ํ ํฐ ๋ฐ ์นด์ดํธ ๋ค์ด ์ํ๋ฅผ ์ ์งํฉ๋๋ค.
Redux.state์ ์ ์งํ ์ ์์ง๋ง์ด ์ํ๋ ํ๋ฐ์ฑ์ ๋๋ค. ํฐ ์ํ์์ ์ฐ๋ฆฌ๋ ์ ์ญ ๋ณ์๋ฅผ ์ฌ์ฉํ ํ๋ก๊ทธ๋๋ฐ๊ณผ ๋์ผํ ๋ฌธ์ ์ ๋๋ฌ ํ ์ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ๊ทธ๊ฒ์ ํ ์คํธํ๋ ๊ฒ์ ์ด๋ ต๊ณ ์๋ง๋ ๋ถ๊ฐ๋ฅํ ๊ฒ์ ๋๋ค. ๋ฆฌ๋์๋ฅผ ํ ์คํธํ๋ ๊ฒ์ ์ฝ์ง๋ง ํ ๋ฆฌ๋์ ๋ง ์ํ ๊ฐ์ฒด์ ํน์ ํค๋ฅผ ์ ๋ฐ์ดํธ ํ ๋ ์๋ํ๋ค๋ ๊ฒ์ ์ฆ๋ช ํฉ๋๋ค. ์ด๊ฒ์ ๋ค๋ฅธ ์์ง์ ๊ฐ๋ฐ์๊ฐ ๋ง์ ๋๊ท๋ชจ ํ๋ก์ ํธ์์ ๋๋น ์ง ์ ์์ต๋๋ค. ๋๊ตฌ๋ ๋ฆฌ๋์๋ฅผ ์์ฑํ๊ธฐ๋ก ๊ฒฐ์ ํ ์ ์๊ณ ์ํ์ ์ผ๋ถ๊ฐ ์ ๋ฐ์ดํธํ๊ธฐ์ ์ข๋ค๊ณ ์๊ฐํ ์ ์์ผ๋ฉฐ ๊ฐ๋ฅํ ๋ชจ๋ ์ ๋ฐ์ดํธ ์ํ์ค์์ ๋ชจ๋ ๋ฆฌ๋์๋ฅผ ํจ๊ป ํ ์คํธํ๋ ๋ฐฉ๋ฒ์ ์์ํ ์ ์์ต๋๋ค.
์ฌ์ฉ ์ฌ๋ก์ ๋ฐ๋ผ์ด ์ํ๋ ๋ก๊ทธ์ธ์ด๊ธฐ ๋๋ฌธ์ ๋ณดํธํ๋ ๊ฒ์ด ํฉ๋ฆฌ์ ์ผ ์ ์์ต๋๋ค. ๋งค์ฐ ์ค์ํ ๊ธฐ๋ฅ์ด๋ฉฐ ๋ถ๋ฆฌ๋์ด ์์ต๋๋ค. ์ด ์ํ๊ฐ ๋ทฐ ๋ ์ด์ด์ ํ์ํ ๊ฒฝ์ฐ ๋ฐ์ ๋ผ์ฐํฐ ์์น ์ํ๊ฐ ์ฃผ๋ณ์ ์ผ๋ถ ์์์ Redux.state์ ๋ณต์ ๋๋ ๊ฒ๊ณผ ์ ์ฌํ ๋ฐฉ์์ผ๋ก Redux.state์ ๋ณต์ ํฉ๋๋ค. ๋น์ ์ ์ฃผ์ ํ์ด ์๊ณ ์ ํ๋ํ๋ค๋ฉด ํ๊ณณ์ ๋๋ ๊ฒ์ด ์ข์ต๋๋ค.
ํธ์ ๋ด์ ๊ฐ๊ธฐ
์, ๊ทธ ๋๋ฆ ๋๋ฌด ์์ ์ ์ ๋ง ๋ฉ์ ธ์! ๋ํ Cycle.js "๋๋ผ์ด๋ฒ"์ํคํ ์ฒ๋ฅผ ์๊ฐ ๋๊ฒํฉ๋๋ค.
@merk ์ฌ์ค, ์์จ LOGIN_EXPIRED๋ ๋ฆฌํ๋ ์ด์ ํฐ ์ํฅ์์ฃผ์ง ์์ ๊ฒ์ ๋๋ค. ์๋ํ๋ฉด ๊ทธ๊ฒ์ ์ก์ ๋ก๊ทธ์ ๋์ ๋ค์ด๊ฐ์ ๋ฆฌํ๋ ์ด์ ์ํด ์ฆ์ ์ฒ๋ฆฌ๋์ง ์์ ๊ฒ์ด๊ณ ์๋ง๋ ์ก์ ๋ก๊ทธ์ ์ ํ ๋์ฐฉํ์ง ์์ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ๋๋ค.-๋ชจ๋ฅด๊ฒ ์ต๋๋ค. ์ฌ์์ด ์ ํํ ์ด๋ป๊ฒ ๊ตฌํ๋๋์ง.
@gaeron ์์ ์์ค์์ Elm๊ณผ Cycle์ด ์ฌ๋ฐ๋ฅด๊ฒ ์ดํดํ๋ฉด ์ค๋ช ํ๋ ค๋ ํจํด์ ๊ตฌํํ๋ ๊ฒ ๊ฐ์ต๋๋ค. ๊ธฐ๋ณธ ํ๋ซํผ์ ์ ๊ณตํ๋ ๋ธ๋ผ์ฐ์ ๊ฐ ์์ต๋๋ค.์ด ํ๋ซํผ์ ์๋น์ค ๊ณ์ธต (http, db ...)์ผ๋ก ํ์ฅํ์ฌ ์ฑ์ฉ ํ๋ซํผ์ ๊ตฌ์ถํฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ ์๋น์ค ๊ณ์ธต๊ณผ ์ํธ ์์ฉํ๊ณ ์์ํ ์ฑ์ด ๊ฐ์ ์ ์ผ๋ก ํต์ ํ ์ ์๋๋กํ๋ ์ผ์ข ์ ์ ์ฐฉ์ ๊ฐ ํ์ํ๋ฏ๋ก ๋ด ์ฑ์ด ์ํ๋ ์์ ์ ์ค๋ช ํ ์ ์์ง๋ง ์ค์ ๋ก ์คํํ์ง๋ ์์ต๋๋ค (Cycle ๋๋ผ์ด๋ฒ๋ก ์ ์ก ๋ ๋ฉ์์ง, Elm Effects ์์ ๋ชฉ๋ก ํฌํจ). ๋ด ์ฑ์ด ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ์ฌ "ํ๋ก๊ทธ๋จ"์ ๋น๋ํ๊ณ ์๋ค๊ณ ๋งํ ์ ์์ต๋๋ค (๋ฐ์ดํฐ ๋งํธ๋ผ๋ก ์ฝ๋์ ๋ํด ์๊ธฐ์์ผ์ค๋๋ค). ๊ทธ๋ฐ ๋ค์ ์คํ์ ์ํด ์๋น์ค ๊ณ์ธต์ผ๋ก ์ ๋ฌ๋๊ณ ๋ด ์ฑ์์ด "ํ๋ก๊ทธ๋จ"์ ๊ฒฐ๊ณผ์๋ง ๊ด์ฌ์ด ์์ต๋๋ค. ๊ทธ ์ํ๋ก.
@merk : ๋. ํ ํฐ ๋ฐ ๋ง๋ฃ๊ฐ Redux.state / ๋๋ ๋ค๋ฅธ js ์๋น์ค์ ์ด๋ ๊ณณ์ ๋ ๋ฐฐ์น๋๋ ๊ฒฝ์ฐ ์ฌ์ฉ์๊ฐ ์ ํญ์์ ์ฑ์ ์ด ๋ ์ ์ก๋์ง ์์ต๋๋ค. ์ฌ์ฉ์๊ฐ ๋ก๊ทธ์ธ ์ํ๋ฅผ ์ ์งํ๊ธฐ๋ฅผ ๊ธฐ๋ํฉ๋๋ค. ๊ทธ๋์ ์ ๋์ด ์ํ๊ฐ ์ค์ ๋ก SessionStore์ ์์ด์ผํ๋ค๊ณ ๊ฐ์ ํฉ๋๋ค.
๊ทธ๊ฒ ์์ด๋ ํ ํฐ ๋ง๋ฃ๊ฐ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ฆ์ ์ ๋ฆฌํ๊ณ / login์ผ๋ก ์ ํํ๋ ๊ฒ์ ์๋ฏธํ์ง ์์ ๋ ์ํ๊ฐ ๋ถ๋ฆฌ ๋ ์ ์์ต๋๋ค. ์ฌ์ฉ์๊ฐ ์ํธ ์์ฉ์ ํตํด ์๋ฒ๋ฅผ ๋ง์ง์ง ์์ ๋๊น์ง (์บ์ ๋ ๋ฐ์ดํฐ๊ฐ ์ถฉ๋ถ ํจ) ๊ณ์ ์์ ํ ์ ์์ผ๋ฉฐ LOGIN_EXPIRED ์์ ์ ์๋ฒ๊ฐ ํ์ํ ์์ ์ ์ํ ํ ํ์ ๋ง โโํธ๋ฆฌ๊ฑฐ๋ฉ๋๋ค. Redux.state๋ฅผ ๊ธฐ๋ฐ์ผ๋กํ๋ isLogged ์ํ๋ ์ ํจํ ํ ํฐ์ด ์กด์ฌ ํจ์ ์๋ฏธ ํ ํ์๊ฐ ์์ต๋๋ค. Redux.state์ isLogged ์ํ๋ ๋ ๋๋ง ํ ํญ๋ชฉ์ ๊ฒฐ์ ํ๋ ๋ฐ ์ฌ์ฉ๋๋ฉฐ, ํ ํฐ ์ฃผ๋ณ์ ์ํ๋ ๋ทฐ ๋ ์ด์ด์ ์จ๊ฒจ ์ง ์ ์์ผ๋ฉฐ ๋ทฐ ๋ ์ด์ด์ ์ํฅ์์ฃผ๋ ๊ฒ์ ์ ์ธํ๊ณ ์ก์ ๊ณผ ๋ฆฌ๋์๋ฅผ ์์ฑํ์ง ์๊ณ ๋ ์ก์ ์์ฑ์ ์์ค์์๋ง ์ ์ง๋ฉ๋๋ค.
@vladar ๋๋ ๋น์ ์ ์ผ๋ฐ์ ์ธ ์์ ์ ์ป์ ์ ์๋ค๊ณ ์๊ฐํฉ๋๋ค. ๋๋ ๊ทธ๊ฒ์ ์ ์ ๊นจ๋ซ์ง ๋ชปํ ๊ฒ ๊ฐ์ต๋๋ค.
๊ฐ์๊ธฐ์์ ์์ ์์ฑ์์๊ฒ ์ ์ด๋ฅผ ๋ฐํํ๊ณ ์ผ๋ถ ๊ฐ์ ์ ๋ฌํ๋ ๋ฐฉ๋ฒ์ ์ฝ์ง ์์ต๋๋ค. ์ด๋ฌํ ๊ฐ์ ๋ ๋๋ง์ ํ์ํ์ง ์๊ณ ์ผ์์ ์ด์ง๋ง ๋น๋๊ธฐ ์์ ์ ์์ํ๋ ๋ฐ ํ์ํ๋ค๊ณ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค.
actionCreator() {
... getState
... some logic L1
... dispatch({ACTION1})
}
reducer() {
case ACTION1
... some logic L2
... x, y result from L2
... some logic L3
... resulting in new state
... return new state
}
๊ฐ์๊ธฐ์์ ๊ณ์ฐ ๋ x, y๋ฅผ ์ฌ์ฉํ์ฌ ๋น๋๊ธฐ ์์ ์ ์์ํ๋ ๋ฐฉ๋ฒ์๋ 3 ๊ฐ์ง ์ต์ ์ด ์์ต๋๋ค. ๊ทธ๋ค ์ค ์ด๋ ๊ฒ๋ ์๋ฒฝํ์ง ์์ต๋๋ค.
1) ๊ฐ์๊ธฐ์์ ์ก์ ์์ฑ๊ธฐ๋ก ๋ก์ง์ ์ด๋ํ๊ณ ํซ ๋ฆฌ๋ก๋์ ํ์ ์ค์ ๋๋ค. Reducer๋ ๋ฉ์ฒญํ ์ํ ์ ๋ฐ์ดํธ ํ๋ก๊ทธ๋จ์ด๊ฑฐ๋ ๋ ผ๋ฆฌ L3 ์ด์์ ๋๋ค.
2) x, y๋ฅผ Redux.state์ ์ ์ฅํ๊ณ ์์ / ์ผ์์ ์ธ ๊ฐ์ผ๋ก ์ค์ผ์ํค๊ณ ๊ธฐ๋ณธ์ ์ผ๋ก ๊ฐ์๊ธฐ์ ์ก์ ์ ์์ ์ฌ์ด์ ๊ธ๋ก๋ฒ ์ปค๋ฎค๋์ผ์ด์ ์ฑ๋๋ก ์ฌ์ฉํฉ๋๋ค. ์ค์ ์ํ๋ผ๋ฉด ๊ด์ฐฎ๋ค๊ณ ์๊ฐํ์ง๋ง ์ด๋ฐ ๊ฐ์น๊ด์ ์๋๋๋ค. ์ก์ ์ ์์๊ฐ ๋ค์์ผ๋ก ๋ณ๊ฒฝ๋ฉ๋๋ค.
actionCreator() {
... getState
... some logic L1
... dispatch({ACTION1})
// I assume I get updated state if previous dispatch is sync.
// If previous dispatch is async it has to be chained properly.
// If updated state can't be received here after a dispatch
// then I would think there is a flaw.
... getState
... asyncOperation(state.x, state.y)
}
3) x, y๋ฅผ ์ํ๋ก ์ ์ฅํ๊ณ ์ผ๋ถ ๊ตฌ์ฑ ์์์์ ์ํ์ผ๋ก ์ฌ์ฉํ๊ณ componentWillReceiveProps๋ฅผ ์ฌ์ฉํ์ฌ ์ ์ฒด ๋ทฐ ๋ ์ด์ด ๋ฃจํ๋ฅผ ํตํด ํฐ๋๋งํ์ฌ ์ ์์ ์์ฑ์์ ๋น๋๊ธฐ ์์ ์ ํธ๋ฆฌ๊ฑฐํฉ๋๋ค. ๋ด๊ฒ ๋ฌป๋๋ค๋ฉด ์ต์ ์ ์ต์ ์ ๋น์ฆ๋์ค ๋ก์ง์ ์ฌ๋ฐฉ์ผ๋ก ํผ๋จ๋ฆฌ๋ ๊ฒ์ ๋๋ค.
๋ธ๋ผ ๋ค๋ฅด
์ผ๋ฐ์ ์ผ๋ก์ด ์์
์ ๊ฒฐ๊ณผ๊ฐ ์์
์ผ๋ก ์์ถ๋๊ณ ๊ฐ์๊ธฐ์ ์ํด ์ ๋ฌ ๋ฐ ์ ์ฉ๋๋ ํ ๋น๋๊ธฐ๊ฐ ์์๋๋ ์์น๋ ์ค์ํ์ง ์์ต๋๋ค. ๋์ผํ๊ฒ ์๋ํฉ๋๋ค. ์ก์
์์ฑ ์๋ ์์ ์์ ๋น๋๊ธฐ๋ฅผ ์์ํด์ผํ๋ ๊ฒฝ์ฐ ๋ฐ๋๋ผ ํ๋ญ์ค์ ๋์ผํ ๋
ผ์์
๋๋ค.
Redux๊ฐ ์ฌ์์ ์ด๋ฌํ ๋น๋๊ธฐ ํธ์ถ์ ์๋ณํ๊ณ ๋ฌด์ํ ์ ์์ด์ผํฉ๋๋ค.
๊ฐ์๊ธฐ์์ ์์ ์์ฑ์์๊ฒ ์ ์ด๋ฅผ ๋ฐํํ๊ณ ์ผ๋ถ ๊ฐ์ ์ ๋ฌํ๋ ๋ฐฉ๋ฒ์ ์ฝ์ง ์์ต๋๋ค.
์ด๊ฒ์ด ์ฆ์ ์ค ํ๋๋ผ๊ณ ๋งํ๊ณ ์ถ์ต๋๋ค. ๋ ๋ฒ์งธ ์๋ ๋ด ๊ด์ ์ ๋งค์ฐ ์ ๋ณด์ฌ์ค๋๋ค (์๋ ์ฐธ์กฐ).
์ผ๋ฐํ ๋ ์ํ ์ ํ ํ๋ฆ์ ๊ณ ๋ คํ์ญ์์ค (FSM ์ธ๊ณ์์) :
ํ์ฌ ์ํ๊ฐ ์ค์ํฉ๋๋ค! ๋์ผํ ์ด๋ฒคํธ๋ ํ์ฌ ์ํ์ ๋ฐ๋ผ ๋ค๋ฅธ ๊ฒฐ๊ณผ๋ก ์ด์ด์ง ์ ์์ต๋๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก 3 ๋จ๊ณ์์ ๋ค๋ฅธ ์์ ์ํ์ค (๋๋ ์ธ์)๊ฐ ๋ฐ์ํฉ๋๋ค.
๋ฐ๋ผ์ ์ด๊ฒ์ ์ก์ ์ด ๋๊ธฐํ ๋ ๋ Flux์์ ์ํ ์ ํ์ด ์๋ํ๋ ๋ฐฉ์์ ๋๋ค. ๊ฐ์๊ธฐ / ์ ์ฅ์๋ ์ค์ ๋ก FSM์ ๋๋ค.
๊ทธ๋ฌ๋ ๋น๋๊ธฐ ์์ ์ ์ด๋ป์ต๋๊น? ๋น๋๊ธฐ ์์ ์ ์ฌ์ฉํ๋ ๋๋ถ๋ถ์ Flux ์์ ๋ ๋ฐ์ ๋ ๊ฒ์ผ๋ก ์๊ฐํ๊ฒํฉ๋๋ค.
๋ฐ๋ผ์ ํ์ฌ ์ํ๋ ๋ฌด์๋๊ณ ๋์ ์ํ๋ ํญ์ ๋์ผํ ๊ฒ์ผ๋ก ๊ฐ์ฃผ๋ฉ๋๋ค. ์ค์ ๋ก ์ผ๊ด๋ ์ํ ์ ํ ํ๋ฆ์ ์ฌ์ ํ โโ๋์ผํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ๋ค์๊ณผ ๊ฐ์์ผํฉ๋๋ค (AC ํฌํจ).
๋ ๋ฒ์งธ ์์ ๋๋ค. ์ด ๋ชจ๋ ๋จ๊ณ๊ฐ ํญ์ ํ์ํ๋ค๋ ๊ฒ์ ์๋๋๋ค. ์ข ์ข ์ผ๋ถ๋ฅผ ์๋ต ํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๋ณต์กํ ๊ฒฝ์ฐ์๋ ๊ทธ๋ ๊ฒ ํ๋ํด์ผํฉ๋๋ค. ๋ชจ๋ ์ํ ์ ํ์ ์ผ๋ฐํ ๋ ํ๋ฆ์ ๋๋ค. ๋ํ FSM์ ๊ฒฝ๊ณ๊ฐ AC ๋ ๊ฐ์๊ธฐ / ์ ์ฅ์๋ก ์ด๋ํ์์ ์๋ฏธํฉ๋๋ค.
๊ทธ๋ฌ๋ ๊ฒฝ๊ณ๋ฅผ ์ด๋ํ๋ฉด ๋ค๋ฅธ ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค.
๋๋ถ๋ถ์ ๋ฌธ์ ๋ ๋๋ถ๋ถ์ ์น ์ฑ์ ๊ฐ๋จํ ์ํ ์๊ตฌ ์ฌํญ์ ์ํด ์จ๊ฒจ์ ธ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๋ณต์กํ ์ํ ์ ์ฅ ์ฑ์ด์๋ ๊ฒฝ์ฐ ์ด๋ฌํ ์ํฉ์ ํ์คํ ์ง๋ฉดํ๊ฒ๋ฉ๋๋ค.
๋๋ถ๋ถ์ ๊ฒฝ์ฐ ๋ชจ๋ ์ข ๋ฅ์ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ์ฐพ์ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ์ํ ์ ํ ๋ ผ๋ฆฌ๊ฐ ๋ ์ ์บก์ํ๋๊ณ FSM์ด AC์ ๊ฐ์๊ธฐ๊ฐ์ ๋ถ๋ฆฌ๋์ง ์์ ๊ฒฝ์ฐ ์ฒ์๋ถํฐ์ด๋ฅผ ํผํ ์ ์์ต๋๋ค.
๋ถํํ๊ฒ๋ ์ํ ์ ํ์ "๋ถ์์ฉ"๋ถ๋ถ์ ์ฌ์ ํ โโ์ํ ์ ํ์ ์ผ๋ถ์ด๋ฉฐ ๋ณ๋์ ๋
๋ฆฝ์ ์ธ ๋
ผ๋ฆฌ ๋ถ๋ถ์ด ์๋๋๋ค. ๊ทธ๋์ (state, action) => (state, sideEffects)
์ด ๋ ์์ฐ์ค๋ฝ๊ฒ ๋ณด์
๋๋ค. ์, ๋ ์ด์ "๊ฐ์"์๋ช
์ด ์๋๋๋ค. %)ํ์ง๋ง ํ๋ ์ ์ํฌ์ ๋๋ฉ์ธ์ ๋ฐ์ดํฐ ๋ณํ์ด ์๋๋ผ ์ํ ์ ํ์
๋๋ค.
์ก์ ์์ฑ ์๋ ์์ ์์ ๋น๋๊ธฐ๋ฅผ ์์ํด์ผํ๋ ๊ฒฝ์ฐ ๋ฐ๋๋ผ ํ๋ญ์ค์ ๋์ผํ ๋ ผ์์ ๋๋ค.
์, ๊ทธ๋ฌ๋ Flux๋ ๋น๋๊ธฐ ์ฝ๋ฐฑ์์ dispatch ()๋ฅผ ์ง์ ์ ์ผ๋ก ๋ณ๊ฒฝํ๋ ํ ์คํ ์ด์ ๋น๋๊ธฐ ํญ๋ชฉ์ ๊ฐ๋ ๊ฒ์ ๊ธ์งํ์ง ์์ต๋๋ค. ๋๋ถ๋ถ์ ๊ตฌํ์์ ๋น๋๊ธฐ๋ฅผ ์ํด AC๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ๊ฐ์ธ์ ์ผ๋ก ๋๋ ๊ทธ๊ฒ์ด MVC์ ํ์์ด๋ผ๊ณ ์๊ฐํ๋ค. ์๋ํ๋ฉด AC๋ฅผ ์ปจํธ๋กค๋ฌ๋ก ์ทจ๊ธํ๋ ๊ฒ๋ณด๋ค ์ ์ ์ ์ผ๋ก FSM์ผ๋ก ์ ํํ๋ ๊ฒ์ด ์ ์ ์ ์ผ๋ก ํธ๋ฆฌํ๊ธฐ ๋๋ฌธ์ด๋ค.
๋ธ๋ผ ๋ค๋ฅด
(state, action) => (state, sideEffects)
๊ทธ๋ฅ ์๊ฐ. ์ฆ, combineReducers ํจ์์ ๋ฐํ ์ ํ์ [state, SideEffects] ๋๋ [state, [SideEffects]]๋ก ๋ณ๊ฒฝํ๊ณ ๋ฆฌ๋์์ SideEffect๋ฅผ ๊ฒฐํฉํ๋๋ก ์ฝ๋๋ฅผ ๋ณ๊ฒฝํด์ผํฉ๋๋ค. ์๋ (์ํ, ์กฐ์น) => ์ํ ๊ฐ์๊ธฐ ์ ํ์ ๊ณ์ ์ง์ ๋ ์ ์์ต๋๋ค. ์ด๋ combineReducer๊ฐ ์ ํ์ [์ํ] ๋๋ [์ํ, []]๋ก ๊ฐ์ (์ํ) ๋ฆฌํดํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
๊ทธ๋ฐ ๋ค์ Redux ์ด๋๊ฐ์ SideEffect๋ฅผ ์คํํ๊ณ ์ ๋ฌํด์ผํฉ๋๋ค. ์๋ก์ด ์ํ๋ฅผ ์ ์ฉํ๊ณ SideEffects ๋ชฉ๋ก์ ์คํํ๊ณ ๋์คํจ์นํ๋ Store.dispatch ()์์ ์ํ ํ ์ ์์ต๋๋ค. ๋๋ ์ฐ๋ฆฌ๊ฐ ๋ฉ์ง ๋์๋ ์ฌ๊ท์ ๋ค์ด๊ฐ ์ ์๋์ง ์๊ฐํ๊ณ ์์ต๋๋ค.
๋๋ ๋ฏธ๋ค์จ์ด ์์ค์ ์ด๋๊ฐ์์ ์คํ๋ ์ ์์ง๋ง Store.dispatch๊ฐ ์์ ๊ณผ ํจ๊ป SideEffects ๋ชฉ๋ก์ ๋ฐํํด์ผํ๋ค๊ณ ์๊ฐํฉ๋๋ค.
@vladar https://github.com/gaearon/redux/issues/291#issuecomment -125267259
๋ธ๋ผ ๋ค๋ฅด
์, ๊ทธ๋ฌ๋ Flux๋ ๋น๋๊ธฐ ์ฝ๋ฐฑ์์ dispatch ()๋ฅผ ์ง์ ์ ์ผ๋ก ๋ณ๊ฒฝํ๋ ํ ์คํ ์ด์ ๋น๋๊ธฐ ํญ๋ชฉ์ ๊ฐ๋ ๊ฒ์ ๊ธ์งํ์ง ์์ต๋๋ค. ๋๋ถ๋ถ์ ๊ตฌํ์์ ๋น๋๊ธฐ๋ฅผ ์ํด AC๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ๊ฐ์ธ์ ์ผ๋ก ๋๋ ๊ทธ๊ฒ์ด MVC์ ํ์์ด๋ผ๊ณ ์๊ฐํ๋ค. ์๋ํ๋ฉด AC๋ฅผ ์ปจํธ๋กค๋ฌ๋ก ์ทจ๊ธํ๋ ๊ฒ๋ณด๋ค ์ ์ ์ ์ผ๋ก FSM์ผ๋ก ์ ํํ๋ ๊ฒ์ด ์ ์ ์ ์ผ๋ก ํธ๋ฆฌํ๊ธฐ ๋๋ฌธ์ด๋ค.
ActionCreators๋ฅผ ์ปจํธ๋กค๋ฌ๋ก ๋ํ๋ ๊ฒ์ด ์ข์ ์ฌ๊ณ ๋ฐฉ์์ด ์๋๋ผ๋ ๋ฐ ๋์ํฉ๋๋ค. ๋ณต์กํ ๋ ผ๋ฆฌ์ ๊ฒฝ์ฐ ๊ฐ์๊ธฐ์์ ๋ค์ AC๋ก ์ ์ด๋ฅผ ๋๋๋ ค ์ผํ๋ค๊ณ ์๊ฐํ๋ ๋ฃจํธ ์์ธ์ ๋๋ค. ๊ทธ๋ด ํ์ ์์ด์. AC๊ฐ ๋น๋๊ธฐ๋ฅผ ์ฒ๋ฆฌํ๋ ๊ฒฝ์ฐ ์์ฒญ ์ฒ๋ฆฌ๊ธฐ์ ๋น์ทํด์ผํฉ๋๋ค. ๋ค๋ฅธ ๊ณณ์์ ๋ด๋ฆฐ ๊ฒฐ์ ์ ๊ธฐ๋ฐ์ผ๋ก ์คํ๋๋ฉฐ์ด ์์ฒญ์ ๋๋ฉ์ธ์ ๊ฐ๋ก ์ง๋ฌ์๋ ์๋ฉ๋๋ค.
์ปจํธ๋กค๋ฌ๋ก์์ ์ญํ ์ ํผํ๊ธฐ ์ํด ์ด์ ์ ์ผํ ์ต์ ์ ์ค๋งํธ ๊ตฌ์ฑ ์์๋ฅผ ํตํด ๋ ผ๋ฆฌ๋ฅผ ๋ผ์ฐํ ํ๊ณ ActionCreators๋ฅผ ์ฌ์ฉํ์ฌ UI์ ๋ํ ์ง์ ์๋ต์ผ๋ก ๋ ผ๋ฆฌ์ ์ด๊ธฐ ๋จ๊ณ๋ฅผ ์คํํ๋ ๊ฒ์ ๋๋ค. ์ค์ ์ฒซ ๋ฒ์งธ ๊ฒฐ์ ์ Redux.state ๋ฐ / ๋๋ ๊ตฌ์ฑ ์์์ ๋ก์ปฌ ์ํ๋ฅผ ๊ธฐ๋ฐ์ผ๋กํ๋ ์ค๋งํธ ๊ตฌ์ฑ ์์์์ ์ด๋ฃจ์ด์ง๋๋ค.
๋ฒ์ฃผ๋ฅผ ์ญ์ ํ๊ณ webapi๋ฅผ ์ฌ์ฉํ์ฌ ์๋ต์ผ๋ก ๋ค๋ฅธ ํญ๋ชฉ์ ์๋ก ๊ณ ์น๊ฑฐ๋ ์ญ์ ํ๋ ์ด์ ์์ ์์ด ์ ๊ทผ ๋ฐฉ์์ ์ข์ง ์์ต๋๋ค. ๊ฐ๋ฐ ํ๊ฒฝ ์ค์ ์ ๋ฐ๋ผ ์๋ก ๋ค๋ฅธ ๊ธฐ์ ์ ํผํฉ์ผ๋ก ์ด์ด์ง ๊ฒ์ด๋ผ๊ณ ๊ฐ์ ํฉ๋๋ค. AC, ๊ฐ์๊ธฐ, ์ค๋งํธ ๊ตฌ์ฑ ์์์ ์์ด์ผํฉ๋๊น? ํจํด์ด ์ด๋ป๊ฒ ์งํํ๋์ง ๋ณด๊ฒ ์ต๋๋ค.
๋๋ ๋น๋๊ธฐ ํธ์ถ์ ์์ ์์ ๋ฉ๋ฆฌํ๊ธฐ ์ํด ํฌ์ธํธ๋ฅผ ๊ตฌ์ ํ์ต๋๋ค. ๊ทธ๋ฌ๋ ๋๋ ๊ทธ๊ฒ์ด ํ๋นํ๋ค๊ณ ์๊ฐํ์ง ์์ต๋๋ค. ์๋ํ๋ฉด ๊ทธ๊ฒ์ ๋ค๋ฅธ ๊ณณ์์ ๋ณต์ก์ฑ์ ์๋นํ ์ฆ๊ฐ์ํค๊ธฐ ๋๋ฌธ์ ๋๋ค. ๋ฐ๋ฉด์ ์คํ ์ด / ๋ฆฌ๋์์์ ๋น๋๊ธฐ ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ ๊ฒ์ ๊ฑฐ๊ธฐ์์ ์คํํ๊ณ ๋์คํจ์นํ๊ฑฐ๋ ์์ํ ์ ๊ทผ ๋ฐฉ์์ผ๋ก ์ด๋ฌํ ๊ธฐ๋ฅ์ ๋ฐ์ดํฐ๋ก ์ฒ๋ฆฌํ๊ณ ๋จผ ๊ณณ์์ ํธ๋ฆฌ๊ฑฐํ๋ ํ ๊ทธ๋ค์ง ๋ณต์กํ์ง ์์ต๋๋ค.
์กํฐ๋ ๋น์ทํ๊ฒ ๋น๋๊ธฐ๋ฅผ ์คํํ๊ณ ๋ค๋ฅธ ์กํฐ์๊ฒ ๋ฉ์์ง (์ก์ ๊ฐ์ฒด)๋ฅผ ๋ณด๋ด๊ฑฐ๋ FSM์์ ๊ณ์ํ๊ธฐ ์ํด ์์ ์๊ฒ ๋ณด๋ผ ์ ์์ต๋๋ค.
์ฌ๊ธฐ์ ์กฐ์น ํ ์์๋ ๊ฒ์ด์๋ ๊ฒ ๊ฐ์์ ๋ซ์ต๋๋ค. ๋น๋๊ธฐ ์์ ๋ฌธ์๋ ๋๋ถ๋ถ์ ์ง๋ฌธ์ ๋ตํด์ผํฉ๋๋ค. ๋ ๋ง์ ์ด๋ก ์ ๋ ผ์๋ ์ฐ๋ฆฌ๊ฐ ์คํํ ์์๋ ์ค์ ์ฝ๋ ์์ด๋ ๋์๊ฒ ๊ฐ์น์๋ ๊ฒ ๊ฐ์ง ์์ต๋๋ค. ;-)
@gaearon redux๋ฅผ ์ฌ์ฉํ๋ ์์ ์ค ํ๋์ API ํธ์ถ์ ์ฒ๋ฆฌํ๋ ์ฌ๋ฐ๋ฅธ ๋ฐฉ๋ฒ์ ๊ตฌํํ๋ ์ค์ ์ฝ๋๋ฅผ ์ถ๊ฐ ํ ์ ์์ต๋๊น (๋ฏธ๋ค์จ์ด๋ฅผ ์ฌ์ฉํ๋ "์ค์ "์์ ์ธ๋ถ)?
๋ชจ๋ ๋ฌธ์์์ด ๋ฌธ์ ๋ฅผ ๋ช ๋ฒ ์ฝ์ ํ์๋ ์ค์ ๋ฐฐ์น์ ๋ํ ์ง๋ฌธ์ด ์์ต๋๋ค. ์ด๋ฌํ ๋ถ์์ฉ์ ๋ฐฐ์น ํ ํ์ผ์ ์ดํดํ๋ ๋ฐ ๋ฌธ์ ๊ฐ ์์ต๋๋ค https://github.com/rackt/redux/issues/291#issuecomment -123010379 . ์ด ์ด์ ์ค๋ ๋์ "์ฌ๋ฐ๋ฅธ"์๋ผ๊ณ ์๊ฐํฉ๋๋ค.
์ด ์์ญ์ ๋ํ ์ค๋ช ์ ๋ฏธ๋ฆฌ ๊ฐ์ฌ๋๋ฆฝ๋๋ค.
๋ถ์ํ ์ก์ ํฌ๋ฆฌ์์ดํฐ์ ๋ํ ์ค์ํ ์๊ฐ์ ๋ง์ ๋๋ฆฌ๊ณ ์ถ์ต๋๋ค.
์ก์ ์์ฑ์์๊ฒ ๋น๋๊ธฐ ํธ์ถ์ ๋ฃ๊ฑฐ๋ ์ผ๋ฐ์ ์ผ๋ก ๋ถ์ํ ์ก์ ์์ฑ์๋ฅผ ๊ฐ๋ ๊ฒ์ ๋์๊ฒ ํฐ ๋จ์ ์ด ์์ต๋๋ค. ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ์ด ๋ก์ง์ ์์ ํ ์ค์ํํ๋ ๊ฒ์ด ๋จ์ํ ์คํ ์ด๋ฅผ ์ค์ํํ๋ ๊ฒ๋ง ํผ ๊ฐ๋จํ์ง ์์ ๋ฐฉ์์ผ๋ก ์ ์ด ๋ก์ง์ ์กฐ๊ฐํํฉ๋๋ค. ์ฐฝ์กฐ์. ๋๋ ํญ์ ๋น๋๊ธฐ ํ๋ก์ธ์ค์ ๋ฏธ๋ค์จ์ด๋ฅผ ์ฌ์ฉํ๊ณ ๋ถ์ํ ์ก์ ์์ฑ์๋ฅผ ์์ ํ ํผํ๋ ค๊ณ ํฉ๋๋ค.
๋ด๊ฐ ๊ฐ๋ฐ์ค์ธ ์ฑ์๋ ์ ์ด๋ ๋ ๊ฐ์ง ๋ฒ์ ์ด ์์ต๋๋ค. ํ๋๋ ์จ ์ฌ์ดํธ Raspberry Pi์์ ์คํ๋๊ณ ๋ค๋ฅธ ํ๋๋ ํฌํธ์ ์คํํฉ๋๋ค. ๊ณ ๊ฐ์ด ์ด์ํ๋ ๊ณต๊ฐ ํฌํธ / ํฌํธ์ ๋ํด ๋ณ๋์ ๋ฒ์ ์ด์์ ์๋ ์์ต๋๋ค. ๋ค๋ฅธ API๋ฅผ ์ฌ์ฉํด์ผํ๋์ง ์ฌ๋ถ๋ ๋ถํ์คํ์ง๋ง ๊ฐ๋ฅํ ํ ๊ทธ ๊ฐ๋ฅ์ฑ์ ๋๋นํ๊ณ ์ถ์ต๋๋ค. ๋ฏธ๋ค์จ์ด๋ฅผ ์ฌ์ฉํ๋ฉด ๊ทธ๋ ๊ฒ ํ ์ ์์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ ๋์๊ฒ API ํธ์ถ์ ์ก์ ์์ฑ์์๊ฒ ๋ถ์ฐ์ํค๋ ๊ฐ๋ ์ ์ํ ์ ๋ฐ์ดํธ์ ๋ํ ์ค์ ์ง์ค์ ์ ์ด๋ผ๋ Redux ๊ฐ๋ ๊ณผ ์์ ํ ๋ฐ๋๋ฉ๋๋ค. ๋ฌผ๋ก , API ์์ฒญ์ด ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์คํ๋๊ณ ์๋ค๋ ๋จ์ํ ์ฌ์ค์ Redux ์คํ ์ด ์ํ์ ์ผ๋ถ๊ฐ ์๋์ง๋ง, ๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ ์ ํํ ์ ์ด๋ฅผ ์ํ๋ ๊ฒ์ ์ฌ์ ํ โโ์ ํ๋ฆฌ์ผ์ด์ ์ํ์ ๋๋ค. ๊ทธ๋ฆฌ๊ณ Redux ์ ์ฅ์ / ๊ฐ์ ๊ธฐ์ ๋ง์ฐฌ๊ฐ์ง๋ก ์ ์ด๊ฐ ๋ถ์ฐ์ด ์๋ ์ค์ ์ง์คํ ๋ ๋ ๊ฐ์ฅ ์ ๋ฐํ๊ฒ ์ ์ด ํ ์ ์์ต๋๋ค.
@ jedwards1211 https://github.com/redux-effects/redux-effects ์ ๊ด์ฌ์ด์์ ์ ์์ต๋๋ค. ์์ง ํ์ธํ์ง ์์ ๊ฒฝ์ฐ์ # 569์์ ๋ ผ์ ํ ์ ์์ต๋๋ค.
@gaearon ์ฟจ, ์ง์ ํด ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค! ์ด์จ๋ ๋ด ๋ฏธ๋ค์จ์ด๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ์ง๊ธ๊น์ง ๊ทธ๋ฆฌ ์ด๋ ต์ง ์์์ต๋๋ค. :)
๋๋ Elm๊ณผ ๊ฐ์ ์ ๊ทผ ๋ฐฉ์์ ๋ง๋ค์์ต๋๋ค : redux-side-effect . README ๋ ์ ๊ทผ ๋ฐฉ์์ ์ค๋ช ํ๊ณ ๋์๊ณผ ๋น๊ตํฉ๋๋ค.
@gregwebs ๋๋ redux-side-effect
์ข์ํ์ง๋ง ์ค์ ๊ฐ๋ฅํ ์ ์ด ๋ก์ง๋ ์ด์ ํ ๊ฒ์
๋๋ค. ์๋ํ๋ฉด ์ฌ๋ฌ ๋ค๋ฅธ ์ ์ฅ์ ๊ตฌ์ฑ์๊ฐ์์ ๋ sideEffect
ํจ์๋ฅผ ๋ด ๊ฐ์๊ธฐ ๋ชจ๋๋ก ๊ฐ์ ธ ์ค๋ ๋ฐฉ๋ฒ์ ๋ํ ์ง๋ฌธ์ด ์๊ธฐ ๋๋ฌธ์
๋๋ค. ๋ค๋ฅธ ๋น๋์์ ์ฌ์ฉํ ๋ชจ๋.
๊ทธ๋๋ ์ฌ๋ฏธ์๋ ํดํน์ ์ฌ์ฉํ ์ ์์ต๋๋ค. state
์์ฒด์ sideEffect
๋ง ์ ์ฅํ๋ฉด ๊ฐ์๊ธฐ์์ ์๋์ผ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค! : stuck_out_tongue_winking_eye :
https://github.com/rackt/redux/pull/569/ ์ ๊ฐ์ ๊ฒ์ ๋ด๊ฐ ์์ ํ๋ ค๋ ๋ฐฉ์์ ์ด์์ ์ ๊ฐ๊น์ง๋ง ๋ฌผ๋ก ํ์ค ๋ถํ์ด ์๋ ํ ํ๋ก๋์ ํ๋ก์ ํธ์์ ์ฌ์ฉํ๊ณ ์ถ์ง ์์ต๋๋ค. API์.
์ฌ๊ธฐ์ ์์ด๋์ด๊ฐ ์์ต๋๋ค. ๋ฏธ๋ค์จ์ด๊ฐ ์ก์
์ sideEffect
ํจ์๋ฅผ ๋ถ์
๋๋ค. ์ฝ๊ฐ ํดํคํ์ง๋ง ๊ฐ์๊ธฐ๊ฐ ๋น๋๊ธฐ ์ฝ๋๋ฅผ ์์ํ ์ ์๋๋ก ๋ง๋๋ ๋ฐ ํ์ํ ๊ฐ์ฅ ์์ ๋ณ๊ฒฝ ์ฌํญ :
sideEffectMiddleware.js
:
export default store => next => action => {
let sideEffects = [];
action.sideEffect = callback => sideEffects.push(callback);
let result = next(action);
sideEffects.forEach(sideEffect => sideEffect(store));
return result;
};
๊ฐ๋จํ sideEffect ์ ๊ทผ ๋ฐฉ์์๋ ์ฌ๋ฌ ๊ฐ์ง ๋ฐฉ๋ฒ์ด ์์ต๋๋ค. ๋ณํ์ ์๋ํ๊ณ ๋ค์๋ณด๊ณ ํ์ญ์์ค.
์์ sideEffectMiddleware
์ ๊ทผ ๋ฐฉ์์ ์ฌ์ฉํ๋๋ก ์ฝ๋๋ฅผ ๋ฆฌํฉํฐ๋งํ์ผ๋ฉฐ ๊ฒฐ๊ณผ ์ฝ๋ ๊ตฌ์ฑ์ด ์ ๋ง ๋ง์์ ๋ญ๋๋ค. sideEffect
ํจ์๋ฅผ ๋ด ๋ฆฌ๋์๋ก ๊ฐ์ ธ์ฌ ํ์๊ฐ์๋ ๊ฒ์ด ์ข์ต๋๋ค. action
๋ฉ๋๋ค.
@ jedwards1211 ํจํค์ง ๋ฒ์ 2.1.0์์ ์ฝ๋๋ฅผ actionSideEffectMiddleware
๋ก ๊ฒ์ํ์ต๋๋ค.
@gregwebs ๋ฉ์ง๋ค! ์ ๋ฅผ ๊ณต๋ ์์ ์๋ก ๋ฑ๋ก ํ์๊ฒ ์ต๋๊น?
@ jedwards1211 ๋น์ ์ด ์ถ๊ฐ๋์์ต๋๋ค. ์๋ง ๋น์ ์ ์ ์ ํ ์ฌ์ ์ง์์ ์ถ๊ฐ ํ ๊ฒ์ ๋๋ค. :) ๋๋ ์ด๊ฒ์ ์ฌ์ฉํ๋ ๊ณณ์์ ์์ง ๊ทธ๊ฒ์ ์ด์ฉํ ์ ์์ต๋๋ค.
@gaearon ๊ธฐ๋กํ๊ณ ์ฌ์ ํ ์ก์ ์ ๋ฏธ๋ค์จ์ด๋ฅผ ์ ํ ๊ฑฐ์น์ง ์๋ ๊ฑฐ์ฃ ?
๊ทธ๋ค์ ๊ธฐ๋ก ๋ ๋ ์ด๋ฏธ ํ๋ฒํ ๊ฐ์ฒด์ด๊ธฐ ๋๋ฌธ์ ๋ฏธ๋ค์จ์ด๋ ์ผ๋ฐ์ ์ผ๋ก ๊ฐ์ ํ์ง ์์ต๋๋ค.
@gaearon ํ . ๊ทธ๋์ ์ค์ ๋ก ๊ทธ ๊ธฐ๋ฅ์ ์ฌ์ฉ ํด๋ณธ ์ ์ ์์ง๋ง ... ๋ถ์์ฉ ๋ฏธ๋ค์จ์ด๊ฐ ๋
น์ / ์ฌ์๋ ๊นจ๋จ๋ฆด ๊ฒ ๊ฐ๋ค์? ์๋ฅผ ๋ค์ด redux-effects-fetch
๋ฅผ ์ฌ์ฉํ๋ฉด ์ผ๋ฐ ๊ฐ์ฒด FETCH ์์
์ ๋ํด ์ฌ์ ํ ajax ์์ฒญ์ ์ํํฉ๋๋ค.
function fetchMiddleware ({dispatch, getState}) {
return next => action =>
action.type === 'FETCH'
? fetch(action.payload.url, action.payload.params).then(checkStatus).then(deserialize, deserialize)
: next(action)
}
๋ ์ฝ๋๊ฐ FETCH ์์
์ steps
์์ [success, failure]
์ฝ๋ฐฑ์ ์ ๋ฆฌํ๋ฉด redux-effects
๋ฏธ๋ค์จ์ด๋ ์ํ ๋ณ๊ฒฝ ์์
์ ์ ๋ฌํ์ง ์์ง๋ง ์ฌ์ ํ ์ํ์ง ์์ต๋๋ค. ajax ์์ฒญ์ ํธ๋ฆฌ๊ฑฐํ๊ธฐ ์ํด ์ฌ์ํฉ๋๋ค.
redux-logger
์ ๊ฐ์ "์์ํ"๋ฏธ๋ค์จ์ด (์ถ๊ฐ ์์
์ ์ ๋ฌํ์ง ์๋)๋ฅผ "์์ํ"๋ฏธ๋ค์จ์ด (์์
์ ์ ๋ฌํ ์ ์์)์ ๋ถ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ด ์์ต๋๊น?
์ํ๊น๊ฒ๋ redux-effects
๋ฉด๋ฐํ ์กฐ์ฌํ์ง ์์ ๊ทํ์ ์ง๋ฌธ์ ๋ต๋ณ ํ ์ ์์ต๋๋ค.
๋ฌธ์ ์์ต๋๋ค. ์ด๋ค ๊ฒฝ์ฐ์๋ ๋ ์ฝ๋๋ ๋ฏธ๋ค์จ์ด๊ฐ ๋ถ์์ฉ์ ์ํํ ์ง ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํ๋ ๋ฐ ์ฌ์ฉํ ์์๋ ์์ ์ ํ๋๊ทธ๋ฅผ ์ถ๊ฐํฉ๋๊น? ๋ด ๋ฏธ๋ค์จ์ด์์ devtools๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ์ง์ํ ์์๋ ๋ฐฉ๋ฒ์ ์ฐพ์ผ๋ ค๊ณ ํฉ๋๋ค.
๊ทธ๋ ์ง ์์ต๋๋ค. ์ธํธ์ ์ปดํฌ์ง์
์ฒด์ธ์ devTools()
_after_ applyMiddleware
๋ฅผ ๋ฃ์ด์ผํ๋ฏ๋ก ์ก์
์ ๋๋ฌ ํ ๋๊น์ง ์ถ๊ฐ ํด์์ด ํ์์๋ "์ต์ข
"์ก์
์ด๋ฉ๋๋ค.
์, ์๊ฒ ์ต๋๋ค. ๋ฏธ๋ค์จ์ด๊ฐ ๋ถ์์ฉ์ ์ํ ํ ํ์๋ ์์ ์์ ํ๋๋ฅผ ์ ๊ฑฐํ๊ฑฐ๋ ์ฌ์์ ๋ฏธ๋ค์จ์ด๋ฅผ ํตํด ๋๋์ ๊ฐ ๋ ๋ถ์์ฉ์ด ๋ฐ์ํ์ง ์๋๋ก ์กฐ์ ํ๋ฉด๋ฉ๋๋ค. ๊ฐ๋ฐ ๋๊ตฌ๋ก ์์ ํ์ง?
๋ค, ์ข์ ๋ฐฉ๋ฒ ์ธ ๊ฒ ๊ฐ์ต๋๋ค.
๊นจ๋ฌ์์ ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค!
@gaearon @vladar @ jedwards1211 https://github.com/salsita/redux-side-effects์ ๊ด์ฌ์ด์์ ์ ์์ต๋๋ค (state, action) => (state, sideEffects)
์ ๊ตฌํ์ด์ง๋ง ๋ฆฌ๋์๊ฐ ํํ์ ๋ฐํํ๋ ๋์ (์ด๋ฏธ ๋ฐ๊ฒฌ ํ ๊ฒ์ ๋ถ๊ฐ๋ฅ ํจ) ํจ๊ณผ๋ฅผ ์ฐ์ถํฉ๋๋ค.
๋๋ ๊ณง ๊ทธ๊ฒ์ ๊ฐ์ง๊ณ ๋์๊ณ , ํซ ๋ฆฌ๋ก๋์ ๋ฆฌํ๋ ์ด๋ ๊ด์ฐฎ์ ๊ฒ ๊ฐ์ต๋๋ค. ์ง๊ธ๊น์ง redux ๊ธฐ๋ฅ์ด ์์๋์ง๋ ์์์ง๋ง ๊ณ ์ reduxer ์ค ์ผ๋ถ๊ฐ ๋ญ๊ฐ๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค. :)
๋์๊ฒ ์ด๊ฒ์ ๋ก์ง์ด ์ฃผ๋ก ๋ฆฌ๋์์ ์๋๋กํ์ฌ ํจ๊ณผ (ํ์ฌ ์ํ์๋ง ์์กดํ์ง ์๋ ์ ํ ๋์)๋ฅผ ์ธ๋ถ ์๋น์ค์ ์์ํ๋ ํจ๊ณผ์ ์ด๊ณ ํ
์คํธ ๊ฐ๋ฅํ ์ํ ๋จธ์ ์ผ๋ก ๋ง๋๋ ๋ฆฌ๋์ค ์คํ์ ์ ๋ง ์ค์ํ ์ถ๊ฐ๋ก ๋ณด์
๋๋ค. Elm ์ํคํ
์ฒ, ํจ๊ณผ ๋ฐ ์๋น์ค์ ๋งค์ฐ ๋น์ทํฉ๋๋ค.
๋ ๋ค๋ฅธ ์ ๊ทผ๋ฒ์ redux-saga ๋ก ์ ๋๋ ์ดํฐ๋ ์ฌ์ฉํ์ง๋ง ๋ฆฌ๋์์ ๋ถ์์ฉ์ ๋ณ๋๋ก ์ ์งํฉ๋๋ค.
๋๋ ์๋ฏธ @minedeljkovic ์๊ฐ @gaearon
๋์๊ฒ ์ด๊ฒ์ ๋ก์ง์ด ์ฃผ๋ก ๋ฆฌ๋์์ ์๋๋กํ์ฌ ํจ๊ณผ (ํ์ฌ ์ํ์๋ง ์์กดํ์ง ์๋ ์ ํ ๋์)๋ฅผ ์ธ๋ถ ์๋น์ค์ ์์ํ๋ ํจ๊ณผ์ ์ด๊ณ ํ ์คํธ ๊ฐ๋ฅํ ์ํ ๋จธ์ ์ผ๋ก ๋ง๋๋ ๋ฆฌ๋์ค ์คํ์ ์ ๋ง ์ค์ํ ์ถ๊ฐ๋ก ๋ณด์ ๋๋ค. Elm ์ํคํ ์ฒ, ํจ๊ณผ ๋ฐ ์๋น์ค์ ๋งค์ฐ ๋น์ทํฉ๋๋ค.
https://github.com/yelouafi/redux-saga/ ๋ ๊ธฐ์กด์ ์ ๊ทผ ๋ฐฉ์์ ๋นํด ๊ฐ์ฅ ํฐ ์ฅ์ ์
๋๋ค. ์๋ํ๋ฉด redux-thunk
์๋ ๋ฐฉ์๊ณผ ๋งค์ฐ ์ ์ฌํ๊ธฐ ๋๋ฌธ์
๋๋ค. .
๋ฐ๋ฉด์ https://github.com/salsita/redux-side-effects ๋ Elm ์ํคํ ์ฒ์ ๋น์ทํฉ๋๋ค.
์, redux-saga ๋ฐ redux-side-effects๋ ์์ฑ๊ธฐ๋ฅผ ์ฌ์ฉํ์ฌ ๋ถ์์ฉ์ ์ ์ธํ๊ณ sagas์ reducer๋ฅผ ๊ฐ๊ฐ ์์ํ๊ฒ ์ ์งํฉ๋๋ค. ๋น์ทํฉ๋๋ค.
๊ฐ์๊ธฐ์์ ์ ํธํ๋ ๋ ๊ฐ์ง ์ด์ :
https://github.com/rackt/redux/issues/1139#issuecomment -165419770์ ๋ด ์๊ฒฌ์ redux-saga
ํด๊ฒฐ๋์ง ์๊ณ ๋ชจ๋ธ์ ์๋ฝํ๋ ๊ฒ ์ธ์๋ ํด๊ฒฐํ ์์๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ด ์๊ธฐ ๋๋ฌธ์ ์ฌ์ ํ ์ ํจํฉ๋๋ค. Elm ์ํคํ
์ฒ์์ ์ฌ์ฉ๋ฉ๋๋ค.
redux-side-effects์ ๋ํ ๋ด ์์ ์ ๊ฐ์กฐํ๋ ค๋ ๊ฐ๋จํ ์์ ์ ๋ฃ์์ต๋๋ค : https://gist.github.com/minedeljkovic/7347c0b528110889aa50
๋๋ ๋จ์ง "์ค์ ์ธ๊ณ"๋ผ๊ณ ์๊ฐํ๋ ๊ฐ์ฅ ๊ฐ๋จํ ์๋๋ฆฌ์ค๋ฅผ ์ ์ํ๋ ค๊ณ ๋ ธ๋ ฅํ์ง๋ง ์ฌ์ ํ์ด ๋ ผ์์ ๋ช ๊ฐ์ง ์์ ์ ๊ฐ์กฐํฉ๋๋ค.
์๋๋ฆฌ์ค๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
์์ฉ ํ๋ก๊ทธ๋จ์๋ ๊ฐ์ธ ์ฌ์ฉ์ ๋ฐ์ดํฐ๋ฅผ ์
๋ ฅํด์ผํ๋ "์ฌ์ฉ์ ๋ฑ๋ก"๋ถ๋ถ์ด ์์ต๋๋ค. ๋ค๋ฅธ ๊ฐ์ธ ๋ฐ์ดํฐ ์ค์์ ์ถ์ ๊ตญ๊ฐ๋ ๊ตญ๊ฐ ๋ชฉ๋ก์์ ์ ํ๋ฉ๋๋ค. ์ฌ์ฉ์๊ฐ ๊ตญ๊ฐ๋ฅผ ์ ํํ๊ณ ์ ํ์ ํ์ธํ๊ฑฐ๋ ์ทจ์ ํ ์์๋ "๊ตญ๊ฐ ์ ํ"๋ํ ์์์์ ์ ํ์ด ์ํ๋ฉ๋๋ค. ์ฌ์ฉ์๊ฐ ์ ํ์ ํ์ธํ๋ ค๊ณ ํ์ง๋ง ๊ตญ๊ฐ๊ฐ ์ ํ๋์ง ์์ ๊ฒฝ์ฐ ๊ฒฝ๊ณ ๋ฅผ ๋ฐ์์ผํฉ๋๋ค.
์ํคํ ์ฒ ์ ์ฝ :
์ด ๋ํ์ ๊ด๋ จํ์ฌ ์์ ์์ ๊ฐ์ฅ ์ค์ํ ๋ถ๋ถ์ countrySelection ๊ฐ์๊ธฐ๊ฐ CONFIRM_SELECTION ์์ ์ ์ฒ๋ฆฌํ๋ ๋ฐฉ์์ ์์ต๋๋ค.
@gaearon , ๋๋ ํ์ค redux์ ์ถ๊ฐ ๋ redux-side-effects๊ฐ constratints๋ฅผ ๊ณ ๋ คํ์ฌ ๊ฐ์ฅ ๊ฐ๋จํ ์๋ฃจ์ ์ ์ ๊ณตํ๋ค๋ ๋ด ์ง์ ์ ๋ํ ๊ทํ์ ์๊ฒฌ์ ๋๋ถ๋ถ ํ๊ฐํ ๊ฒ์ ๋๋ค.
์ด ์๋๋ฆฌ์ค์ ๊ตฌํ์์ํ ๊ฐ๋ฅํ ๋์ ์์ด๋์ด (redux-side-effects๋ฅผ ์ฌ์ฉํ์ง ์๊ณ redux-saga, redux-thunk ๋๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ์ฌ์ฉ)๋ ๋งค์ฐ ์ ์ ํ ๊ฒ์ ๋๋ค.
@ tomkis1 , ๋๋ ์ฌ๊ธฐ์์ ๊ทํ์ ์๊ฒฌ์
(์ด ์์ https://gist.github.com/minedeljkovic/9d4495c7ac5203def688์๋ ์ฝ๊ฐ ๋ค๋ฅธ ๊ตฌํ์ด ์์ต๋๋ค. ์ฌ๊ธฐ์ globalActions๋ ํผํฉ๋๋ค.์ด ์ฃผ์ ์๋ ์ค์ํ์ง ์์ง๋ง ๋๊ตฐ๊ฐ์ด ํจํด์ ๋ํด ์๊ฒฌ์ ๋งํ๊ณ ์ถ์ ์๋ ์์ต๋๋ค.)
@minedeljkovic ์์ ์ ๊ฐ์ฌ๋๋ฆฝ๋๋ค. ๋๋ ๋น์ ์ ์์์ ํ๋์ ๊ฐ๋
์ ๋ฌธ์ ๋ฅผ ๋ด
๋๋ค. redux-side-effects
์ ๋ถ์์ฉ์๋ง ์ฌ์ฉ๋ฉ๋๋ค. ๊ทธ๋ฌ๋ ๊ทํ์ ์์๋ ๋ถ์์ฉ์ด ์์ง๋ง ์ฅ๊ธฐ์ ์ธ ๋น์ฆ๋์ค ๊ฑฐ๋๊ฐ ์์ผ๋ฏ๋ก redux-saga
๊ฐ ํจ์ฌ ๋ ์ ํฉํฉ๋๋ค. @slorber ์ @yelouafi ๋ ์ด๊ฒ์ ๋ํด ๋ ๋ง์ ๊ฒ์
์ฆ, ์ ์๊ฒ ๊ฐ์ฅ ์ฐ๋ ค๋๋ ๋ฌธ์ ๋ ๋ฆฌ๋์ (https://github.com/salsita/redux-side-effects/pull/9#issuecomment-165475991) ๋ด์์ ์๋ก์ด ์์
์ ๋๊ธฐ์ dispatching
์
๋๋ค.
yield dispatch => dispatch({type: COUNTRY_SELECTION_SUCCESS, payload: state.selectedCountryId});
@slorber ๋ "๋น์ฆ๋์ค ๋ถ์์ฉ"์ด๋ผ๋ ์ฉ์ด์ ํจ๊ป ์์ผ๋ฉฐ ์ด๊ฒ์ด ๋ฐ๋ก ๊ทํ์ ๊ฒฝ์ฐ์
๋๋ค. redux-saga
์์ด ํน์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐ ๋น์ ๋ฐํฉ๋๋ค.
@mindjuice ์ ๋ ๊ทํ์ ์์ ๋ฅผ ์๋ฒฝํ๊ฒ ์ดํดํ์ง๋ ๋ชปํ์ง๋ง ์ฌ๊ธฐ์ ์ค ์จ ๋ณด๋ฉ ์์ ๊ฐ ๋ง์์ ๋ญ๋๋ค : https://github.com/paldepind/functional-frontend-architecture/issues/20#issuecomment -162822909
saga ํจํด์ ๋ํ ์ผ๋ถ ์์์ ์ธ ๊ฒ์ ๋ช
์ ์ ์ผ๋ก ๋ง๋ค ์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด ์์
์ ์คํํ์ฌ ๋ฐ์ํ ์ผ์ ์ค๋ช
ํ๊ณ (๋๋ ์ด๋ฒคํธ๊ฐ ๊ณผ๊ฑฐ ์์ ์ฌ์ผํ๋ฏ๋ก ์ด๋ฒคํธ๋ฅผ ์ ํธ ํจ) ์ผ๋ถ ๋น์ฆ๋์ค ๊ท์น์ด ์์๋๊ณ UI๋ฅผ ์
๋ฐ์ดํธํฉ๋๋ค. ๊ทํ์ ๊ฒฝ์ฐ ์ค๋ฅ ํ์๋ ์์ ์ ์
๋๋ค. ๋ฌด์ฉ๋ด์ ํตํด ํ์ธ์ ๊ตญ๊ฐ๊ฐ ์ ํ๋์ง ์์ ๊ฒฝ์ฐ "NO_COUNTRY_SELECTED_ERROR_DISPLAYED"๋๋ ์ด์ ์ ์ฌํ ์์
์ ์ ๋ฌํ ์ ์์ต๋๋ค. ๋๋ ๊ทธ๊ฒ์ด ์์ ํ ๋ช
์์ ์ธ ๊ฒ์ ์ ํธํฉ๋๋ค.
๋ํ ์ฌ๊ฐ๋ฅผ ์ค๋ฆฌ ์ฌ์ด์ ์ฐ๊ฒฐ ์ง์ ์ผ๋ก ๋ณผ ์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด duck1๊ณผ duck2๊ฐ ์๊ณ ๊ฐ๊ฐ์ ๋ํ ๋ก์ปฌ ์์
์ด ์์ต๋๋ค. ๋ ๋ง๋ฆฌ์ ์ค๋ฆฌ๋ฅผ ์ฐ๊ฒฐํ๋ ์์ด๋์ด๊ฐ ๋ง์์ ๋ค์ง ์์ผ๋ฉด (ํ ๋ง๋ฆฌ์ ์ค๋ฆฌ๊ฐ ๋ ๋ฒ์งธ ์ค๋ฆฌ์ ์์
์์ฑ์๋ฅผ ์ฌ์ฉํ๋ค๋ ๋ป์
๋๋ค) ๋ฌด์จ ์ผ์ด ์ผ์ด ๋ฌ๋์ง ์ค๋ช
ํ๋๋ก ํ ๋ค์ ๋ ์ค๋ฆฌ ์ฌ์ด์ ๋ณต์กํ ๋น์ฆ๋์ค ๊ท์น์ ์ฐ๊ฒฐํ๋ Saga๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค. ์ค๋ฆฌ 2 ๋ง๋ฆฌ.
Sooooo, ๊ทธ๊ฒ์ ์์ฒญ๋๊ฒ ๊ธด ์ค๋ ๋์ด๋ฉฐ ์์ง ๋ฌธ์ ์ ๋ํ ํด๊ฒฐ์ฑ ์ด ์์ต๋๊น?
๋น๋๊ธฐ action()
์๊ณ ์ฝ๋๊ฐ ์ค๋ฅ๋ฅผ ๋ํ๋ด๊ฑฐ๋ ๊ฒฐ๊ณผ๋ฅผ ํ์ํด์ผํ๋ค๊ณ ๊ฐ์ ํฉ๋๋ค.
์ฒซ ๋ฒ์งธ ์ ๊ทผ ๋ฐฉ์์ ๋ค์๊ณผ ๊ฐ์ด ๋ง๋๋ ๊ฒ์ด ์์ต๋๋ค.
// the action call
action().then(dispatch(SUCCESS)).catch(dispatch(FAILURE))
// the reducer
case SUCCESS:
state.succeeded = true
alert('Success')
case FAILURE:
state.succeeded = false
alert('Failure')
๊ทธ๋ฌ๋ ์ด์ ๊ฐ์๊ธฐ์ "๋ถ์์ฉ"์ด ํฌํจ๋์ด ์๊ธฐ ๋๋ฌธ์ Redux ๋ฐฉ์์ด ์๋๋๋ค (๊ทธ๊ฒ ๋ฌด์จ ๋ป์ธ์ง ๋ชจ๋ฅด๊ฒ ์ต๋๋ค).
๊ฐ๋จํ ๋งํด์, ์ฌ๋ฐ๋ฅธ ๋ฐฉ๋ฒ์์ด alert()
๊ฐ์๊ธฐ์์ ์ด๋๊ฐ๋ก ์ฎ๊ธฐ๋ ๊ฒ์
๋๋ค.
์ด๋๊ฐ์ action
๋ฅผ ํธ์ถํ๋ React ์ปดํฌ๋ํธ๊ฐ ๋ ์ ์์ต๋๋ค.
์ด์ ๋ด ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
// the reducer
case SUCCESS:
state.succeeded = true
case FAILURE:
state.succeeded = false
// the React component
on_click: function()
{
action().then
({
dispatch(SUCCESS)
alert('Success')
// do something else. maybe call another action
})
.catch
({
dispatch(FAILURE)
alert('Failure')
// do something else. maybe call another action
})
}
์ด์ ์ด๊ฒ์ด ์ฌ๋ฐ๋ฅธ ๋ฐฉ๋ฒ์
๋๊น?
์๋๋ฉด ๋ ์กฐ์ฌํ๊ณ ํ์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ ์ฉํด์ผํฉ๋๊น?
Redux๋ ์ ํ ๊ฐ๋จํ์ง ์์ต๋๋ค. ์ค์ ์ฑ์ ๊ฒฝ์ฐ ์ดํดํ๊ธฐ ์ฝ์ง ์์ต๋๋ค. ์ฌ๋ฐ๋ฅธ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ฃผ๋ ํ์ค ์์ ๋ก ์ํ ์ค์ ์ฑ ์ ์ฅ์๊ฐ ํ์ํฉ๋๋ค.
@ halt-hammerzeit Redux ์์ฒด๋ ๋งค์ฐ ๊ฐ๋จํฉ๋๋ค. ํผ๋์ค๋ฌ์ด ๋จํธํ๋ Redux๋ฅผ ์ฌ์ฉํ ๋ ๋ฆฌ๋์์ ๋ถ์์ฉ์ ํตํฉ / ๋ถ๋ฆฌํ๋ ๊ฒ์ ๋ํ ๋ค์ํ ์๊ตฌ ๋๋ ์๊ฒฌ์์ ๋น๋กฏ๋ฉ๋๋ค.
๋ํ ๋จํธํ๋ Redux๋ก ์ํ๋๋๋ก ๋ถ์์ฉ์ ์ํํ๋ ๊ฒ์ด ์ค์ ๋ก ๊ทธ๋ ๊ฒ ์ด๋ ต์ง ์๋ค๋ ์ฌ์ค์์ ๋น๋กฏ๋ฉ๋๋ค. ๊ธฐ๋ณธ ๋ถ์์ฉ ๋ฏธ๋ค์จ์ด๋ฅผ ๋กค๋งํ๋ ๋ฐ ์ฝ 10 ์ค์ ์ฝ๋ ๋ง ํ์ํ์ต๋๋ค. ๊ทธ๋ฌ๋ฏ๋ก ์์ ๋ฅผ ๋ฐ์๋ค์ด๊ณ "์ฌ๋ฐ๋ฅธ"๋ฐฉ๋ฒ์ ๋ํด ๊ฑฑ์ ํ์ง ๋ง์ญ์์ค.
@ jedwards1211 "Redux ์์ฒด"๋ ๊ฐ์น ๋ ์๋ฏธ๊ฐ ์์ผ๋ฉฐ Flux ๊ฐ๋ฐ์์ ์ผ์์ ์ธ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๊ฒ์ด ์ฃผ ๋ชฉ์ ์ด๊ธฐ ๋๋ฌธ์ ์๋ฏธ๊ฐ ์์ต๋๋ค. ๊ทธ๊ฒ์ AJAX, ์๋ฆ๋ค์ด ์ ๋๋ฉ์ด์ ๋ฐ ๊ธฐํ ๋ชจ๋ _ ํ๋ฒํ๊ณ ๊ธฐ๋๋๋ _ ๊ฒ๋ค์ ์๋ฏธํฉ๋๋ค.
@ halt-hammerzeit ๊ฑฐ๊ธฐ์ ์์ ์ด ์์ต๋๋ค. Redux๋ ํ์คํ ๋๋ถ๋ถ์ ์ฌ๋๋ค์ด ์ํ ์ ๋ฐ์ดํธ๋ฅผ ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ๋์ํ๋๋ก ์๋ ํ ๊ฒ์ฒ๋ผ ๋ณด์ด๋ฏ๋ก ๋๋ถ๋ถ์ ์ฌ๋๋ค์ด ๋ถ์์ฉ์ ์ํํ๋ ๋ฐฉ๋ฒ์ ๋์ํ์ง ์์ ๊ฒ์ ๋ถ๋๋ฌ์ด ์ผ์ ๋๋ค.
์ ์ฅ์์์ "examples"ํด๋๋ฅผ ๋ณด์ จ์ต๋๊น?
๋ถ์์ฉ์ ์ํํ๋ ์ฌ๋ฌ ๊ฐ์ง ๋ฐฉ๋ฒ์ด ์์ง๋ง ์ผ๋ฐ์ ์ผ๋ก ๊ถ์ฅ ์ฌํญ์ ๋ชจ๋ ์์์์ ๊ฐ์ด Redux ์ธ๋ถ ๋๋ ์ก์ ์ ์์ ๋ด๋ถ์์ ์ํํ๋ ๊ฒ์ ๋๋ค.
๋ค, ์์์ ... ๋ด ๋ง์์ด ์ค๋ ๋๊ฐ ๋ถ์์ฉ์ ์ํํ๋ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ ๋ํ (์ ์ด๋ ์ฌ๊ธฐ ์ฌ๋๋ค ์ฌ์ด์์) ํฉ์์ ๋ถ์กฑ์ ์ค๋ช ํ๋ค๋ ๊ฒ์ ๋๋ค.
์๋ง๋ ๋๋ถ๋ถ์ ์ฌ์ฉ์๋ ์ฝํฌ ์ก์ ์ ์์๋ฅผ ์ฌ์ฉํ๊ณ ์ฐ๋ฆฌ๋ ๊ทธ์ ์ด์ ์น์ผ๋ฟ์ ๋๋ค.
^ ๊ทธ๊ฐ ๋งํ ๊ฒ.
๋๋ ๋ชจ๋ ์๋ํ ๋ง์์ด ํ๋์ ์๋ก์ด ํด๊ฒฐ์ฑ
์ ๋์ํ๋ ๊ฒ์ ์ ํธํฉ๋๋ค
9000 ๊ฐ์ ํ๋ฉด์ ์ฝ์ ํ์๊ฐ ์๋๋ก ๋์ ์๊ฒจ์
์ค
2016 ๋ 1 ์ 7 ์ผ ๋ชฉ์์ผ์ Andy Edwards [email protected] ์ ๋ค์๊ณผ ๊ฐ์ด ์ผ์ต๋๋ค.
์, ์์์ ... ๋ด๊ฐ ๋งํ๊ณ ์ํ๋ ๊ฒ์์ด ์ค๋ ๋๊ฐ
์ธก๋ฉด์ ์ํํ๋ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ ๋ํ ํฉ์ (์ ์ด๋ ์ฌ๊ธฐ ์ฌ๋๋ค ์ฌ์ด์์)
ํจ๊ณผ.โ
์ด ์ด๋ฉ์ผ์ ์ง์ ๋ต์ฅํ๊ฑฐ๋ GitHub์์ ํ์ธํ์ธ์.
https://github.com/rackt/redux/issues/291#issuecomment -169751432.
๊ทธ๋์, ํ์ฌ ํฉ์ ๋ ํด๊ฒฐ์ฑ
์ ๋ชจ๋ ๊ฒ์ ํ๋์ผ๋ก ์ฎ๊ธฐ๋ ๊ฒ์
๋๋ค.
์ ์์. ์ด ์ ๊ทผ ๋ฐฉ์์ ์๋ํด๋ณด๊ณ ๊ฒฐํจ์ด ๋ฐ๊ฒฌ๋๋ฉด
์ฌ๊ธฐ์ ๋ค์ ๊ฒ์ํ๊ฒ ์ต๋๋ค.
2016 ๋ 1 ์ 7 ์ผ ๋ชฉ์์ผ์ ะะธะบะพะปะฐะน ะัััะผะพะฒ [email protected] ์ ๋ค์๊ณผ ๊ฐ์ด ์ผ์ต๋๋ค.
^ ๊ทธ๊ฐ ๋งํ ๊ฒ.
๋๋ ๋ชจ๋ ์๋ํ ๋ง์์ด ํ๋์ ์๋ก์ด ํด๊ฒฐ์ฑ ์ ๋์ํ๋ ๊ฒ์ ์ ํธํฉ๋๋ค
9000 ๊ฐ์ ํ๋ฉด์ ์ฝ์ ํ์๊ฐ ์๋๋ก ๋์ ์๊ฒจ์
์ค2016 ๋ 1 ์ 7 ์ผ ๋ชฉ์์ผ, Andy Edwards < [email protected]
<_e i = "16">์, ์์์ ... ๋ด๊ฐ ๋งํ๊ณ ์ํ๋ ๊ฒ์์ด ์ค๋ ๋๊ฐ
์ธก๋ฉด์ ์ํํ๋ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ ๋ํ ํฉ์ (์ ์ด๋ ์ฌ๊ธฐ ์ฌ๋๋ค ์ฌ์ด์์)
ํจ๊ณผ.โ
์ด ์ด๋ฉ์ผ์ ์ง์ ๋ต์ฅํ๊ฑฐ๋ GitHub์์ ํ์ธํ์ธ์.
https://github.com/rackt/redux/issues/291#issuecomment -169751432.
Redux ์ฌ์ฉ์์ 1 %๊ฐ ๋ถ์์ฉ์ ๋ํด ๋ ๊ฐ๋ ฅํ๊ณ ์์ํ๋ฉฐ ์ ์ธ์ ์ธ ์๋ฃจ์ ์ ์ฐพ๊ณ ์ถ์ดํ๊ธฐ ๋๋ฌธ์ ์ด์ ์ ์ฌํ ์ค๋ ๋๊ฐ ์กด์ฌํฉ๋๋ค. ์๋ฌด๋ ๋์ํ์ง ์๋๋ค๋ ์ธ์์๋ฐ์ง ๋ง์ญ์์ค. ์นจ๋ฌตํ๋ ๋๋ค์๋ ์๊ฐ๊ณผ ์ฝ์์ ์ฌ์ฉํ๋ฉฐ ๋๋ถ๋ถ์ด ์ ๊ทผ ๋ฐฉ์์ ๋ง์กฑํฉ๋๋ค. ๊ทธ๋ฌ๋ ๋ค๋ฅธ ๊ธฐ์ ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ๋จ์ ๊ณผ ์ฅ๋จ์ ์ด ์์ต๋๋ค. ๋ณต์กํ ๋น๋๊ธฐ ๋ ผ๋ฆฌ๊ฐ์๋ ๊ฒฝ์ฐ Redux๋ฅผ ์ญ์ ํ๊ณ ๋์ Rx๋ฅผ ํ์ ํ ์ ์์ต๋๋ค. Redux ํจํด์ Rx์์ ์ฝ๊ฒ ํํํ ์ ์์ต๋๋ค.
์์์ด ๊ณ ๋ง์
2016 ๋ 1 ์ 7 ์ผ ๋ชฉ์์ผ์ Dan Abramov [email protected] ์ ๋ค์๊ณผ ๊ฐ์ด ์ผ์ต๋๋ค.
Redux ์ฌ์ฉ์์ 1 %๊ฐ ์ฐพ๊ณ ์ถ์ดํ๊ธฐ ๋๋ฌธ์ ์ด์ ์ ์ฌํ ์ค๋ ๋๊ฐ ์กด์ฌํฉ๋๋ค.
๋ถ์์ฉ์ ๋ํ๋ณด๋ค ๊ฐ๋ ฅํ๊ณ ์์ํ๋ฉฐ ์ ์ธ์ ์ธ ์๋ฃจ์ ์ ๋๋ค. ์ ๋ฐ ํ์ง๋ง
์๋ฌด๋ ๋์ ํ ์ ์๋ค๋ ์ธ์์๋ฐ์ต๋๋ค. ์นจ๋ฌตํ๋ ๋๋ค์๋
์๊ฐํ๊ณ ์ฝ์ํ๋ฉฐ ๋๋ถ๋ถ์ด ์ ๊ทผ ๋ฐฉ์์ ๋ง์กฑํฉ๋๋ค. ํ์ง๋ง ์ด๋ค
๊ธฐ์ ์๋ ๋จ์ ๊ณผ ์ฅ๋จ์ ์ด ์์ต๋๋ค. ๋ณต์กํ ๋น๋๊ธฐ ๋ ผ๋ฆฌ๊ฐ์๋ ๊ฒฝ์ฐ
Redux๋ฅผ ์ญ์ ํ๊ณ ๋์ Rx๋ฅผ ํ์ ํ ์ ์์ต๋๋ค. Redux ํจํด์
Rx์์ ์ฝ๊ฒ ํํํ ์ ์์ต๋๋ค.โ
์ด ์ด๋ฉ์ผ์ ์ง์ ๋ต์ฅํ๊ฑฐ๋ GitHub์์ ํ์ธํ์ธ์.
https://github.com/rackt/redux/issues/291#issuecomment -169761410.
@gaearon ๋ค, ๋ง์์. ๊ทธ๋ฆฌ๊ณ Redux๊ฐ ์ฐ๋ฆฌ์ ๋ค์ํ ์ ๊ทผ ๋ฐฉ์์ ๋ชจ๋ ์์ฉ ํ ์์์๋งํผ ์ ์ฐํ๋ค๋ ์ ์ ๊ฐ์ฌ๋๋ฆฝ๋๋ค!
๋ด๊ฐ REDUX-์ฌ๊ฐ REDUX-์ฝํฌ๋ณด๋ค ๋ ์ข์ ์ ์์ต๋๋ค ์ด์ ๋ฅผ ์ค๋ช ๊ณณ @ ์ค๋จ-hammerzeit ์ฌ๊ธฐ์ ๋ด ๋๋ต์ ์ดํด : http://stackoverflow.com/questions/34570758/why-do-we-need-middleware-for- async-flow-in-redux / 34599594
@gaearon ๊ทธ๊ฑด ๊ทธ๋ ๊ณ , stackoverflow์ ๋ํ ๋ต๋ณ์ ๋ฌธ์์ ๋์ผํ ๊ฒฐํจ์ด ์์ต๋๋ค-๊ฐ์ฅ ๊ฐ๋จํ ๊ฒฝ์ฐ๋ฅผ ๋ค๋ฃน๋๋ค
http://stackoverflow.com/questions/34570758/why-do-we-need-middleware-for-async-flow-in-redux/34599594#34599594
์ค์ ์ ํ๋ฆฌ์ผ์ด์
์ AJAX๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ ์ค๋ ๊ฒ ์ด์์ผ๋ก ๋น ๋ฅด๊ฒ ์งํ๋ฉ๋๋ค. ๋ํ ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ๊ณ ์กฐ์น ํธ์ถ์ ์ถ๋ ฅ์ ๋ฐ๋ผ ์ผ๋ถ ์กฐ์น๋ฅผ ์ํํด์ผํฉ๋๋ค.
๊ทํ์ ์กฐ์ธ์ ๋ค๋ฅธ ์ด๋ฒคํธ dispatch
๋ํ ๊ฒ์
๋๋ค.
๊ทธ๋ฌ๋ฉด ๋ด ์ฝ๋๊ฐ ์ฌ์ฉ์์๊ฒ ์์
์๋ฃ์ alert()
์ํ๋ฉด ์ด๋ป๊ฒ๋ฉ๋๊น?
๊ทธ thunk
๋ ๋์์ด๋์ง ์์ง๋ง ์ฝ์์ ๋์์ด๋ฉ๋๋ค.
์ ๋ ํ์ฌ ๊ฐ๋จํ ์ฝ์์ ์ฌ์ฉํ์ฌ ์ฝ๋๋ฅผ ์์ฑํ๊ณ ์์ผ๋ฉฐ ๊ทธ๋ ๊ฒ ์๋ํฉ๋๋ค.
๋๋ redux-saga
๋ํ ์ธ์ ํ ์๊ฒฌ์ ์ฝ์์ต๋๋ค.
๊ทธ๊ฒ์ด ๋ฌด์์ํ๋์ง ์ดํดํ์ง ๋ชปํ์ต๋๋ค.
๋๋ monads
๋ณ๋ก ๊ด์ฌ์ด์๊ณ , thunk
๊ฐ ๋ญ์ง ์์ง๋ ๋ชจ๋ฅด๊ฒ ๊ณ , ๊ทธ ์ด์ํ ๋จ์ด๋ฅผ ์ฒ์๋ถํฐ ์ข์ํ์ง ์์ต๋๋ค.
๊ทธ๋์ ์ ๋ React ์ปดํฌ๋ํธ์์ Promise๋ฅผ ๊ณ์ ์ฌ์ฉํฉ๋๋ค.
๋ฌธ์ ์ ๋ฐ์ ๊ฑธ์ณ ์ฝํฌ์์ ์ฝ์์ ๋ฐํํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
@gaearon ๋ค, ๊ทธ๊ฒ ์ ๊ฐ ๋งํ๋ ๊ฒ์
๋๋ค : on_click() { dispatch(load_stuff()).then(show_modal('done')) }
๊ทธ๋ ๊ฒ ํ ๊ฒ์
๋๋ค.
์์ง๋ ๋ญ๊ฐ ๋น ์ง ๊ฒ ๊ฐ์์.
redux-thunk์ README๋ฅผ ์ฐธ์กฐํ์ญ์์ค.
"์ปดํฌ์ง์
"์น์
์์ ์ฝํฌ ์ก์
์์ฑ์๋ฅผ ์ฐ๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค.
@gaearon ๋ค, ์ ํํ ์ ๊ฐํ๋ ์ผ์ ๋๋ค.
store.dispatch(
makeASandwichWithSecretSauce('My wife')
).then(() => {
console.log('Done!');
});
์์์ ์ผ๋ ๊ทธ๋๋ก์ ๋๋ค.
on_click()
{
dispatch(load_stuff())
.then(() => show_modal('done'))
.catch(() => show_error('not done'))
}
README ์น์ ์ ์ ์์ฑ๋์ด ์์ต๋๋ค.
์๋, ๋ด ๋ง์ด ์๋์ผ. makeSandwichesForEverybody
์ดํด๋ณด์ธ์. ๋ค๋ฅธ ์ฝํฌ ์ก์
์ ์์๋ฅผ ๋ถ๋ฅด๋ ์ฝํฌ ์ก์
์ ์์์
๋๋ค. ์ด๊ฒ์ด ์ปดํฌ๋ํธ์ ๋ชจ๋ ๊ฒ์ ๋ฃ์ ํ์๊ฐ์๋ ์ด์ ์
๋๋ค. ์ด์ ๋ํ ์์ธํ ๋ด์ฉ์์ด ์ ์ฅ์์ async
์์ ๋ฅผ ์ฐธ์กฐํ์ญ์์ค.
@gaearon ํ์ง๋ง ๋ด ๋ฉ์ง ์ ๋๋ฉ์ด์
์ฝ๋๋ฅผ ์ก์
์ ์์์๊ฒ ๋ฃ๋ ๊ฒ์ ์ ์ ํ์ง ์์ ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
์ด ์๋ฅผ ๊ณ ๋ คํ์ญ์์ค.
button_on_click()
{
this.props.dispatch(load_stuff())
.then(() =>
{
const modal = ReactDOM.getDOMNode(this.refs.modal)
jQuery(modal).fancy_animation(1200 /* ms */)
setTimeout(() => jQuery.animate(modal, { background: 'red' }), 1500 /* ms */)
})
.catch(() =>
{
alert('Failed to bypass the root mainframe protocol to override the function call on the hyperthread's secondary firewall')
})
}
์ฌ๋ฐ๋ฅธ ๋ฐฉ๋ฒ์ผ๋ก ์ด๋ป๊ฒ ๋ค์ ์์ฑ ํ์๊ฒ ์ต๋๊น?
@ halt-hammerzeit ๋น์ ์ actionCreator๊ฐ ํ๋ผ ๋ฏธ์ค๋ฅผ ๋ฐํํ๋๋กํ์ฌ ์ปดํฌ๋ํธ๊ฐ ๋ก์ปฌ ์ปดํฌ๋ํธ ์ํ๋ฅผ ์ฌ์ฉํ์ฌ ์คํผ๋ ๋ฑ์ ๋ณด์ฌ์ค ์ ์๋๋ก ํ ์ ์์ต๋๋ค.
๊ทธ๋ ์ง ์์ผ๋ฉด ๋ณต์กํ ํ์ด๋จธ๋ฅผ ๊ด๋ฆฌํ์ฌ redux-saga๋ก ์ ๋๋ฉ์ด์ ์ ๊ตฌ๋ ํ ์ ์์ต๋๋ค.
์ด ๋ธ๋ก๊ทธ ๊ฒ์๋ฌผ์ ์ดํด๋ณด์ญ์์ค : http://jaysoo.ca/2016/01/03/managing-processes-in-redux-using-sagas/
์,์ด ๊ฒฝ์ฐ ๊ตฌ์ฑ ์์์ ๋ณด๊ดํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
(์ฐธ๊ณ : ์ผ๋ฐ์ ์ผ๋ก React์์๋ jQuery๋ฅผ ์ฌ์ฉํ์ฌ ๋ช
๋ น ์ ์ผ๋ก ๋ชจ๋ฌ์ ํ์ํ๋ ๊ฒ๋ณด๋ค ์ ์ธ์ ๋ชจ๋ธ์ ๋ชจ๋ ๊ฒ์ ์ฌ์ฉํ๋ ๊ฒ์ด ๊ฐ์ฅ ์ข์ต๋๋ค.ํ์ง๋ง ํฐ ๋ฌธ์ ๋ ์๋๋๋ค.)
@slorber ์, ์ ๋ ์ด๋ฏธ "thunks"(๋๋ ๋น์ ์ด ๋ถ๋ฅด๋ ๋ชจ๋ ๊ฒ, ์,์ด ์ด์ํ ๋จ์ด๊ฐ ๋ง์์ ๋ค์ง ์์)์์ ์ฝ์๊ณผ ๋ฌผ๊ฑด์ ๋ฐํํ๊ณ ์์ผ๋ฏ๋ก ์คํผ๋ ๋ฑ์ ์ฒ๋ฆฌ ํ ์ โโ์์ต๋๋ค.
@gaearon ์ข์, ๋ด๊ฐ ์ก์๋ค. ์ด์์ ์ธ ๊ธฐ๊ณ ์ธ๊ณ์์๋ ๋ฌผ๋ก ์ ์ธ์ ํ๋ก๊ทธ๋๋ฐ ๋ชจ๋ธ ๋ด๋ถ์ ๋จธ๋ฌผ ์ ์์ง๋ง ํ์ค์ ๊ธฐ๊ณ์ ๊ด์ ์์ ๋นํฉ๋ฆฌ์ ์ธ ์๊ตฌ๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค. ์ฌ๋๋ค์ ์์ํ 0๊ณผ 1๋ก ์๋ํ๋ ๋น์ด์ฑ์ ์ธ ์กด์ฌ์ด๋ฉฐ ๋นํฉ๋ฆฌ์ ์ธ ์์ ์ ์ํํ๊ธฐ ์ํด ์ฝ๋์ ์๋ฆ๋ค์๊ณผ ์์์ฑ์ ์์์์ผ์ผํฉ๋๋ค.
์ด ์ค๋ ๋์ ์ง์์ ๋ง์กฑํฉ๋๋ค. ๋ด ์์ฌ์ ์ด์ ํด๊ฒฐ ๋ ๊ฒ ๊ฐ๋ค.
๊ด๋ จ ์ ํ ๋ก : https://github.com/reactjs/redux/issues/1528
@gaearon ๋งค์ฐ ๋ฉ์ง ์ค๋ช ! : ํธ๋กํผ : ๊ฐ์ฌํฉ๋๋ค : +1 :
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
๋ง์ง๋ง์ผ๋ก ๋ก๊ทธ์ธ API ํธ์ถ์ ์ด๋์ ๋ฃ์ต๋๊น?
์ด๊ฒ์ด ๋ฐ๋ก
dispatch => {}
์ก์ ํฌ๋ฆฌ์์ดํฐ์ ๋ชฉ์ ์ ๋๋ค. ๋ถ์์ฉ!๋ ๋ค๋ฅธ ์ก์ ํฌ๋ฆฌ์์ดํฐ ์ผ๋ฟ์ ๋๋ค. ๋ค๋ฅธ ์์ ๊ณผ ํจ๊ป ์ฌ์ฉํ์ญ์์ค.
๊ตฌ์ฑ ์์์์