Search code examples
reactjsreduxredux-thunknext.js

how can i dispatch store and override initial props in nextjs


I want to call API inside getInitialProps then save that response in redux store.so how can I call dispatch store and override initial props

right now after fetching data from API, I'm able to dispatch value to the reducer and it also saving data in store but after saving data my app calling for initial props(i don't know from where it changes the states) and overriding my new saved data into initial props.

main.js

class StepThree extends React.Component {
static async getInitialProps({ reduxStore, req }) {
    let encID = req.query.id //null
    try {
        let encode = await encrption(encID,7,'dec')
        const apiCall = await fetch(`${config.leadSearchApi}&search_param=${encode}`);
        let res = await apiCall.json();
        if(res.data['next_action'] !== "converted"){
            let test = await reduxStore.dispatch({ type: PATIENT_NAME,payload:res.data.name });
            console.log(test,'res');
            await reduxStore.dispatch({ type: PATIENT_NUMBER,payload:res.data['mobile_number'] });
            await reduxStore.dispatch({ type: LEAD_ID,payload:res.data.id });
        }

        } catch (err) {
        console.log(err,'get err');
        }
    return {  }
}

render() {
    return <div>Hello World </div>
}
}

const mapStateToProps = (state, prevProps) =>{
return{
    AmbSelect:state.StepThreeReducer.isAmbSel,
    Addons:state.StepThreeReducer.addonSel,
    VehcileData:state.StepThreeReducer.vehcileData,
    TotalPrice:state.StepThreeReducer.totalPrice,
    Cameback:state.StepThreeReducer.comeback,
    LeadID:state.Main.LeadId
}
}
export default connect(mapStateToProps,{addOnSelected,priceCal,updateLeadS3,previous,VehicleDataHandler,updateVehData, addonsCount,totalPrice,existLeadData,linkLead2,linkLead3,encrption })(StepThree);

App.js

import App, { Container } from 'next/app'
import React from 'react'
import withReduxStore from '../lib/with-redux-store'
import { Provider } from 'react-redux'
class MyApp extends App {
render () {
    const { Component, pageProps, reduxStore } = this.props;


    return (
    <Container>
        <Provider store={reduxStore}>
        <Component {...pageProps} />
        </Provider>
    </Container>
    )
}
}

export default withReduxStore(MyApp)

redux-store.js

  import React from 'react'
import { initializeStore } from '../store'

const isServer = typeof window === 'undefined'
const __NEXT_REDUX_STORE__ = '__NEXT_REDUX_STORE__'

function getOrCreateStore (initialState) {
// Always make a new store if server, otherwise state is shared between requests
if (isServer) {
    return initializeStore(initialState)
}

// Create store if unavailable on the client and set it on the window object
if (!window[__NEXT_REDUX_STORE__]) {
    window[__NEXT_REDUX_STORE__] = initializeStore(initialState)
}
return window[__NEXT_REDUX_STORE__]
}

export default App => {
return class AppWithRedux extends React.Component {
    static async getInitialProps (appContext) {
    // Get or Create the store with `undefined` as initialState
    // This allows you to set a custom default initialState
    const reduxStore = getOrCreateStore()

    // Provide the store to getInitialProps of pages
    appContext.ctx.reduxStore = reduxStore

    let appProps = {}
    if (typeof App.getInitialProps === 'function') {
        appProps = await App.getInitialProps(appContext)
    }

    return {
        ...appProps,
        initialReduxState: reduxStore.getState()
    }
    }

    constructor (props) {
    super(props)
    this.reduxStore = getOrCreateStore(props.initialReduxState)
    }

    render () {
    return <App {...this.props} reduxStore={this.reduxStore} />
    }
}
}

store.js

import { createStore, applyMiddleware,combineReducers } from 'redux'
import { composeWithDevTools } from 'redux-devtools-extension'
import thunkMiddleware from 'redux-thunk'

import './actions';
import reducer from './reducers'

export function initializeStore () {
return createStore(
    reducer,
    composeWithDevTools(applyMiddleware(thunkMiddleware))
)
}

reducer.js

import {PATIENT_NAME,PATIENT_NUMBER,RIDE_DATE,RIDE_TIME,FCAUSES,SETCAUSE} from '../actions/types';
const INITIAL_STATE = {
    patient_name:'',
    patient_number:'',
    ride_date:false,
    ride_time:false,
    causes:{},
    sel_cause:''
};
export default  (state=INITIAL_STATE,action) => {
    console.log(action,'reducer')
    switch(action.type) {
        case PATIENT_NAME:
            return {...state,patient_name:action.payload};
        case PATIENT_NUMBER:
            return {...state,patient_number:action.payload};
        case RIDE_DATE:
            return {...state,ride_date:action.payload};
        case RIDE_TIME:
            return {...state,ride_time:action.payload};
        case FCAUSES:
            return {...state,causes:action.payload};
        case SETCAUSE:
            return {...state,sel_cause:action.payload};
        default:
            return state;
    }
}

enter image description here

after dispatch I don't want to make app state as initial props
please help,stuckkkkkk


Solution

  • You did't provide an initialState into initializeStore when you creating your store. To make sure that you're using the same state shape across server and client pass the initialState params to you store initialization inside store.js:

    export function initializeStore(initialState = {}) {
    return createStore(
        reducer,
        initialState,
        composeWithDevTools(applyMiddleware(thunkMiddleware))
      )
    }
    

    Otherwise same state will always be applied and server-propagated state will be lost.