2017-12-19 33 views
0

나는 잠시 동안 Redux-Saga를 내 React/Redux 응용 프로그램에 통합하려고 노력해 왔으며, 누락 된 일부 핵심 요소가 있습니다 (작동하지 않으므로). rootSaga 기능에Redux-Saga에서 누락 된 점은 무엇입니까?

  1. , 나는 특정 작업이 발생하는 것을 감시하는 '감시자를 "오프 포크 다음과 같이

    이 작동하도록되어 방법의 나의 이해이다.

  2. 감시자가 작업을 볼 때 해당 작업에 대한 처리기를 호출하고 완료 될 때 적절한 성공/실패 작업을 호출합니다.
  3. 관찰자가 볼 수 있도록 조치를 지정하려면 put 또는 call을 사용해야합니다.

다음은 작동하기 위해 (개념적으로) 익숙해 진 코드입니다. (코드는 급하게 익명으로 처리되었으므로 오타를 용서하십시오.)

내 sagas.ts 파일 :

import { all, call, fork, put, takeLatest} from 'redux-saga/effects'; 
import { fromJS } from 'immutable'; 
import AppRedux, { IAction } from 'app/containers/App/reducers'; 

const fetchData = async (id: string, name: string): Promise<any> => { 
    console.log('calling fetchData'); 
    const resource = `someurl?id=${id}`; 
    const data = await((await fetch(resource)).json()); // request(resource); 
    console.log('returning fetchData'); 
    return fromJS({ 
     id: id, 
     name, 
     data, 
    }); 
}; 

const callFetchData = function* callFetchData(action: IAction) { 
    console.log('calling callFetchData*'); 
    try { 
     const result = yield call(fetchData, action.id, action.name); 
     yield put({ 
      type: AppRedux.Action.DATA_FETCHED, 
      result, 
     }); 
    } catch (error) { 
     yield put({ 
      type: AppRedux.Action.FETCH_FAILED, 
      error, 
     }); 
    } 
    console.log('exiting callFetchData*'); 
}; 

const watchCallFetchData = function* watchCallFetchData(action: IAction): IterableIterator<any> { 
    console.log('calling watchCallFetchData*'); 
    yield* takeLatest(AppRedux.Action.FETCH_DATA, callFetchData, action)[Symbol.iterator]; 
    console.log('exiting watchCallFetchData*'); 
}; 

export function* rootSaga(action: IAction): IterableIterator<any> { 
    console.log('calling rootSaga*'); 

    const watcher = yield all([ 
     fork(watchCallFetchData, action), 
    ]); 

    console.log('exiting rootSaga*'); 
} 

export default [ 
    rootSaga, 
]; 

내 routes.ts 파일 :

import { RouterState } from 'react-router'; 
import { ComponentCallback, errorLoading, loadModule } from 'app/routes'; 
import AppRedux from 'app/containers/App/reducers'; 
import { call, put } from 'redux-saga/effects'; 

path: '/somepath/:id', 
async getComponent(nextState: RouterState, cb: ComponentCallback) { 
    try { 
     const renderRoute = loadModule(cb); 
     const [reducer, sagas, component] = await importModules(); 

     const id = nextState.params.id; 
     const name = ''; 
     const action = { 
      id, 
      name, 
      type: AppRedux.Action.FETCH_DATA, 
     }; 

     console.log('routes.ts pre-put fetch_data'); 
     const putResult = put(action); 
     console.log('routes.ts post-put fetch_data'); 

     return renderRoute(component); 
    } catch (err) { 
     errorLoading(cb)(err); 
    } 
}, 

내 app.tsx 파일 : 여기

import * as React from 'react'; 
import * as ReactRouter from 'react-router'; 
import { connect, DispatchProp } from 'react-redux'; 
import AppRedux from 'app/containers/App/reducers'; 
import { createStructuredSelector } from 'reselect'; 
import { selectid, selectResponses, selectname } from 'app/containers/App/selectors'; 
import { ISection } from './data'; 


export class App extends React.Component<IProps, {}> { 
    constructor(props: Readonly<IProps>) { 
     super(props); 
     console.log('app-constructor'); 
    } 

    public render() { 
     console.log('app-render'); 
     return (<div className="app" />); 
    } 
} 

export default connect<{}, {}, IProps>(
    createStructuredSelector({ 
     id: selectId(), 
     data: selectData(), 
     name: selectName(), 
    }), 
    (dispatch) => ({ 
     fetchData: (id: string, name: string) => dispatch(AppRedux.fetchData(id, name)), 
     dispatch, 
    }), 
)(App); 

console.log의 출력입니다 전화 :

calling rootSaga* 
calling watchCallFetchData* 
exiting watchCallFetchData* 
exiting rootSaga* 
routes.ts pre-put fetch_data 
routes.ts post-put fetch_data 
app-constructor 
app-render 

편집 : 명확한 설명 나는 일이 기대

