Событие React запускает видимое обновление страницы при повторном отображении

#javascript #reactjs

Вопрос:

Я пытаюсь понять, почему любое событие вызывает видимое обновление страницы при повторном рендеринге. Ниже приведен родительский компонент :

 export default function FullScreenDialog({purchaseList={"testtest":"900","heyzi":"90"}}) {
  const [open, setOpen] = React.useState(false);
  const [pieChartData,setPieChartData]=React.useState([])
  const [formset,setFormset]=React.useState([
    {
        id: uuidv4(),
        product:"",
        price: 0,
        quantity: 0,
        productSubtotal: 0,
    }
])

const singleForm= {
    id: uuidv4(),
    product:"",
    price: 0,
    quantity: 0,
    productSubtotal: 0,
}

const handleProduct = (e,id) => {   
    const newFormset=formset.map(item=>
        (item.id !== id? item : {
            ...item , product: e.target.value , price:purchaseList[e.target.value]
        })
    )
    setFormset(newFormset)
}

const handleQuantity = (e,id) => {
    const newFormset=formset.map((item)=>
    {
        if (item.id===id){
            const newItem={
                ...item, quantity: e.target.value
            }
            return newItem
        }
        return item
    })
    setFormset(newFormset)
}


const handleAdd=()=>{
    setFormset([...formset,singleForm])
}

const handleDelete=(id)=>{
    const newFormset=formset.filter(item=>
        item.id !==id
    )
    setFormset(newFormset)
}

//below is solely from this component, up is the state from children

  const handleClickOpen = () => {
    setOpen(true);
  };

  const handleClose = () => {
    setOpen(false);  
    handlePieChartData()
  };



  const handlePieChartData=()=>{
    setPieChartData(
        [...pieChartData,{id:uuidv4(), data:formset }])
  }
  
   
  console.log(formset)
  console.log(pieChartData)
 

  return (
    <div>
      <ListOfPieChartsPresenter 
      open={open} 
      handleClickOpen={handleClickOpen} 
      handleClose={handleClose}  
      handleProduct={handleProduct}
      handleQuantity={handleQuantity}
      handleDelete={handleDelete}
      handleAdd={handleAdd}
      purchaseList={purchaseList}
      formset={formset}/>
    </div>
  );
}
 

Вот ListOfPieChartsPresenter компонент:

 const ListOfPieChartsPresenter=({handleClickOpen,open,handleClose,handleProduct,handleQuantity,handleDelete,handleAdd,purchaseList,formset})=>{
  const classes = useStyles();

  const Transition = React.forwardRef(function Transition(props, ref) {
    return <Slide direction="up" ref={ref} {...props} />;
  });

  
    return (
        <div>
            <Button variant="outlined" color="primary" onClick={handleClickOpen}>
        Open full-screen dialog
      </Button>
      <Dialog fullScreen open={open} onClose={handleClose} TransitionComponent={Transition}>
        <AppBar className={classes.appBar}>
          <Toolbar>
            <IconButton edge="start" color="inherit" onClick={handleClose} aria-label="close">
              {/* <CloseIcon /> */}
            </IconButton>
            <Typography variant="h6" className={classes.title}>
              Sound
            </Typography>
            <Button autoFocus color="inherit" onClick={handleClose}>
              save
            </Button>
          </Toolbar>
        </AppBar>
        <form >
        <PieChartGroupForm
        handleProduct={handleProduct}
        handleQuantity={handleQuantity}
        handleDelete={handleDelete}
        handleAdd={handleAdd}
        purchaseList={purchaseList} 
        formset={formset}  />
        </form>
      </Dialog>
        </div>
    )
}
 

Наконец, это PieChartGroupFormPresenter :

 const PieChartGroupFormPresenter=({handleProduct,handleQuantity,handleDelete,product,quantity,item,purchaseList,id})=>{
    return (
        <div>
            <FormControl>
            <Select onChange={(e)=>handleProduct(e,id)} value={product}>
                {Object.keys(purchaseList).map((item,index) =>
                    <MenuItem value={item} key={index}>{item}</MenuItem>
                )}
            </Select>
            <TextField onChange={(e)=>handleQuantity(e,id)} value={quantity} />
            <TextField value={item.price} disabled>{item.price}</TextField>
            <button onClick={()=>handleDelete(id)}>Delete</button>
            </FormControl>
            <br>

            </br>
        </div>
    )
}
 

Я просматриваю это уже около часа и до сих пор понятия не имею, почему это происходит. Не могли бы вы поделиться своим мнением? Спасибо!

Комментарии:

1. какое событие вызывает повторную визуализацию конкретно?

2. @кевин в любом случае ! вот что для меня так умопомрачительно …

3. попробуйте добавить event.preventdefault() в форму функции отправки

4. @AmruthLS Я пробовал e.preventDefault() везде, но это поведение сохраняется…

Ответ №1:

Первая проблема заключается в том, что с функциональными компонентами каждый раз, когда родитель повторяет отправку, ребенок также повторяет отправку. Вы можете исправить это с помощью React.memo :

 const PieChartGroupFormPresenter = React.memo(({handleProduct,handleQuantity,handleDelete,product,quantity,item,purchaseList,id})=>{
  //...
});
 

Вторая проблема заключается в том, что каждый раз, когда вы выполняете код, const handleAdd=()=>{...} вы получаете другую функцию (закрытие). Таким образом, каждый раз FullScreenDialog , когда состояние меняется, оно будет изменять все переданные реквизиты ListOfPieChartsPresenter .

Вы можете использовать useCallback крюк, чтобы улучшить это: тогда функция/закрытие изменится только при изменении указанных зависимостей. Например:

 const handleAdd = React.useCallback(()=>{
    setFormset([...formset,singleForm])
}, [formset, singleForm]);
 

Однако обратите внимание, что эта функция обратного вызова все равно будет меняться всякий formset раз, когда или singleForm изменится, поэтому она все равно вызовет повторный вызов при изменении этого состояния.

Так что, надеюсь, по крайней мере понятно, почему происходят повторные заявки и почему их трудно предотвратить. К сожалению, я недостаточно знаком с переходами React, чтобы понять, почему они запускаются для каждого повторного участника.

Комментарии:

1. Большое спасибо за ваш ответ ! Я пытался это реализовать , но все равно не работает …