簡體   English   中英

使用 useState 更新 React 道具?

[英]React props updating with useState?

我有下面的組件,我正在嘗試構建功能以允許用戶更新商店的開放時間。

我將原始開放時間作為道具傳遞,並使用初始 state 的道具開放時間創建一些 state。 我想使用新的 state 提交更改,但如果用戶選擇取消 UI 更新以反映原始時間。

我的大部分功能都在工作,但由於某種原因,我的處理程序使用輸入更改更新 state 似乎也更新了 props 值,因此它不會 go 恢復到原始值。

如何停止道具更新並確保僅更改allOpeningHours state?

視頻: https://www.veed.io/view/c40bf9e8-7502-408a-ba6d-fd306dbf4b6f?sharingWidget=true

輸出截圖

const EditStudioHours: FC<{ studio: Studio }> = ({ studio }) => {
  const { value: edit, toggle: toggleEdit } = useBoolean(false)
  const { value: submitting, toggle: toggleSubmitting } = useBoolean(false)
  const [allOpeningHours, setAllOpeningHours] = useState([
    ...studio.openingHours.regularDays,
  ])

  return (
    <Box>
      <Typography variant='h6' mt={2} gutterBottom>
        Set standard hours
      </Typography>
      <Typography fontWeight='light' fontSize={14}>
        Configure the standard operating hours of this studio
      </Typography>
      <Stack mt={3} spacing={2}>
        {studio.openingHours.regularDays.map((hours, i) => (
          <DayOfWeek
            dow={daysOfWeek[i]}
            openingHours={hours}
            edit={edit}
            i={i}
            setAllOpeningHours={setAllOpeningHours}
            allOpeningHours={allOpeningHours}
          />
        ))}
      </Stack>

      <Button
        variant={edit ? 'contained' : 'outlined'}
        onClick={() => {
          toggleEdit()
        }}
        fullWidth
        sx={{ mt: 2 }}
        disabled={!edit ? false : submitting}
      >
        {submitting ? (
          <CircularProgress size={22} />
        ) : edit ? (
          'Submit changes'
        ) : (
          'Edit'
        )}
      </Button>
      {edit && (
        <Button
          onClick={toggleEdit}
          variant={'outlined'}
          sx={{ mt: 1 }}
          fullWidth
        >
          Cancel
        </Button>
      )}
    </Box>
  )
}

export default EditStudioHours

const DayOfWeek: FC<{
  openingHours: { start: number; end: number }
  dow: string
  edit: boolean
  i: number
  setAllOpeningHours: any
  allOpeningHours: any
}> = ({ openingHours, dow, edit, i, setAllOpeningHours, allOpeningHours }) => {
  const [open, setOpen] = useState(openingHours.end !== openingHours.start)

  const handleOpenClose = () => {
    open &&
      setAllOpeningHours((ps: any) => {
        const newHours = [...ps]
        newHours[i].start = 0
        newHours[i].end = 0
        return newHours
      })
    setOpen((ps) => !ps)
  }

  const handleStart = (e: any) => {
    setAllOpeningHours((prevState: any) => {
      const newHours = [...prevState]
      newHours[i].start = e.target.value
      return newHours
    })
  }

  const handleEnd = (e: any) => {
    setAllOpeningHours((ps: any) => {
      const newHours = [...ps]
      newHours[i].end = e.target.value
      return newHours
    })
  }

  return (
    <Box display='flex' alignItems='center' justifyContent={'space-between'}>
      <Box display={'flex'} alignItems='center'>
        <Typography width={150}>{dow}</Typography>
        <FormGroup>
          <FormControlLabel
            control={
              <Switch
                disabled={!edit}
                checked={open}
                onChange={handleOpenClose}
              />
            }
            label='Open'
          />
        </FormGroup>
      </Box>

      {open && (
        <Box display={'flex'} alignItems='center'>
          <TextField
            disabled={!edit}
            id={`${i}open`}
            select
            label='Open'
            value={edit ? allOpeningHours[i].start : openingHours.start}
            type='number'
            sx={{ minWidth: 120 }}
            size='small'
            onChange={handleStart}
          >
            {openingOptions.map((option: { value: number; label: string }) => (
              <MenuItem dense key={option.value} value={option.value}>
                {option.label}
              </MenuItem>
            ))}
          </TextField>
          <Typography mx={2}>TO</Typography>
          <TextField
            disabled={!edit}
            id={`${i}close`}
            select
            label='Close'
            value={edit ? allOpeningHours[i].end : openingHours.end}
            type='number'
            sx={{ minWidth: 120 }}
            size='small'
            onChange={handleEnd}
          >
            {openingOptions.map((option: { value: number; label: string }) => (
              <MenuItem dense key={option.value} value={option.value}>
                {option.label}
              </MenuItem>
            ))}
          </TextField>
        </Box>
      )}
    </Box>
  )
}

問題是studio.openingHours.regularDays數組中的對象仍然共享相同的引用,即使您復制了數組本身。

當你使用類似的東西時

newHours[i].start = e.target.value

您仍在從道具更新原始對象。

您可以使用Array.prototype.splice()刪除索引i處的 object 並將其替換為新的

const day = newHours[i];
newHours.splice(i, 1, {
  ...day,
  start: e.target.value,
});

在 3 個句柄函數中的每一個中執行此操作。


或者,在從道具創建本地 state 時中斷所有引用

const [allOpeningHours, setAllOpeningHours] = useState(
  studio.openingHours.regularDays.map((day) => ({ ...day }))
);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM