Skip to content

Commit

Permalink
fix(Environment): avoid react state change during rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
mman committed Sep 18, 2024
1 parent 35fc568 commit 2579930
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 128 deletions.
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"@testing-library/user-event": "^14.5.2",
"@typescript-eslint/eslint-plugin": "^5.48.2",
"@typescript-eslint/parser": "^5.48.2",
"@victronenergy/mfd-modules": "^6.0.3",
"@victronenergy/mfd-modules": "^7.0.0",
"axios": "^0.28.1",
"babel-eslint": "^10.1.0",
"babel-jest": "^26.6.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { observer } from "mobx-react-lite"
import { useTemperatures, TemperatureInstanceId } from "@victronenergy/mfd-modules"
import { useState, createContext, useCallback } from "react"
import { useTemperatures, TemperatureState } from "@victronenergy/mfd-modules"
import { useState } from "react"
import { useVisibilityNotifier } from "../../../modules"
import Box from "../../ui/Box"
import TemperatureData from "./TemperatureData"
Expand All @@ -19,91 +19,73 @@ interface Props {
pageSelectorPropsSetter?: (arg0: PageSelectorProps) => void
}

export const VisibleComponentsContext = createContext({
passVisibility: (id: number, type: SensorInformationType, visible: boolean) => {},
})

type SensorInformationType = "humidity" | "pressure" | "temperature"

