ES6 제너레이터에서 redux-saga를 사용하는 것과 ES2017 비동기/대기에서 redux-thunk를 사용하는 것의 장단점
지금 레독스 타운에서는 레독스가/레독스가라는 최신 아이에 대한 이야기가 많이 나오고 있습니다.액션을 수신/디스패치하기 위해 제너레이터 기능을 사용합니다.
에 먼저 .redux-saga
어프로치 하고 있는 입니다.redux-thunk
비동기/동기/동기/동기
컴포넌트는, 통상대로 디스패치 액션을 실시합니다.
import { login } from 'redux/auth';
class LoginForm extends Component {
onClick(e) {
e.preventDefault();
const { user, pass } = this.refs;
this.props.dispatch(login(user.value, pass.value));
}
render() {
return (<div>
<input type="text" ref="user" />
<input type="password" ref="pass" />
<button onClick={::this.onClick}>Sign In</button>
</div>);
}
}
export default connect((state) => ({}))(LoginForm);
그러면 내 행동은 다음과 같습니다.
// auth.js
import request from 'axios';
import { loadUserData } from './user';
// define constants
// define initial state
// export default reducer
export const login = (user, pass) => async (dispatch) => {
try {
dispatch({ type: LOGIN_REQUEST });
let { data } = await request.post('/login', { user, pass });
await dispatch(loadUserData(data.uid));
dispatch({ type: LOGIN_SUCCESS, data });
} catch(error) {
dispatch({ type: LOGIN_ERROR, error });
}
}
// more actions...
// user.js
import request from 'axios';
// define constants
// define initial state
// export default reducer
export const loadUserData = (uid) => async (dispatch) => {
try {
dispatch({ type: USERDATA_REQUEST });
let { data } = await request.get(`/users/${uid}`);
dispatch({ type: USERDATA_SUCCESS, data });
} catch(error) {
dispatch({ type: USERDATA_ERROR, error });
}
}
// more actions...
redux-saga에서 위의 예시와 동등한 것은 다음과 같습니다.
export function* loginSaga() {
while(true) {
const { user, pass } = yield take(LOGIN_REQUEST)
try {
let { data } = yield call(request.post, '/login', { user, pass });
yield fork(loadUserData, data.uid);
yield put({ type: LOGIN_SUCCESS, data });
} catch(error) {
yield put({ type: LOGIN_ERROR, error });
}
}
}
export function* loadUserData(uid) {
try {
yield put({ type: USERDATA_REQUEST });
let { data } = yield call(request.get, `/users/${uid}`);
yield put({ type: USERDATA_SUCCESS, data });
} catch(error) {
yield put({ type: USERDATA_ERROR, error });
}
}
할 것은 를 API 입니다.yield call(func, ...args)
call
게 ' 좋다' 같은 단순한 요.단순한 오브젝트를 생성할 뿐입니다.{type: 'CALL', func, args}
을 위임하고그 redux-saga middleware는 redux-saga middleware, generator는 redux-saga middleware, generator.
주요 장점은 간단한 등식 검사를 사용하여 Redux 외부에서 생성기를 검정할 수 있다는 것입니다.
const iterator = loginSaga()
assert.deepEqual(iterator.next().value, take(LOGIN_REQUEST))
// resume the generator with some dummy action
const mockAction = {user: '...', pass: '...'}
assert.deepEqual(
iterator.next(mockAction).value,
call(request.post, '/login', mockAction)
)
// simulate an error result
const mockError = 'invalid user/password'
assert.deepEqual(
iterator.throw(mockError).value,
put({ type: LOGIN_ERROR, error: mockError })
)
호출 api 호출 를 api에 하는 것 입니다.next
반복기의 메서드.데이터를 조롱하는 것은 기능을 조롱하는 것보다 훨씬 간단합니다.
해야 할 은 '콜입니다.yield take(ACTION)
액액예예예, 을을을을을을)에 대해 LOGIN_REQUEST
). 즉, 액션은 지속적으로 thunks에 푸시되며, thunks는 이러한 액션의 처리를 정지할 타이밍을 제어할 수 없습니다.
레독스가에서는 발전기가 다음 액션을 당깁니다.즉, 어떤 액션을 들을 때와 들을 때를 제어할 수 있습니다.위의 예에서는 플로우 지시가 내부로 배치되어 있습니다.while(true)
루프를 통해 들어오는 각 동작을 듣습니다. 이는 쿵크 푸쉬 동작과 어느 정도 유사합니다.
풀 어프로치를 사용하면 복잡한 제어 플로우를 구현할 수 있습니다.예를 들어 다음과 같은 요건을 추가한다고 가정합니다.
LOGOUT 사용자 작업 처리
로그인에 는 토큰을 이 토큰은 어느 이 만료되어 「」에됩니다.이 토큰은 에 저장되어 있는 지연으로 만료됩니다.
expires_in
각 각각의 허가서를 백그라운드에서 갱신해야 합니다.expires_in
(밀리초 단위API 콜의 결과(초기 로그인 또는 리프레시 중 하나)를 기다리는 경우 사용자가 중간에 로그아웃할 수 있음을 고려하십시오.
전체 흐름에 대한 완전한 테스트 범위를 제공하면서 어떻게 탠크를 사용하여 이를 구현합니까?Sagas는 다음과 같습니다.
function* authorize(credentials) {
const token = yield call(api.authorize, credentials)
yield put( login.success(token) )
return token
}
function* authAndRefreshTokenOnExpiry(name, password) {
let token = yield call(authorize, {name, password})
while(true) {
yield call(delay, token.expires_in)
token = yield call(authorize, {token})
}
}
function* watchAuth() {
while(true) {
try {
const {name, password} = yield take(LOGIN_REQUEST)
yield race([
take(LOGOUT),
call(authAndRefreshTokenOnExpiry, name, password)
])
// user logged out, next while iteration will wait for the
// next LOGIN_REQUEST action
} catch(error) {
yield put( login.error(error) )
}
}
}
예에서는 race
.take(LOGOUT)
경주에서 우승합니다(즉, 사용자가 로그아웃 버튼을 클릭).됩니다.authAndRefreshTokenOnExpiry
그 일이 일어난다면authAndRefreshTokenOnExpiry
call(authorize, {token})
콜도 취소됩니다.취소는 자동으로 아래로 전파됩니다.
도서관 저자의 꽤 철저한 답변에 덧붙여, 제작 시스템에 사가를 사용한 경험을 추가한다.
Pro(saga 사용):
테스트 가능성sags를 테스트하는 것은 매우 간단합니다.call()은 순수 객체를 반환하기 때문입니다.트렁크를 테스트하려면 보통 테스트에 mockStore를 포함해야 합니다.
redux-timeout에는 태스크에 관한 유용한 도우미 기능이 많이 포함되어 있습니다.saga의 개념은 리액트 리덕스 아키텍처에서 누락된 부분으로 기능하는 앱의 백그라운드 워커/스레드를 만드는 것이라고 생각합니다(action Creators와 Reducer는 순수한 함수여야 합니다).다음 포인트로 이어지죠
사가들은 모든 부작용을 처리할 수 있는 독립적인 장소를 제공한다.내 경험상 thunk 액션보다 보통 수정하고 관리하는 것이 더 쉽다.
단점:
제너레이터 구문
배워야 할 컨셉이 많네요.
API 안정성redux-saga는 아직 기능(예를 들어 Channels?)을 추가하고 있는 것 같고, 커뮤니티는 그다지 크지 않습니다.라이브러리가 언젠가 하위 호환성이 없는 업데이트를 할 경우 문제가 있습니다.
제 개인적인 경험에서 몇 가지 코멘트를 추가하고 싶습니다(sagas와 thunk를 모두 사용).
Saga는 테스트에 최적입니다.
- 효과로 포장된 기능을 시뮬레이션할 필요가 없습니다.
- 따라서 테스트는 깨끗하고 읽기 쉬우며 쓰기 쉽습니다.
- saga를 사용할 때 액션 크리에이터는 대부분 일반 객체 리터럴을 반환합니다.그것은 또한 덩크의 약속과 달리 테스트하고 주장하기가 더 쉽다.
사가는 더 강력하다.하나의 Thunk의 액션 크리에이터로 할 수 있는 모든 것은 하나의 사가로도 할 수 있지만, 그 반대는 할 수 없습니다(적어도 쉽지는 않습니다).예를 들어 다음과 같습니다.
take
)- 루틴을
cancel
,takeLatest
,race
) - 액션을 수 (리슨할 수 있습니다.
take
,takeEvery
, ... )
Sagas는 몇 가지 일반적인 애플리케이션 패턴을 일반화하는 기타 유용한 기능도 제공합니다.
channels
외부 이벤트 소스(예: 웹소켓)를 청취합니다.- 모델Fork Model)
fork
,spawn
) - 스로틀
- ...
사가는 위대하고 강력한 도구입니다.하지만 힘에는 책임이 따른다.어플리케이션이 커지면 액션이 디스패치되기를 기다리는 사람이나 액션이 디스패치될 때 일어나는 모든 일을 파악함으로써 쉽게 잃어버릴 수 있습니다.반면에 덩크는 더 간단하고 쉽게 추론할 수 있다.하나 또는 다른 하나를 선택하는 것은 프로젝트의 유형 및 크기, 프로젝트가 처리하거나 팀 선호도를 개발해야 하는 부작용 유형 등 여러 측면에 따라 달라집니다.어떤 경우에도 애플리케이션을 단순하고 예측 가능한 상태로 유지하십시오.
2020년 7월 갱신:
지난 16개월 동안 React 커뮤니티에서 가장 눈에 띄는 변화는 React 훅입니다.
제가 관찰한 바에 따르면 기능 컴포넌트 및 후크와의 호환성을 높이기 위해 프로젝트(대형 프로젝트라도)는 다음을 사용하는 경향이 있습니다.
- hook + async thunk (hook은 모든 것을 매우 유연하게 만듭니다.따라서 실제로 비동기 thunk를 원하는 위치에 배치하여 일반 함수로 사용할 수 있습니다.예를 들어 tunk in action.ts를 쓰고 Dispatch()를 사용하여 thunk를 트리거할 수 있습니다.
- useRequest,
- GraphQL/Apollo
useQuery
useMutation
- 반응 페칭 개재성의
- 데이터 가져오기/API 콜 라이브러리, 도구, 설계 패턴 등의 기타 일반적인 선택지
에 비해, 「 」는 「 」입니다.redux-saga
로선 위의 큰 많은 사가 으로써 프로젝트의 최신 1.의 최신 릴리스이기 때문입니다v1.1.1)을 클릭합니다.redux-saga
2019년 9월 18일.오래 전입니다).
하지만 여전히,redux-saga
는 레이싱 효과나 병렬 요구 등 몇 가지 고유한 기능을 제공합니다.이러한에는 다음과 같은 이 필요합니다.redux-saga
여전히 좋은 선택입니다.
2019년 3월 오리지널 투고:
몇 가지 개인적인 경험:
코딩 스타일과 가독성을 위해 과거에 redux-saga를 사용했을 때의 가장 큰 장점 중 하나는 redux-thunk의 콜백헬을 피할 수 있다는 것입니다.즉, 많은 네스트/캐치를 사용할 필요가 없어집니다.그러나 현재 비동기/await thunk가 유행하고 있기 때문에 redux-thunk를 사용할 때 동기 스타일로 비동기 코드를 작성할 수도 있습니다.이것은 redux-thunk의 향상으로 간주될 수 있습니다.
특히 Typescript에서 redux-saga를 사용할 때는 훨씬 더 많은 보일러 플레이트 코드를 작성해야 할 수 있습니다.예를 들어 fetch 비동기 함수를 구현하는 경우 데이터와 오류 처리는 단일 FETH 액션으로 action.js의 하나의 thunk 단위로 직접 수행할 수 있습니다.그러나 redux-saga에서는 FETCH_START, FETCH_SUCCESS 및 FETCH_FAILURE 액션과 관련된 모든 유형 체크를 정의해야 할 수 있습니다.redux-saga의 기능 중 하나는 이러한 종류의 풍부한 "토큰" 메커니즘을 사용하여 쉽게 효과를 생성하고 redux 저장소를 지시하는 것이기 때문입니다.물론 이런 행동을 하지 않고도 사가를 쓸 수 있지만, 그것은 덩크와 비슷할 것이다.
파일 구조면에서는 redux-saga가 더 명확한 경우가 많은 것 같습니다.모든 sagas.ts에서 비동기 관련 코드를 쉽게 찾을 수 있지만, redux-thunk에서는 동작에서 이를 확인할 필요가 있습니다.
간단한 테스트는 레독스가의 또 다른 가중치 기능이 될 수 있습니다.이것은 정말 편리합니다.단, redux-saga "call" 테스트는 테스트에서 실제 API 호출을 수행하지 않으므로 API 호출 후에 사용할 수 있는 스텝의 샘플 결과를 지정해야 합니다.따라서 redux-saga로 쓰기 전에 사가와 그에 대응하는 sagas.spec.ts를 상세하게 계획하는 것이 좋습니다.
또한 Redx-saga는 병렬 태스크 실행, takeLatest/takeEvery, fork/spawn 등의 많은 고급 기능을 제공합니다.
결론적으로 저는 개인적으로 많은 경우나 중소형 앱에서는 비동기식/대기식 redux-thunk를 사용합니다.이렇게 하면 많은 보일러 플레이트 코드/액션/타이프를 절약할 수 있으며, 여러 sagas.t를 전환하여 특정 sagas 트리를 유지할 필요가 없습니다.그러나 매우 복잡한 비동기 로직과 동시성/병렬 패턴 등의 기능이 필요한 대규모 앱을 개발 중이거나 테스트 및 유지 보수(특히 테스트 기반 개발)에 대한 수요가 많은 경우 redux-sagas를 사용하면 생명을 구할 수 있습니다.
어쨌든 redex-saga는 redex 자체보다 어렵고 복잡하지 않으며, 핵심 개념과 API가 한정되어 있어 이른바 가파른 학습 곡선을 가지고 있지 않다.레덕스가를 배우는 데 적은 시간을 소비하는 것이 언젠가 자신에게 도움이 될지도 모른다.
Sagas는 제 경험에서 몇 가지 다른 대규모 React/Redux 프로젝트를 검토한 결과, 훨씬 테스트하기 쉽고 틀리기 어려운 코드 작성 방법을 개발자에게 제공했습니다.
.는 항상 에게 무슨 걱정 .yield
첫 번째로 몇 가지 테스트를 작성하면 바로 알 수 있습니다.
나는 몇몇 프로젝트들을 보아왔다. 그들은 마치 MVC패튼의 컨트롤러처럼 취급되어왔고 이것은 곧 명백한 혼란이 되었다.
A가 필요로 하는 곳에 Sagas를 사용하는 것이 좋습니다.단일 이벤트와 관련된 B타입의 것을 트리거합니다.여러 액션을 절단할 수 있는 경우는 커스텀 미들웨어를 작성하고 FSA 액션의 메타 속성을 사용하여 트리거하는 것이 더 간단하다고 생각합니다.
Thunks vs Sagas
Redux-Thunk
★★★★★★★★★★★★★★★★★」Redux-Saga
몇 가지 중요한 점에서 둘 다 Redux용 미들웨어 라이브러리입니다(Redux 미들웨어는 dispatch() 메서드를 통해 스토어에 들어오는 액션을 대행 수신하는 코드입니다).
액션은 말 그대로 모든 것이 될 수 있지만 베스트 프랙티스를 따를 경우 액션은 유형 필드 및 옵션 페이로드, 메타 및 오류 필드가 있는 일반 javascript 개체입니다.
const loginRequest = {
type: 'LOGIN_REQUEST',
payload: {
name: 'admin',
password: '123',
}, };
리덕스-펑크
액션을 하는 것 에,Redux-Thunk
하면, 「중간 기능」이라고 하는 한 기능을 할 수 .thunks
.
Thunks(Redux의 경우)는 일반적으로 다음과 같은 구조를 가지고 있습니다.
export const thunkName =
parameters =>
(dispatch, getState) => {
// Your application logic goes here
};
아, 아, 아, 아.thunk
는 (임의로) 일부 파라미터를 취득하고 다른 함수를 반환하는 함수입니다.는 ""를 합니다.dispatch function
a. a. a.getState
-둘 다 함수에 의해 됩니다.Redux-Thunk
미들웨어
레독스가
Redux-Saga
미들웨어를 사용하면 복잡한 애플리케이션 로직을 sagas라고 하는 순수한 함수로 표현할 수 있습니다.순수 함수는 예측 가능하고 반복 가능하기 때문에 검정 관점에서 바람직하며, 따라서 비교적 쉽게 검정할 수 있습니다.
사가는 발전기 기능이라고 불리는 특별한 기능을 통해 구현된다.은 것들은 these these these these these these these these these of of의 새로운 특징입니다.의 입니다.ES6 JavaScript
기본적으로 항복문을 볼 때마다 제너레이터를 드나들며 실행이 이루어집니다.★★★★★★★★★★★★★★★★를 생각해 주세요.yield
생성기가 일시 중지되어 반환된 값을 반환하는 것으로 간주됩니다. 후,는 「 」, 「 」, 「 」, 「 」에 할 수 .yield
.
제너레이터 함수는 다음과 같이 정의됩니다.function 키워드 뒤에 아스타리스크가 붙어 있는 것에 주의해 주세요.
function* mySaga() {
// ...
}
가 「」에 되면,Redux-Saga
그 ★★★★★★★★★★★★★★★★★★★★★★★.yield
수행은 이 "예"인 중지됩니다.'LOGIN_REQUEST'
가게로 발송됩니다.그러면 실행이 계속됩니다.
짧은 메모 하나.제너레이터는 취소 가능, 비동기/대기 가능 - 아닙니다.질문에서 예를 들면, 무엇을 선택해야 하는지 이해가 되지 않습니다.그러나 복잡한 흐름의 경우 발전기를 사용하는 것보다 더 나은 해결책은 없을 수 있습니다.
또 다른 아이디어는 레독스 트렁크를 가진 발전기를 사용하는 것입니다만, 저는 네모난 바퀴를 가진 자전거를 발명하려고 하는 것 같습니다.
물론 발전기는 테스트하기가 더 쉽습니다.
두 가지 장점을.redux-saga
★★★★★★★★★★★★★★★★★」redux-thunk
: 에 대한 할 수 은 사가에 대한 것입니다.dispatching
대응하는 액션:https://github.com/diegohaz/redux-saga-thunk
class MyComponent extends React.Component {
componentWillMount() {
// `doSomething` dispatches an action which is handled by some saga
this.props.doSomething().then((detail) => {
console.log('Yaay!', detail)
}).catch((error) => {
console.log('Oops!', error)
})
}
}
나는 최근에 이 프로젝트를 많이 활용했습니다.redux-saga
사가의 더 것을 .
TBH, 아직 찾고 있어요.이 글을 읽고 많은 사람들이 좋아하기 때문에, '프로'는 이해하기 어렵다.위의 답변은 다음과 같이 요약됩니다.
- 테스트 가능성(실제 API 콜 무시),
- 많은 도우미 기능,
- 서버측 코딩에 익숙한 개발자에게 친숙합니다.
다른 많은 주장들은 낙관적이고, 오해의 소지가 있거나, 단순히 잘못된 것처럼 보입니다!예를 들어, "엉뚱이는 X를 할 수 없다"는 부당한 주장을 많이 봐왔습니다.하지만 스컹크는 기능이다.함수가 X를 할 수 없는 경우 Javascript는 X를 할 수 없습니다.그래서 사가도 X를 할 수 없다.
나에게 있어 단점은 다음과 같다.
- 의 교란
generator
커스텀 합니다.JS의 생성기는 사용자 지정 반복기를 반환합니다.할 수 있는 .비동기 콜을 처리하거나 취소할 수 있는 특별한 기능은 없습니다.모든 루프에는 브레이크아웃 조건이 있을 수 있으며, 모든 함수는 비동기 요구를 처리할 수 있으며, 모든 코드는 커스텀 반복기를 사용할 수 있습니다.이 다음과을 할 때:generators have control when to listen for some action
★★★★★★★★★★★★★★★★★」generators are cancellable, but async calls are not
그런 다음 이러한 특성이 발전기 기능에 내재되어 있거나 심지어 고유하다는 것을 암시함으로써 혼란을 일으킨다. - 불분명한 사용 사례: AFAIK SAGA 패턴은 서비스 간 동시 트랜잭션 문제를 처리하기 위한 것입니다.스레드이기 이 어떻게 알 수.
Promise
를 알 수 BTW: 또한 왜 그 종류의 문제를 브라우저에서 처리해야 하는지 이해하기 어렵습니다. - 하여 레덕스를 바꿈
dispatch
Sagas는 리듀서에 도달하지 않는 액션을 이벤트 처리와 같은 형태로 디스패치하기 때문에 Redux 툴에 기록되지 않습니다.다른 라이브러리도 이 작업을 수행하지만 브라우저에 이벤트 처리가 내장되어 있기 때문에 이 작업은 종종 불필요하게 복잡합니다.간접의 이점은 다시 이해하기 어려운데, 이는 사가를 직접 호출하는 것이 더 명확하기 때문입니다.
만약 이 투고가 내가 사가에게 좌절감을 느낀다면, 그것은 내가 사가에게 좌절감을 느꼈기 때문이다.그들은 해결할 문제를 찾는 훌륭한 해결책처럼 보인다.IMO.
보다 쉬운 방법은 redux-auto를 사용하는 것입니다.
문서상
redux-auto는 약속을 반환하는 "액션" 함수를 만드는 것만으로 이 비동기 문제를 해결했습니다."기본" 기능 동작 로직을 수반합니다.
- Thunk, Promise-Middleware, saga 등 다른 Redux 비동기 미들웨어가 필요 없음
- 쉽게 약속을 리덕스로 전달하여 관리할 수 있습니다.
- 외부 서비스 콜을 변환하는 장소와 함께 배치할 수 있습니다.
- 파일의 이름을 "init.js"로 지정하면 앱 시작 시 한 번 호출됩니다.이것은 시작할 때 서버에서 데이터를 로드하는 데 유용합니다.
각 액션을 특정 파일에 저장하여 서버 호출을 "보류", "완료" 및 "거부"를 위한 리듀서 함수와 함께 파일 내에 배치하는 것이 아이디어입니다.이를 통해 약속을 쉽게 처리할 수 있습니다.
또한 도우미 개체("async")를 상태 프로토타입에 자동으로 첨부하여 UI에서 요청된 전환을 추적할 수 있습니다.
언급URL : https://stackoverflow.com/questions/34930735/pros-cons-of-using-redux-saga-with-es6-generators-vs-redux-thunk-with-es2017-asy
'programing' 카테고리의 다른 글
Gradle을 사용하여 JaCoCo 커버리지 보고서 필터링 (0) | 2022.09.28 |
---|---|
캐시된 PHP 생성 미리 보기가 느리게 로드됩니다. (0) | 2022.09.28 |
구성 요소에서 Vuex 데이터스토어를 찾을 수 없습니다. (0) | 2022.09.21 |
Java 제네릭 T 대 객체 (0) | 2022.09.21 |
컨피규레이션파일 비밀번호 암호화 (0) | 2022.09.21 |