我是一个新的react开发者,我的问题是关于一个模型的渲染问题,下面是我的代码:
import * as React from 'react'
import { Typography, IconButton, Box, Link, Grid, FormGroup, FormControlLabel, Switch, Accordion, AccordionSummary, AccordionDetails } from '@mui/material'
import TwinLayout from '../../components/TwinLayout'
import EditIcon from '@mui/icons-material/Edit'
import PinDropIcon from '@mui/icons-material/PinDrop'
import PersonIcon from '@mui/icons-material/Person'
import { createAsset, getAssetTypes, createMonitoringDevice, fetchSites, fetchSiteBySiteId } from '../../api'
import { useTranslation } from 'react-i18next'
import ListAvatarData from '../../components/ListAvatarData'
import ListAvatarDataTitle from '../../components/ListAvatarDataTitle'
import { useState } from 'react'
import { Buffer } from 'buffer'
import styles from './style.module.css'
import { Area, Asset, AssetType, MonitoringDevice, MonitoringDeviceType, Site } from '../../types/entities'
import { connect } from 'react-redux'
import EditSiteModal from '../../components/EditSiteModal'
import { setSelectedAsset, setSelectedSite } from '../../actions'
import CreateAssetModal from '../../components/CreateAssetModal'
import CreateMonitoringDeviceModal from '../../components/CreateMonitoringDeviceModal'
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
import { useNavigate } from 'react-router-dom'
function SiteDetail({ selectedSite, updateSelected, updateSelectedSite }: { selectedSite: Site; updateSelected: any; updateSelectedSite: any }) {
const [assetAreas, setAssetAreas] = React.useState<Area[]>([])
const [monitoringDeviceAreas, setMonitoringDeviceAreas] = React.useState<Area[]>([])
const [assetTypes, setAssetTypes] = React.useState<AssetType[]>([])
const [monitoringDeviceTypes, setMonitoringDeviceTypes] = React.useState<any[]>([])
const site = selectedSite
const { t } = useTranslation()
const [open, setOpen] = React.useState<boolean>(false)
const [data, setData] = React.useState<boolean>(false)
const [assetOpen, setAssetOpen] = React.useState<boolean>(false)
const [monitoringDeviceOpen, setMonitoringDeviceOpen] = React.useState<boolean>(false)
const [deleteItem, setDeleteItem] = useState(false)
const [assetInputs, setAssetInputs] = React.useState<Partial<Asset>>({ name: '', type: '', area: '', siteId: selectedSite.id, serialNumber: '' })
const [monitoringDeviceInputs, setMonitoringDeviceInputs] = React.useState<Partial<MonitoringDevice>>({
name: '',
type: '',
area: '',
siteId: selectedSite.id,
imageRenderLocation: '',
})
const [isExist, setIsExist] = React.useState<any>({
isImageExist: true,
isFloorPlanExist: true,
isMonitoringDeviceNameExist: true,
isEditMonitoringDeviceNameExist: true,
})
const monitoringDeviceTypeList = Object.entries(MonitoringDeviceType)
.filter((e) => isNaN(Number(e[0])))
.map((e) => ({ id: e[0], name: e[0] }))
// const searchList = [
// { id: 0, name: 'Asset' },
// { id: 1, name: 'Monitoring Device' },
// ]
const navigate = useNavigate()
const fetchData = async () => {
const assetTypeList = await getAssetTypes()
setAssetTypes(assetTypeList.data.assetTypes.result)
setMonitoringDeviceTypes(monitoringDeviceTypeList)
if (selectedSite?.areas != undefined) {
setAssetAreas(selectedSite?.areas)
setMonitoringDeviceAreas(selectedSite?.areas)
}
let selectedSiteId = selectedSite.id
if (selectedSiteId !== undefined) {
const sites = await fetchSiteBySiteId([selectedSiteId])
console.log('sites')
console.log(sites.data.sites[0])
updateSelectedSite({ ...selectedSite, assets: sites.data.sites[0].assets.result })
console.log('selectedSite')
console.log(selectedSite)
if (sites.data) setData(sites.data)
else console.log('Something wrong')
}
}
const setIsPropertyExist = (name: 'isImageExist' | 'isFloorPlanExist' | 'isAssetExist' | 'isMonitoringDeviceExist', val: boolean) => {
setIsExist((prevState: any) => ({
...prevState,
[name]: val,
}))
}
const handleAssetOpen = async () => {
setAssetOpen(true)
}
const handleMonitoringDeviceOpen = () => {
setMonitoringDeviceOpen(true)
}
const handleClose = () => {
setOpen(false)
}
const handleAssetClose = () => {
setAssetOpen(false)
}
const handleMonitoringDeviceClose = () => {
setMonitoringDeviceOpen(false)
setIsPropertyExist(isExist.isMonitoringDeviceNameExist, true)
}
const handleDeleteItem = () => {
setDeleteItem(false)
}
const handleAssetClick = (asset: Asset) => {
updateSelected(asset)
navigate(`/console/assets/${asset.id}`)
}
const handleChangeAssetType = (e: any) => {
setAssetInputs((prevState) => ({
...prevState,
type: e.target.value,
}))
}
const handleChangeMonitoringDeviceType = (e: any) => {
setMonitoringDeviceInputs((prevState) => ({
...prevState,
type: e.target.value,
}))
}
const handleChangeAssetArea = (e: any) => {
setAssetInputs((prevState) => ({
...prevState,
area: e.target.value,
}))
}
const handleChangeMonitoringDeviceArea = (e: any) => {
setMonitoringDeviceInputs((prevState) => ({
...prevState,
area: e.target.value,
}))
}
const handleAssetCreate = async () => {
if (selectedSite.id && assetInputs.name && assetInputs.type && assetInputs.area && assetInputs.serialNumber) {
await createAsset(selectedSite.id, assetInputs.name, assetInputs.type, assetInputs.area, assetInputs.serialNumber)
}
setAssetOpen(false)
setAssetInputs({
name: assetInputs.name,
type: assetInputs.type,
area: assetInputs.area,
siteId: selectedSite.id,
serialNumber: assetInputs.serialNumber,
})
await fetchData()
}
const handleMonitoringDeviceCreate = async () => {
if (monitoringDeviceInputs.name === '') {
setIsPropertyExist(isExist.isMonitoringDevice, false)
return
}
if (selectedSite.id && monitoringDeviceInputs.name && monitoringDeviceInputs.type && monitoringDeviceInputs.area && monitoringDeviceInputs.imageRenderLocation) {
await createMonitoringDevice(
selectedSite.id,
monitoringDeviceInputs.name,
monitoringDeviceInputs.type,
monitoringDeviceInputs.area,
monitoringDeviceInputs.imageRenderLocation
)
}
setMonitoringDeviceOpen(false)
setMonitoringDeviceInputs({
name: monitoringDeviceInputs.name,
type: monitoringDeviceInputs.type,
area: monitoringDeviceInputs.area,
siteId: selectedSite.id,
imageRenderLocation: monitoringDeviceInputs.imageRenderLocation,
})
await fetchData()
}
const handleAssetInputChange = (e: any, name: string) => {
//handle asset inputs
setAssetInputs((prevState) => ({
...prevState,
[name]: e.target.value,
}))
}
const handleMonitoringDeviceInputChange = (e: any, name: string) => {
//handle monitoring device inputs
setMonitoringDeviceInputs((prevState) => ({
...prevState,
[name]: e.target.value,
}))
}
React.useEffect(() => {
if (deleteItem) fetchData()
}, [deleteItem])
React.useEffect(() => {
if (selectedSite.image && isExist.isImageExist) fetchImages(selectedSite.image, 'image')
if (selectedSite.floorPlan && isExist.isFloorPlanExist) fetchImages(selectedSite.floorPlan, 'floorPlan')
}, [selectedSite])
const fetchImages = async (url: string, type: string) => {
const res = await fetch(url, { method: 'GET', cache: 'reload' })
if (type === 'image') setIsPropertyExist(isExist.isImageExist, res.ok)
if (type === 'floorPlan') setIsPropertyExist(isExist.isFloorPlanExist, res.ok)
}
return (
<TwinLayout
side={
<div className="w-100 h-100">
<div className="flex row" style={{ alignItems: 'center' }}>
<Typography className={styles.siteDetails}>{t('Site Details')}</Typography>
<IconButton onClick={() => setOpen(true)} color="primary">
<EditIcon className={styles.EditIcon} />
<Typography className="mr-10" fontSize={14}>
{t('Edit')}
</Typography>
</IconButton>
</div>
<div className="detailFields">
<PinDropIcon fontSize="small"></PinDropIcon>
<Typography fontSize={14}>{t('Address')}</Typography>
</div>
<Typography className="mt-4" fontSize={12}>
{selectedSite?.address}
</Typography>
<div className="detailFields">
<PersonIcon fontSize="small"></PersonIcon>
<Typography fontSize={14}>{t('Contact People')}</Typography>
</div>
{selectedSite?.contactPersons?.map((person, i) => {
return (
<div key={i}>
<Typography fontSize={12} className="mt-4">
{person.name}
</Typography>
<Typography fontSize={12} color={'#969696'}>
{`${person.phoneNumber} ${person.email}`}
</Typography>
</div>
)
})}
<Typography fontWeight={600} className="mt-13 mb-13" fontSize={14}>
{t('Site visuals')}
</Typography>
{isExist.isImageExist && (
<Box borderRadius={1} className="mr-10" component="img" alt={t('Site Image')} src={selectedSite?.image + '#' + Date.now()} width={'13vh'} height={'6vw'} />
)}
{isExist.isFloorPlanExist && (
<Box borderRadius={1} component="img" alt={t('Site Floor Plan')} src={selectedSite?.floorPlan + '#' + Date.now()} width={'13vh'} height={'6vw'} />
)}
<Typography fontWeight={600} className="mt-13 mb-13" fontSize={14}>
{t('Projects')} (5)
</Typography>
{[0, 1, 2, 3, 4].map((i) => {
return (
<Box
key={i}
borderRadius={1}
className="mr-10"
component="img"
alt="Factory Picture"
src={'https://scdn.emotorsdirect.ca/img/knowledge-center/hero/choosing-the-right-industrial-motor-for-your-application.jpeg@1080w.webp'}
width={'19.5vh'}
height={'9vw'}
/>
)
})}
</div>
}>
<Grid container justifyContent="flex-end" paddingBottom={5}>
<Link sx={{ marginTop: '7px' }} href="#">
<Typography onClick={handleMonitoringDeviceOpen}>{t('+ Add monitoring device')}</Typography>
</Link>
<Link sx={{ marginTop: '7px' }} onClick={handleAssetOpen} href="#" paddingLeft={5} paddingRight={5}>
<Typography>{t('+ Add asset')}</Typography>
</Link>
<FormGroup>
<FormControlLabel labelPlacement="start" control={<Switch defaultChecked />} label={t('Show drawing')} />
</FormGroup>
</Grid>
<Grid container justifyContent="flex-end" paddingBottom={5}>
<FormGroup>
<FormControlLabel labelPlacement="start" control={<Switch defaultChecked />} label={t('Group by area')} />
</FormGroup>
</Grid>
<Accordion>
<AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls="panel1a-content" id="panel1a-header">
<div className={styles.divAvatarDataTitle}>
<ListAvatarDataTitle count={site.monitoringDevices?.length} type={'Monitoring Devices'}></ListAvatarDataTitle>
</div>
</AccordionSummary>
<AccordionDetails>
<ListAvatarData
handleClick={undefined}
setDelete={handleDeleteItem}
data={site.monitoringDevices}
type={'Monitoring Devices'}
fetchData={undefined}></ListAvatarData>
<div className={styles.divAvatarDataTitle}></div>
</AccordionDetails>
</Accordion>
<Accordion>
<AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls="panel1a-content" id="panel1a-header">
<div className={styles.divAvatarDataTitle}>
<ListAvatarDataTitle count={site.assets?.result?.length} type={'Assets'}></ListAvatarDataTitle>
</div>
</AccordionSummary>
<AccordionDetails>
<ListAvatarData handleClick={handleAssetClick} setDelete={handleDeleteItem} data={site.assets?.result} type={'Assets'} fetchData={undefined}></ListAvatarData>
</AccordionDetails>
</Accordion>
<EditSiteModal
setIsPropertyExist={setIsPropertyExist}
isImageExist={isExist.isImageExist}
isFloorPlanExist={isExist.isFloorPlanExist}
open={open}
handleClose={handleClose}
setOpen={setOpen}></EditSiteModal>
<CreateAssetModal
openAsset={assetOpen}
handleAssetChange={handleAssetInputChange}
handleAssetClose={handleAssetClose}
handleAssetCreate={handleAssetCreate}
handleChangeAssetType={handleChangeAssetType}
handleChangeAssetArea={handleChangeAssetArea}
assetAreas={assetAreas}
assetTypes={assetTypes}
setAssetAreas={setAssetAreas}
setAssetTypes={setAssetTypes}></CreateAssetModal>
<CreateMonitoringDeviceModal
openMonitoringDevice={monitoringDeviceOpen}
handleMonitoringDeviceChange={handleMonitoringDeviceInputChange}
handleMonitoringDeviceClose={handleMonitoringDeviceClose}
handleMonitoringDeviceCreate={handleMonitoringDeviceCreate}
handleChangeMonitoringDeviceType={handleChangeMonitoringDeviceType}
handleChangeMonitoringDeviceArea={handleChangeMonitoringDeviceArea}
monitoringDeviceAreas={monitoringDeviceAreas}
monitoringDeviceTypes={monitoringDeviceTypes}
setMonitoringDeviceAreas={setMonitoringDeviceAreas}
setMonitoringDeviceTypes={setMonitoringDeviceTypes}
isMonitoringDeviceNameExist={isExist.isMonitoringDeviceNameExist}></CreateMonitoringDeviceModal>
</TwinLayout>
)
}
const mapStateToProps = (state: any) => ({ ...state })
const mapDispatchToProps = (dispatch: React.Dispatch<any>) => ({
updateSelected: (asset: Asset) => dispatch(setSelectedAsset(asset)),
updateSelectedSite: (site: Site) => dispatch(setSelectedSite(site)),
})
export default connect(mapStateToProps, mapDispatchToProps)(SiteDetail)
这是模态的:
import React from 'react'
import { Avatar, Button, Chip, Link, List, ListItem, ListItemAvatar, ListItemButton, ListItemText, Typography } from '@mui/material'
import { deepPurple } from '@mui/material/colors'
import { Asset, MeasuringPoint, MonitoredComponent } from '../types/entities'
import { connect } from 'react-redux'
import { setSelectedAsset } from '../actions'
import SpreadOperatorButton from './SpreadOperatorButton'
function ListAvatarData(prop: { handleClick?: ((item: Asset) => void) | ((item: MeasuringPoint) => void); setDelete: any; data: any; type: string; fetchData: any }) {
const { data, type } = prop
const handleClick = (item: any) => {
if (prop.handleClick) prop.handleClick(item)
}
const getAvatarTitle = (item: any) => {
if (type === 'Assets') return item.type.name.at(0)
if (type === 'Components') return item.name.at(0)
return item.type.at(0)
}
const getItemText = (item: any) => {
if (type === 'MeasuringPoints' && item.monitoredComponents.length)
return (
<div>
{item.monitoredComponents.map((mc: MonitoredComponent) => {
return <Chip key={mc.id} className="chip" color="primary" label={mc.name}></Chip>
})}
</div>
)
if (type === 'Components' && item.serialNumber)
return (
<div>
<Typography fontSize={14} fontWeight={400}>
{item?.manufacturer} - {item?.model}
</Typography>
<Typography fontSize={14} fontWeight={400}>
{item?.serialNumber}
</Typography>
</div>
)
return null
}
return (
<div>
{data?.map((item: any, index: number) => {
return (
<List sx={{ width: '100%', bgcolor: 'background.paper' }}>
<ListItem key={item.id}>
{type !== 'MeasuringPoints' && (
<ListItemAvatar>
<Link href="#">
<Avatar sx={{ bgcolor: deepPurple[500] }}>{getAvatarTitle(item)}</Avatar>
</Link>
</ListItemAvatar>
)}
<div>
<Button onClick={() => handleClick(item)} sx={{ textAlign: 'left' }}>
<ListItemText
aria-multiline
primary={
<Typography fontWeight={600} fontSize={16} color={'#1B1B1F'}>
{type === 'MeasuringPoints' ? item.location : item.name}
</Typography>
}
secondary={type == 'Assets' ? item.type.name : item.type}
/>
</Button>
{getItemText(item)}
</div>
<ListItemButton className="flex" sx={{ justifyContent: 'flex-end' }}>
<SpreadOperatorButton fetchData={prop.fetchData} data={item} listType={prop.type} setDelete={prop.setDelete}></SpreadOperatorButton>
</ListItemButton>
</ListItem>
</List>
)
})}
</div>
)
}
const mapStateToProps = (state: any) => ({ ...state })
const mapDispatchToProps = (dispatch: React.Dispatch<any>) => ({
updateSelected: (asset: Asset) => dispatch(setSelectedAsset(asset)),
})
export default connect(mapStateToProps, mapDispatchToProps)(ListAvatarData)
当我在React.useEffect()
中使用if(deleteItem)
语句时,ListAvatarData组件中的选择框没有返回任何项。当我删除if(deleteItem)语句并直接使用下面的useEffect时,它没有返回任何问题。
React.useEffect(() => {
if (deleteItem) fetchData()
}, [deleteItem])
我不明白这种行为的原因,但任何回答都是非常感谢的。谢谢!
1条答案
按热度按时间nfs0ujit1#
在代码的什么地方将deleteItem设置为true?
我觉得应该是
当状态
deleteItem
发生变化时,将触发以[deletItem]
作为依赖项的React.useEffect
。如果您只使用React.useEffect()
,则仅在第一次渲染时触发。UseEffect文档React