const EnvironmentOverview = ({ componentMode = "full", pageSelectorPropsSetter }: Props) => {
const { temperatures: sensors } = useTemperatures()
const [visibleElements, setVisibleElements] = useState({})
const [boxSize, setBoxSize] = useState<ISize>({ width: 0, height: 0 })

const passVisibility = useCallback((id: number, type: SensorInformationType, visible: boolean) => {
setVisibleElements((prev: any) => ({
...prev,
[id]: {
...prev[id],
[type]: visible,
},
}))
}, [])

let temperatureComponents = (sensors || []).map((temperatureId: TemperatureInstanceId) => (
<TemperatureData
key={"temperature" + temperatureId}
dataId={temperatureId}
componentMode={componentMode}
boxSize={boxSize}
/>
))
let temperatureComponents = (sensors.filter((sensor) => sensor.temperature !== undefined) || []).map(
(sensor: TemperatureState) => (
<TemperatureData
key={"temperature" + sensor.instance}
dataId={sensor.instance}
componentMode={componentMode}
boxSize={boxSize}
/>
)
)

let humidityComponents = (sensors || []).map((temperatureId: TemperatureInstanceId) => (
<HumidityData
key={"humidity" + temperatureId}
dataId={temperatureId}
componentMode={componentMode}
boxSize={boxSize}
/>
))
let humidityComponents = (sensors.filter((sensor) => sensor.humidity !== undefined) || []).map(
(sensor: TemperatureState) => (
<HumidityData
key={"humidity" + sensor.instance}
dataId={sensor.instance}
componentMode={componentMode}
boxSize={boxSize}
/>
)
)

let pressureComponents = (sensors || []).map((temperatureId: TemperatureInstanceId) => (
<PressureData
key={"pressure" + temperatureId}
dataId={temperatureId}
componentMode={componentMode}
boxSize={boxSize}
/>
))
let pressureComponents = (sensors.filter((sensor) => sensor.pressure !== undefined) || []).map(
(sensor: TemperatureState) => (
<PressureData
key={"pressure" + sensor.instance}
dataId={sensor.instance}
componentMode={componentMode}
boxSize={boxSize}
/>
)
)

const components = [...temperatureComponents, ...humidityComponents, ...pressureComponents] as JSX.Element[]
const sensorHasData: boolean = Object.values(visibleElements).some(
(sensor: any) => sensor.temperature || sensor.humidity || sensor.pressure
)

const hasValidData = sensorHasData
const hasValidData = components.length > 0

useVisibilityNotifier({ widgetName: BOX_TYPES.ENVIRONMENT, isVisible: hasValidData })

if (componentMode === "compact") {
return (
<VisibleComponentsContext.Provider value={{ passVisibility }}>
<Box
title={translate("boxes.environment")}
icon={<EnvironmentIcon className={"w-4"} />}
withPagination={true}
paginationOrientation={"vertical"}
getBoxSizeCallback={setBoxSize}
>
{components}
</Box>
</VisibleComponentsContext.Provider>
<Box
title={translate("boxes.environment")}
icon={<EnvironmentIcon className={"w-4"} />}
withPagination={true}
paginationOrientation={"vertical"}
getBoxSizeCallback={setBoxSize}
>
{components}
</Box>
)
}

return (
<VisibleComponentsContext.Provider value={{ passVisibility }}>
<GridPaginator
childClassName={"p-1"}
perPage={4}
orientation={"horizontal"}
pageSelectorPropsSetter={pageSelectorPropsSetter}
flow={window.innerWidth > window.innerHeight ? "row" : "col"}
>
{components}
</GridPaginator>
</VisibleComponentsContext.Provider>
<GridPaginator
childClassName={"p-1"}
perPage={4}
orientation={"horizontal"}
pageSelectorPropsSetter={pageSelectorPropsSetter}
flow={window.innerWidth > window.innerHeight ? "row" : "col"}
>
{components}
</GridPaginator>
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import ValueOverview from "../../ui/ValueOverview"
import HumidityIcon from "../../../images/icons/humidity.svg"
import ValueBox from "../../ui/ValueBox"
import { translate } from "react-i18nify"
import { useContext, useEffect, useCallback } from "react"
import { VisibleComponentsContext } from "./EnvironmentOverview"
import { ComponentMode } from "@m2Types/generic/component-mode"
import { AdditionalInformation } from "../GeneratorFp/AdditionalInformation/AdditionalInformation"
import { ISize } from "@m2Types/generic/size"
Expand All @@ -18,22 +16,6 @@ interface Props {

const HumidityData = ({ dataId, componentMode, boxSize }: Props) => {
const { humidity, customName } = useHumidity(dataId)
const { passVisibility } = useContext(VisibleComponentsContext)

const handlePassVisibility = useCallback(
(id: number, isVisible: boolean) => {
passVisibility(id, "humidity", isVisible)
},
[passVisibility]
)

useEffect(() => {
if (humidity !== undefined) {
handlePassVisibility(dataId, true)
} else {
handlePassVisibility(dataId, false)
}
}, [humidity, customName, dataId, handlePassVisibility])

if (humidity === undefined) {
return null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import ValueOverview from "../../ui/ValueOverview"
import PressureIcon from "../../../images/icons/pressure.svg"
import ValueBox from "../../ui/ValueBox"
import { translate } from "react-i18nify"
import { useContext, useEffect, useCallback } from "react"
import { VisibleComponentsContext } from "./EnvironmentOverview"
import { ComponentMode } from "@m2Types/generic/component-mode"
import { ISize } from "@m2Types/generic/size"

Expand All @@ -17,22 +15,6 @@ interface Props {

const PressureData = ({ dataId, componentMode, boxSize }: Props) => {
const { pressure, customName } = usePressure(dataId)
const { passVisibility } = useContext(VisibleComponentsContext)

const handlePassVisibility = useCallback(
(id: number, isVisible: boolean) => {
passVisibility(id, "pressure", isVisible)
},
[passVisibility]
)

useEffect(() => {
if (pressure !== undefined) {
handlePassVisibility(dataId, true)
} else {
handlePassVisibility(dataId, false)
}
}, [pressure, customName, dataId, handlePassVisibility])

if (pressure === undefined) {
return null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import ValueOverview from "../../ui/ValueOverview"
import ThermometerIcon from "../../../images/icons/thermometer.svg"
import ValueBox from "../../ui/ValueBox"
import { translate } from "react-i18nify"
import { useCallback, useContext, useEffect } from "react"
import { VisibleComponentsContext } from "./EnvironmentOverview"
import { ComponentMode } from "@m2Types/generic/component-mode"
import { ISize } from "@m2Types/generic/size"
import { temperatureValueFor } from "../../../utils/formatters/temperature/temperature-value-for"
Expand All @@ -18,24 +16,8 @@ interface Props {

const TemperatureData = ({ dataId, componentMode, boxSize }: Props) => {
const { temperature, customName } = useTemperature(dataId)
const { passVisibility } = useContext(VisibleComponentsContext)
const { temperatureUnitToHumanReadable, temperatureUnit } = useAppStore()

const handlePassVisibility = useCallback(
(id: number, isVisible: boolean) => {
passVisibility(id, "temperature", isVisible)
},
[passVisibility]
)

useEffect(() => {
if (temperature !== undefined) {
handlePassVisibility(dataId, true)
} else {
handlePassVisibility(dataId, false)
}
}, [temperature, customName, dataId, handlePassVisibility])

if (temperature === undefined) {
return null
}
Expand Down

0 comments on commit 2579930

Please sign in to comment.