:

  1. 내가 실제로 뭔가를 할 수있는 사가 액션과 돌아 오는-사가를 위해 파견하는 put(action)를 기대합니다.
  2. 나는 함수 callFetchData을 호출 할 것이고, 비슷하게 fetchData을 호출 할 것으로 기대한다.
  3. console.log에서 exiting watchCallFetchData*을보기 전에 두 호출이 모두 발생하기를 기대합니다.
  4. (어느 시점에서) "A-ha!" 순간.

    1. rootSaga* 함수가 호출됩니다 : 실제로 무슨 일

    .

  5. watchCallFetchData*이 두 번 호출됩니까? (가정은 yield 진술이 가정 한 내용을 기반으로합니다).
  6. rootSaga* 함수가 다시 호출됩니다. (가정은 yield 진술이 가정 한 내용을 기반으로합니다).
  7. "A-ha!" 순간이 나를 계속 피합니다.
+0

3의 경우, 감시자가 선택하도록하려면 'put'을 사용하여 작업을 전달하십시오. –

+0

질문을 수정해야한다고 생각합니다. 코드는 무엇을하고 무엇을하기를 기대합니까? 사가가 발동되지 않습니까? 문제가 정확히 무엇입니까? –

+0

@CoryDanielson은 "3"으로 3 번째 코드 파일을 의미합니까? 나는 내 노선에'put '을 사용하고 있습니다 .ts .. – pete

답변

1

나는이 문제를 볼 수 있습니다

1. yield 대신 yield*가 : 당신의 * (슈퍼 스타)없이 yield를 사용한다 :

yield* takeLatest(AppRedux.Action.FETCH_DATA,... 

yield*가 확산입니다 운영자는 내부의 모든 호출을 서브 루틴으로 간단히 가져와 매크로 기능 yield* docs으로 확장합니다. 과 takeLatest이 사용되지 않았습니다. 동작 매개 변수가 자동으로 전달됩니다를, 그래서 그냥해야한다 :

2. 매개 변수로 action을 통과하지 마십시오 action으로

yield* takeLatest(AppRedux.Action.FETCH_DATA, callFetchData) 

rootSaga() 인수로 전달되지 않는 것 undefined이되어야합니다. takeLatest 자동 callFetchDataaction 매개 변수를 전달하려고합니다 때 이미 함수가 기대되지 않는 2 매개 변수로 실제 행동을 얻을 것이다 다음 callFetchData을 인수 목록 (see the Notes section in takeLatest docs) & 기존에 추가합니다 , 그래서 그것은 통과하지 않을 것이다.

제안 :yield all() 내부적으로 병렬로 모든 통화를 실행, 그래서 우리는 그 안에 call 대신 fork을 사용해야합니다

const watcher = yield all([ 
    call(watchCallFetchData, action), 
]); 

차이 while(take()) & takeLatest() 사이 :take을에 루프가 동기 인 반면, 차단하기 때문에 원하는 작업이 발송 될 때까지 다음 줄로 이동하지 않습니다. 전체 무용담을 일시 중지합니다. takeLatest()은 비동기 비 차단 스레드를 분기하여 원하는 작업을 기다리는 반면, &은 계속해서 사가의 다음 줄을 실행합니다.

+0

변경 사항을 시도했는데 ('*'제거하고'action' 매개 변수를 전달하지 않음). 차이점은 없었습니다 (심지어'console.logs '도 같습니다). 또한'takeEvery'를 사용하지 않고'takeLatest'를 사용하고 있습니다 (답이 맞는지 아닌지는 확실하지 않습니다). – pete

+0

죄송합니다. 오타가 수정되었습니다 ('takeEvery'). 내 생각에'put'은 무용담 내부에서만 작동합니다. ** routes.ts ** 파일은'put' 대신'dispatch'을 사용해야합니까? Redux 개발자 도구 (Chrome 확장 프로그램)에서 전달 된 'FETCH_DATA' 작업이 표시됩니까? –

+0

Redux 개발자 도구에서 'FETCH_DATA'에 지정된 문자열을 볼 수 있습니다. '@@ router/LOCATION_CHANGE' 다음에 발생하지만 해당 함수의'console.log' 호출은 결코 적중하지 않습니다. – pete

0

@Ali Saeed가 제안한 변경 사항은 제게 맞습니다. 그러나 주된 문제는 put 내부의 사용이 routes.ts 인 것으로 생각됩니다.

redux-saga가 운영하는 발전기 (saga) 내부에서만 작동합니다. 당신의 routes.ts에서

는 그 라인이 아무것도하지 않는

const putResult = put(action); 

파일. 리턴 값을 보면 객체를 반환한다는 것을 알 수 있습니다.

당신은 당신이 너무 있음을 업데이트해야합니다 있도록

store.dispatch(action); 

이 코드를 기반으로, 가게가 가능한하지 않는 것 싶지.

+0

'put (action)'대신'store.dispatch (action);'을 시도했습니다. 아무런 효과가 없었다. 나는 또한 [Ali Saeed] (https://stackoverflow.com/users/2528761/ali-saeed)의 변경 사항을 시도했다. 여전히 효과가 없습니다. – pete

+0

상점을 만들 때'applyMiddleware'를 사용하여 rootSaga를 실행하고 있습니까? https://redux-saga.js.org/docs/introduction/BeginnerTutorial.html –

+0

번호. 먼저 상점이 생성됩니다. 루트를 통해 앱을 선택하면 내 'rootSaga'가 미들웨어에 의해 실행됩니다. – pete