How to dispatch Redux action from stateless component when route is loaded?

前端 未结 5 1884
离开以前
离开以前 2020-12-15 17:03

Goal: when loading a react-router route, dispatch a Redux action requesting asynchronic Saga worker to fetch data for the underlying stateless component of

5条回答
  •  情歌与酒
    2020-12-15 17:31

    In general, I don't think this is possible without some kind of trigger action which is dispatched when the component is mounted/rendered for the first time. You've achieved this by making mapDispatchToProps impure. I 100% agree with Sebastien that this is a bad idea. You could also move the impurity to the render function, which is even worse. The component lifecycle methods are meant for this! His HOC solution makes sense, if you don't want to have to write out the component classes.

    I don't have much to add, but in case you just wanted to see the actual saga code, here's some pseudocode, given such a trigger action (untested):

    // takes the request, *just a single time*, fetch data, and sets it in state
    function* loadDataSaga() {
        yield take(myActionTypes.DATA_GET_REQUEST)
        const data = yield call(fetchData)
        yield put({type: myActionTypes.SET_DATA, data})
    }
    
    function* mainSaga() {
        yield fork(loadDataSaga);
        ... do all your other stuff
    }
    
    function myReducer(state, action) {
        if (action.type === myActionTypes.SET_DATA) {
             const newState = _.cloneDeep(state)
             newState.whatever.data = action.data
             newState.whatever.loading = false
             return newState
        } else if ( ... ) {
             ... blah blah
        }
        return state
    }
    
    const MyStatelessComponent = (props) => {
      if (props.loading) {
        return 
      }
      return 
    }
    
    const mapStateToProps = (state) => state.whatever;
    const mapDispatchToProps = (dispatch) => {
        // catched by a Saga watcher, and further delivered to a Saga worker that asynchronically fetches data to the store
        dispatch({ type: myActionTypes.DATA_GET_REQUEST });
        return {};
    };
    

    plus the boilerplate:

    const sagaMiddleware = createSagaMiddleware();
    
    export default connect(mapStateToProps, mapDispatchToProps)(MyStatelessComponent);
    
    const store = createStore(
      myReducer,
      { whatever: {loading: true, data: null} },
      applyMiddleware(sagaMiddleware)
    );
    sagaMiddleware.run(mainSaga)
    

提交回复
热议问题