Skip to content

Commit

Permalink
Prevent status message handler from re-rendering component tree
Browse files Browse the repository at this point in the history
Status message handler changes

Prevent status message handler from re-rendering component tree
  • Loading branch information
saulipurhonen committed Nov 3, 2021
1 parent 0fe9ca5 commit 8297b7e
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 41 deletions.
11 changes: 1 addition & 10 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,6 @@ const App = (): React$Element<typeof React.Fragment> => {
const dispatch = useDispatch()

const locale = useSelector(state => state.locale)
const statusDetails = useSelector(state =>
state.statusDetails ? JSON.parse(state.statusDetails) : state.statusDetails
)

// Fetch array of schemas from backend and store it in frontend
// Fetch only if the initial array is empty
Expand Down Expand Up @@ -194,13 +191,7 @@ const App = (): React$Element<typeof React.Fragment> => {
</Route>
</Switch>
{/* Centralized status message handler */}
{statusDetails?.status === "asd" && !Array.isArray(statusDetails.response) && (
<StatusMessageHandler
status={statusDetails.status}
response={statusDetails.response}
helperText={statusDetails.helperText}
/>
)}
<StatusMessageHandler />
</React.Fragment>
)
}
Expand Down
19 changes: 15 additions & 4 deletions src/__tests__/StatusMessageHandler.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ import { ResponseStatus } from "constants/responseStatus"
const mockStore = configureStore([])

