Issue with domain tasks while doing server prerendering #1263

Closed
opened 2025-08-09 17:19:28 +00:00 by fergalmoran · 0 comments
Owner

Originally created by @LovedByTheLord on 11/15/2016

Hi,

I have a component that calls three action creators in componentWillMount. Each of these makes a call to an API to get data.

componentWillMount() {
    this.props.requestCompanyProducts();
    this.props.requestCompanies();
    this.props.requestProducts();
}

I want all of these calls to be completed on the server when the page is first loaded. However, it seems that the prerendering is completing before requestCompanies is completed.

The action creator for requestCompanies looks like this:

requestCompanies: (): ActionCreator => (dispatch, getState) => {
    if (getState().companies.companies.length === 0) {
        let fetchTask = fetch('/api/Companies/', {
            headers: {
                'Accept': 'application/json'
            }
        })
        .then(response => {
            if (response.ok) {
                response.json().then((companies: Company[]) => dispatch(new ReceiveCompanies(companies)));
            }
            else {
                response.json().then(body => dispatch(new ReceiveCompanies(undefined, body.Message)));
            }
        })
        .catch(error => {
            dispatch(new ReceiveCompanies(undefined, error));
        });
        
        addTask(fetchTask); // Ensure server-side prerendering waits for this to complete
        dispatch(new RequestCompanies());
    }
}

The reducers:

export const reducer: Reducer<CompaniesState> = (state, action) => {
    if (isActionType(action, RequestCompanies)) {
        return { isLoading: true, error: '', companies: state.companies };
    }
    else if (isActionType(action, ReceiveCompanies)) {
        return { error: '', companies: action.companies, isLoading: false };
    }

    // For unrecognized actions (or in cases where actions have no effect), must return the existing state
    // (or default initial state if none was supplied)
    return state || unloadedState;
};

The problem is that "window.initialReduxState" does not have the final result of the API call. It has the "is loading" state that exists while the app is waiting on the server call to complete.

window.initialReduxState = {"companyProducts":{"error":"","companyProducts":[{"companyProductUrlInt":4,"companyInt":30,"productInt":1,"url":"http://blah/"},{"companyProductUrlInt":1,"companyInt":30,"productInt":3,"url":"http://blah2/"},{"companyProductUrlInt":5,"companyInt":2409,"productInt":1,"url":"blah3/?q=Thisisatest"}],"isLoading":false},"companies":{"isLoading":true,"error":"","companies":[]},"products":{"error":"","products":[{"productInt":1,"name":"Product 1","code":"wot"},{"productInt":3,"name":"Product 2","code":"won"}],"isLoading":false},"routing":{"locationBeforeTransitions":null}};

This causes the API to be called again from the browser. I set a breakpoint in the API endpoint and it does get hit during the prerendering. Twice, in fact, and I can't figure out why it gets called twice. Once in a blue moon, the initial state will contain the companies list as expected. The company list is quite large (2000+ records). I'm wondering if there is a timing thing going on.

I added a Task.Delay to the API endpoint that gets called by this.props.requestProducts(). In that case the companies list was properly added to the initial state.

I'm at a loss as to how to test this further because I don't know how to debug the javascript that gets called by node during prerendering.

Any ideas what might be happening or how I can debug the node process to see what it's doing?

*Originally created by @LovedByTheLord on 11/15/2016* Hi, I have a component that calls three action creators in componentWillMount. Each of these makes a call to an API to get data. componentWillMount() { this.props.requestCompanyProducts(); this.props.requestCompanies(); this.props.requestProducts(); } I want all of these calls to be completed on the server when the page is first loaded. However, it seems that the prerendering is completing before requestCompanies is completed. The action creator for requestCompanies looks like this: requestCompanies: (): ActionCreator => (dispatch, getState) => { if (getState().companies.companies.length === 0) { let fetchTask = fetch('/api/Companies/', { headers: { 'Accept': 'application/json' } }) .then(response => { if (response.ok) { response.json().then((companies: Company[]) => dispatch(new ReceiveCompanies(companies))); } else { response.json().then(body => dispatch(new ReceiveCompanies(undefined, body.Message))); } }) .catch(error => { dispatch(new ReceiveCompanies(undefined, error)); }); addTask(fetchTask); // Ensure server-side prerendering waits for this to complete dispatch(new RequestCompanies()); } } The reducers: export const reducer: Reducer<CompaniesState> = (state, action) => { if (isActionType(action, RequestCompanies)) { return { isLoading: true, error: '', companies: state.companies }; } else if (isActionType(action, ReceiveCompanies)) { return { error: '', companies: action.companies, isLoading: false }; } // For unrecognized actions (or in cases where actions have no effect), must return the existing state // (or default initial state if none was supplied) return state || unloadedState; }; The problem is that "window.initialReduxState" does not have the final result of the API call. It has the "is loading" state that exists while the app is waiting on the server call to complete. window.initialReduxState = {"companyProducts":{"error":"","companyProducts":[{"companyProductUrlInt":4,"companyInt":30,"productInt":1,"url":"http://blah/"},{"companyProductUrlInt":1,"companyInt":30,"productInt":3,"url":"http://blah2/"},{"companyProductUrlInt":5,"companyInt":2409,"productInt":1,"url":"blah3/?q=Thisisatest"}],"isLoading":false},**"companies":{"isLoading":true,"error":"","companies":[]}**,"products":{"error":"","products":[{"productInt":1,"name":"Product 1","code":"wot"},{"productInt":3,"name":"Product 2","code":"won"}],"isLoading":false},"routing":{"locationBeforeTransitions":null}}; This causes the API to be called again from the browser. I set a breakpoint in the API endpoint and it does get hit during the prerendering. Twice, in fact, and I can't figure out why it gets called twice. Once in a blue moon, the initial state will contain the companies list as expected. The company list is quite large (2000+ records). I'm wondering if there is a timing thing going on. I added a Task.Delay to the API endpoint that gets called by `this.props.requestProducts()`. In that case the companies list was properly added to the initial state. I'm at a loss as to how to test this further because I don't know how to debug the javascript that gets called by node during prerendering. Any ideas what might be happening or how I can debug the node process to see what it's doing?
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github/JavaScriptServices#1263
No description provided.