-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from MostafaRastegar/redux-ssr-request
Add Redux ssr request
- Loading branch information
Showing
11 changed files
with
462 additions
and
393 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { useSelector } from 'react-redux'; | ||
import { usersSelectors } from 'store'; | ||
import { StyledUsersWrapper, StyledUsersTitle } from './styles'; | ||
import { RootStore } from 'store/interfaces'; | ||
|
||
const Users = () => { | ||
const usersData = useSelector((state: RootStore) => | ||
usersSelectors.getUsersData(state), | ||
); | ||
|
||
const usersLoading = useSelector((state: RootStore) => | ||
usersSelectors.getUsersLoading(state), | ||
); | ||
|
||
return ( | ||
<> | ||
<StyledUsersWrapper> | ||
<StyledUsersTitle>List Of Names</StyledUsersTitle> | ||
{usersLoading ? ( | ||
<span>Loading ....</span> | ||
) : ( | ||
<div> | ||
{usersData?.map((item: { id: number; userName: string }) => ( | ||
<p key={item.id}>{item?.userName}</p> | ||
))} | ||
</div> | ||
)} | ||
</StyledUsersWrapper> | ||
</> | ||
); | ||
}; | ||
|
||
export default Users; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import styled from 'styled-components'; | ||
import { color, px } from 'constants/theme/helpers'; | ||
|
||
export const StyledUsersWrapper = styled.div` | ||
position: relative; | ||
background-color: ${color('green', 'light')}; | ||
padding: ${px(30)}; | ||
`; | ||
export const StyledUsersTitle = styled.h3` | ||
padding-bottom: ${px(30)}; | ||
color: ${color('blue', 'dark')}; | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,22 @@ | ||
import { useStore } from 'store/store'; | ||
import { wrapper } from 'store/store'; | ||
import { AppProps } from 'next/app'; | ||
import { Provider } from 'react-redux'; | ||
import { persistStore } from 'redux-persist'; | ||
import { PersistGate } from 'redux-persist/integration/react'; | ||
// import { Provider } from 'react-redux'; | ||
// import { persistStore } from 'redux-persist'; | ||
// import { PersistGate } from 'redux-persist/integration/react'; | ||
import { ThemeProvider } from 'styled-components'; | ||
|
||
import defaultTheme from 'constants/theme'; | ||
import GlobalStyle from 'constants/theme/GlobalStyle'; | ||
|
||
const App = ({ Component, pageProps }: AppProps) => { | ||
const store = useStore(pageProps.initialReduxState); | ||
const persistor = persistStore(store, {}, () => { | ||
persistor.persist(); | ||
}); | ||
|
||
return ( | ||
<Provider store={store}> | ||
<PersistGate loading={<div>loading</div>} persistor={persistor}> | ||
<ThemeProvider theme={defaultTheme}> | ||
<GlobalStyle /> | ||
<Component {...pageProps} /> | ||
</ThemeProvider> | ||
</PersistGate> | ||
</Provider> | ||
<ThemeProvider theme={defaultTheme}> | ||
<GlobalStyle /> | ||
<Component {...pageProps} /> | ||
</ThemeProvider> | ||
|
||
); | ||
}; | ||
|
||
export default App; | ||
export default wrapper.withRedux(App); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import React from 'react'; | ||
import type { | ||
GetStaticPropsResult, | ||
} from 'next'; | ||
import styled from 'styled-components'; | ||
import { usersEffects } from 'store'; | ||
import { wrapper } from 'store/store'; | ||
import Users from 'components/Pages/UsersSSR'; | ||
|
||
const Title = styled.h1` | ||
color: red; | ||
`; | ||
|
||
const MainPage = () => ( | ||
<div> | ||
<Title>My First Next.js Page</Title> | ||
<Users /> | ||
</div> | ||
); | ||
|
||
export const getServerSideProps = wrapper.getServerSideProps((store) => async (): Promise<GetStaticPropsResult<{}>> => { | ||
await store.dispatch(usersEffects.getUsersRequest() as any); | ||
return { props: {} }; | ||
}) | ||
export default MainPage; |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import axios from 'axios'; | ||
import { setupInterceptorsTo } from './interceptors'; | ||
|
||
const request = setupInterceptorsTo( | ||
axios.create({ | ||
headers: { | ||
'Content-Type': 'application/json', | ||
}, | ||
}), | ||
); | ||
|
||
export const requestWithotAuth = setupInterceptorsTo(axios.create()); | ||
|
||
export default request; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import axios, { | ||
AxiosError, | ||
AxiosInstance, | ||
AxiosRequestConfig, | ||
AxiosResponse, | ||
} from 'axios'; | ||
import Cookies from 'js-cookie'; | ||
|
||
// import { useDispatch } from 'react-redux'; | ||
// import { customerActions } from 'store'; | ||
|
||
const onRequest = (config: AxiosRequestConfig): AxiosRequestConfig => { | ||
const accessToken = Cookies.get('accessToken'); | ||
if (accessToken && accessToken !== 'null') { | ||
config.headers['Authorization'] = `Bearer ${accessToken}`; | ||
} else { | ||
delete config.headers['Authorization']; | ||
} | ||
|
||
return config; | ||
}; | ||
|
||
const onRequestError = (error: AxiosError): Promise<AxiosError> => { | ||
return Promise.reject(error); | ||
}; | ||
|
||
const onResponse = (response: AxiosResponse): AxiosResponse => { | ||
return response; | ||
}; | ||
|
||
const onResponseError = async (error: any): Promise<any> => { | ||
// console.log('error.response:>> ', error.response); | ||
// dispatch(customerActions.postTokenWebLoginFailure(errObject(error.response))); | ||
if (!error.response) { | ||
return { | ||
status: 503, | ||
data: null, | ||
problem: 'Network Error', | ||
}; | ||
} | ||
if (error.response) { | ||
if (error.response.status === 403) { | ||
console.log('please login :>> '); | ||
} | ||
if (error.response.status === 401) { | ||
// Access Token was expired | ||
const accessToken = Cookies.get('accessToken'); | ||
const refreshToken = Cookies.get('refreshToken'); | ||
|
||
try { | ||
const rs = await axios.post('/refresh-token-api', { | ||
RefreshToken: refreshToken, | ||
AccessToken: accessToken, | ||
}); | ||
|
||
const { AccessToken, RefreshToken } = rs.data; | ||
|
||
Cookies.set('accessToken', AccessToken); | ||
Cookies.set('refreshToken', RefreshToken); | ||
|
||
return rs.data; | ||
} catch (_error) { | ||
return Promise.reject(_error); | ||
} | ||
} | ||
} | ||
return error.response; | ||
}; | ||
|
||
export const setupInterceptorsTo = ( | ||
axiosInstance: AxiosInstance, | ||
): AxiosInstance => { | ||
axiosInstance.interceptors.request.use(onRequest, onRequestError); | ||
axiosInstance.interceptors.response.use(onResponse, onResponseError); | ||
return axiosInstance; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,60 +1,31 @@ | ||
import { useMemo } from 'react'; | ||
import { createStore, applyMiddleware } from 'redux'; | ||
import { composeWithDevTools } from 'redux-devtools-extension'; | ||
import { persistReducer } from 'redux-persist'; | ||
import storage from 'redux-persist/lib/storage'; | ||
import { createStore, applyMiddleware, AnyAction } from 'redux'; | ||
import { createWrapper, HYDRATE } from "next-redux-wrapper"; | ||
import { loadingBarMiddleware } from 'react-redux-loading-bar'; | ||
import thunk from 'redux-thunk'; | ||
import rootReducer, { RootReducerI } from './rootReducer'; | ||
import rootReducer from './rootReducer'; | ||
|
||
let store: any; | ||
|
||
// add redux loading bar middleware | ||
const loadingMD = loadingBarMiddleware({ | ||
promiseTypeSuffixes: ['REQUEST', 'SUCCESS', 'FAILURE'], | ||
}); | ||
|
||
const persistConfig = { | ||
key: 'primary', | ||
storage, | ||
// whitelist: [], // place to select which state you want to persist | ||
const bindMiddleware = (middleware: any[]) => { | ||
if (process.env.NODE_ENV !== "production") { | ||
const { composeWithDevTools } = require("redux-devtools-extension"); | ||
return composeWithDevTools(applyMiddleware(...middleware)); | ||
} | ||
return applyMiddleware(...middleware); | ||
}; | ||
|
||
const persistedReducer = persistReducer(persistConfig, rootReducer); | ||
|
||
function makeStore(initialState: RootReducerI) { | ||
return createStore( | ||
persistedReducer, | ||
initialState, | ||
composeWithDevTools(applyMiddleware(thunk, loadingMD)), | ||
); | ||
} | ||
|
||
export const initializeStore = (preloadedState: RootReducerI) => { | ||
let _store = store ?? makeStore(preloadedState); | ||
|
||
// After navigating to a page with an initial Redux state, merge that state | ||
// with the current state in the store, and create a new store | ||
if (preloadedState && store) { | ||
_store = makeStore({ | ||
...store.getState(), | ||
...preloadedState, | ||
}); | ||
// Reset the current store | ||
store = undefined; | ||
const reducer = (state: any, action: AnyAction) => { | ||
if(action.type === HYDRATE) { | ||
const nextState = { | ||
...state, | ||
...action.payload, | ||
} | ||
return nextState; | ||
} | ||
return rootReducer(state, action); | ||
|
||
// For SSG and SSR always create a new store | ||
if (typeof window === 'undefined') return _store; | ||
// Create the store once in the client | ||
if (!store) store = _store; | ||
|
||
return _store; | ||
}; | ||
} | ||
|
||
export function useStore(initialState: RootReducerI) { | ||
const memoedStore = useMemo(() => initializeStore(initialState), [ | ||
initialState, | ||
]); | ||
return memoedStore; | ||
const initStore = () => { | ||
return createStore(reducer, bindMiddleware([thunk, loadingBarMiddleware()])); | ||
} | ||
|
||
export const wrapper = createWrapper(initStore); |
Oops, something went wrong.