describe("StatusMessageHandler", () => {
const store = mockStore({
errorMessage: "",
})

it("should render error message", () => {
const responseMock = { data: { accessionId: "TESTID1234", status: 504 } }
const helperTextMock = "Test prefix"

const store = mockStore({
// errorMessage: "",
statusDetails: { status: ResponseStatus.error, response: responseMock, helperText: helperTextMock },
})

render(
<Provider store={store}>
<StatusMessageHandler status={ResponseStatus.error} response={responseMock} helperText={helperTextMock} />
Expand All @@ -28,6 +30,10 @@ describe("StatusMessageHandler", () => {
})

it("should render info message", () => {
const store = mockStore({
statusDetails: { status: ResponseStatus.info },
})

render(
<Provider store={store}>
<StatusMessageHandler status={ResponseStatus.info} />
Expand All @@ -40,6 +46,11 @@ describe("StatusMessageHandler", () => {

it("should render success message", () => {
const responseMock = { data: { accessionId: "TESTID1234" }, config: { baseURL: "/drafts" } }

const store = mockStore({
statusDetails: { status: ResponseStatus.success, response: responseMock },
})

render(
<Provider store={store}>
<StatusMessageHandler response={responseMock} status={ResponseStatus.success} />
Expand Down
2 changes: 1 addition & 1 deletion src/components/Home/UserDraftTemplateActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ const UserDraftTemplateActions = (props: { item: { schema: string, accessionId:
updateStatus({
status: ResponseStatus.error,
response: response,
errorPrefix: "Unable to delete template",
helperText: "Unable to delete template",
})
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,8 @@ const CustomCardHeader = (props: CustomCardHeaderProps) => {
root: classes.cardHeader,
action: classes.cardHeaderAction,
}}
className={currentObject.status === ObjectStatus.template ? classes.resetTopMargin : null}
action={currentObject.status === ObjectStatus.template ? templateButtonGroup : buttonGroup}
className={currentObject?.status === ObjectStatus.template ? classes.resetTopMargin : null}
action={currentObject?.status === ObjectStatus.template ? templateButtonGroup : buttonGroup}
/>
)
}
Expand Down Expand Up @@ -375,7 +375,7 @@ const FormContent = ({
resetTimer()

// Prevent auto save from template dialog
if (currentObject.status !== ObjectStatus.template) startTimer()
if (currentObject?.status !== ObjectStatus.template) startTimer()
}

useEffect(() => {
Expand Down Expand Up @@ -427,7 +427,6 @@ const FormContent = ({
dispatch(
updateStatus({
status: ResponseStatus.info,
response: "",
helperText: "An empty form cannot be saved. Please fill in the form before saving it.",
})
)
Expand All @@ -439,9 +438,6 @@ const FormContent = ({
if (checkFormCleanedValuesEmpty(cleanedValues)) {
const response = await templateAPI.patchTemplateFromJSON(objectType, currentObject.accessionId, cleanedValues)

// closeDialog()
// console.log(response)

if (response.ok) {
dispatch(
updateStatus({
Expand Down Expand Up @@ -528,7 +524,7 @@ const FormContent = ({
/*
* Container for json schema based form. Handles json schema loading, form rendering, form submitting and error/success alerts.
*/
const WizardFillObjectDetailsForm = (props: { closeDialog: () => void }): React$Element<typeof Container> => {
const WizardFillObjectDetailsForm = (props: { closeDialog?: () => void }): React$Element<typeof Container> => {
const { closeDialog } = props
const classes = useStyles()
const dispatch = useDispatch()
Expand Down Expand Up @@ -635,7 +631,7 @@ const WizardFillObjectDetailsForm = (props: { closeDialog: () => void }): React$
folder={folder}
currentObject={currentObject}
key={currentObject?.accessionId || folder.folderId}
closeDialog={closeDialog}
closeDialog={closeDialog || (() => {})}
/>
{submitting && <LinearProgress />}
</Container>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ const submitObjectHook = async (formData: any, folderId: string, objectType: str
dispatch(
updateStatus({
status: ResponseStatus.info,
response: {},
helperText: "",
})
)
Expand Down
30 changes: 22 additions & 8 deletions src/components/StatusMessageHandler.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
//@flow
import React, { useState } from "react"

import Portal from "@material-ui/core/Portal"
// import Portal from "@material-ui/core/Portal"
import Snackbar from "@material-ui/core/Snackbar"
import Alert from "@material-ui/lab/Alert"
import { useDispatch } from "react-redux"
import { useDispatch, useSelector } from "react-redux"

import { ResponseStatus } from "constants/responseStatus"
import { resetStatusDetails } from "features/statusMessageSlice"
Expand Down Expand Up @@ -123,7 +123,7 @@ const SuccessHandler = ({
)
}

const StatusMessageHandler = ({
const Message = ({
status,
response,
helperText,
Expand Down Expand Up @@ -155,11 +155,25 @@ const StatusMessageHandler = ({
}

return (
<Portal>
<Snackbar autoHideDuration={autoHideDuration} open={open} onClose={() => handleClose()}>
{messageTemplate(status)}
</Snackbar>
</Portal>
<Snackbar autoHideDuration={autoHideDuration} open={open} onClose={() => handleClose()}>
{messageTemplate(status)}
</Snackbar>
)
}

const StatusMessageHandler = (): React$Element<any> => {
const statusDetails = useSelector(state => state.statusDetails)

return (
<React.Fragment>
{statusDetails?.status && !Array.isArray(statusDetails.response) && (
<Message
status={statusDetails.status}
response={statusDetails.response}
helperText={statusDetails.helperText}
/>
)}
</React.Fragment>
)
}

Expand Down
27 changes: 19 additions & 8 deletions src/features/statusMessageSlice.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
//@flow
import { createSlice } from "@reduxjs/toolkit"

const initialState = null
import type { StatusDetails, Response } from "types"

const initialState: null | StatusDetails = null

const statusMessageSlice: any = createSlice({
name: "wizardStatusMessage",
Expand All @@ -14,14 +16,23 @@ const statusMessageSlice: any = createSlice({
export const { setStatusDetails, resetStatusDetails } = statusMessageSlice.actions
export default statusMessageSlice.reducer

type StatusDetails = {
status: string,
response?: Object,
helperText?: string,
}

export const updateStatus =
(statusDetails: StatusDetails): ((dispatch: (any) => void) => Promise<void>) =>
async (dispatch: any => void) => {
dispatch(setStatusDetails(JSON.stringify(statusDetails)))
const response = statusDetails.response || {}

const statusResponse: Response = {
config: { baseURL: response.config.baseURL, method: response.config.method },
data: response.data,
ok: response.ok,
status: response.status,
}

const details: StatusDetails = {
status: statusDetails.status,
response: statusResponse,
helperText: statusDetails.helperText,
}

dispatch(setStatusDetails(details))
}
13 changes: 13 additions & 0 deletions src/types/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,16 @@ export type FolderDataFromForm = {
}

export type CreateFolderFormRef = ElementRef<typeof useForm>

export type Response = {
config: { baseURL: string, method: string },
data: any,
ok: boolean,
status: number,
}

export type StatusDetails = {
status: string,
response?: Response,
helperText?: string,
}

0 comments on commit 8297b7e

Please sign in to comment.