首页 > 解决方案 > 将道具传递给模态传递每个对象

问题描述

我不是 100% 确定这里发生了什么。我有一个显示组件,它使用基于我的数据库的地图显示一堆卡片 - 卡片上有一个编辑按钮,它弹出一个模式,将道具传递给编辑表单。这有点像它的样子:

import React, { useState } from 'react'
import { useQuery, useMutation } from '@apollo/client'

import { GET_ALL_PROJECTS, REMOVE_PROJECT } from '../helpers/queries'
import { makeStyles } from '@material-ui/core/styles'
import DeleteIcon from '@material-ui/icons/Delete'
import EditIcon from '@material-ui/icons/Edit'
import AddForm from './AddForm'
import EditForm from './EditForm'
import AlertMessage from '../Alerts/AlertMessage'
import { Grid, Typography, Card, CardActionArea, CardActions, CardContent, CardMedia, Button, Modal, Backdrop, Fade } from '@material-ui/core'

const useStyles = makeStyles((theme) => ({
  modal: {
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
  },
  paper: {
    backgroundColor: theme.palette.background.paper,
    border: '2px solid #000',
    boxShadow: theme.shadows[5],
    padding: theme.spacing(2, 4, 3),
  },
}));


const DisplayProjects = () => {

  const styles = useStyles()

  const [deleteItem] = useMutation(REMOVE_PROJECT)
  const { loading, error, data } = useQuery(GET_ALL_PROJECTS)
  const [status, setStatusBase] = useState('')
  const [resultMessage, setResultMessage] = useState('')
  const [addOpen, setAddOpen] = useState(false)
  const [editOpen, setEditOpen] = useState(false)

  const onDelete = (id, e) => {
    e.preventDefault()
    deleteItem({
      variables: { id },
      refetchQueries: [{ query: GET_ALL_PROJECTS }]
    }).then(
      res => handleSuccess(res),
      err => handleError(err)
    )

  }

  // Handles Result of the Delete Operation
  const handleSuccess = (res) => {
    console.log(res.data.deleteProject.proj_name)
    // console.log('success!');
    setResultMessage(res.data.deleteProject.proj_name)
    setStatusBase({
      msg: `Successfully Deleted ${resultMessage}`,
      key: Math.random()
    })
  }
  const handleError = (err) => {
    console.log('error')
  }

  //Handles the Modal for Add Project
  const handleAddOpen = () => {
    setAddOpen(true);
  };
  const handleAddClose = () => {
    setAddOpen(false);
  };

//Handles the Modal for Edit Project
  const handleEditOpen = () => {
    setEditOpen(true);
  };
  const handleEditClose = () => {
    setEditOpen(false);
  };


  if (loading) return '...Loading'
  if (error) return `Error: ${error.message}`
  return (
    <div>
      <div style={{ marginTop: 20, padding: 30 }}>
        <Grid container spacing={8} justify='center' alignItems='center'>
          {data.projects.map(p => {
            return (
              <Grid item key={p._id}>
                <Card >
                  <CardActionArea>
                    <div style={{ display: 'flex', justifyContent: 'center' }}>
                      <CardMedia
                        style={{ width: 400, height: 100, paddingTop: 10, }}
                        component='img'
                        alt='Project Image'
                        height='140'
                        image={require('../../images/html-css-javascript-lg.jpg')}
                      />
                    </div>
                    <CardContent >
                      <Typography gutterBottom variant='h5' component="h2">
                        {p.proj_name}
                      </Typography>
                      <Typography component='p'>
                        {p.description}
                      </Typography>
                    </CardContent>
                  </CardActionArea>
                  <CardActions>
                    <Button>
                      <DeleteIcon onClick={e => onDelete(p._id, e)} />
                    </Button>
                    <Button onClick={handleEditOpen}>
                      <Modal
                        open={editOpen}
                        onClose={handleEditClose}
                        closeAfterTransition
                        BackdropComponent={Backdrop}
                        className={styles.modal}
                      >
                        <Fade in={editOpen}>
                          <div className={styles.paper}>
                            <EditForm
                              id={p._id}
                              close={handleEditClose}
                              name={p.proj_name}
                              desc={p.description}
                              gh={p.gh_link}
                              live={p.live_link}
                              img={p.image_url}
                            />
                          </div>
                        </Fade>
                      </Modal>
                      <EditIcon />
                    </Button>
                  </CardActions>
                </Card>
                { status ? <AlertMessage key={status.key} message={status.msg} /> : null}
              </Grid>
            )
          }
          )}

        </Grid>
        <Button type='button' onClick={handleAddOpen}>Add Project</Button>
        <Modal
          open={addOpen}
          onClose={handleAddClose}
          closeAfterTransition
          BackdropComponent={Backdrop}
          className={styles.modal}
        >
          <Fade in={addOpen}>
            <div className={styles.paper}>
              <AddForm close={handleAddClose} />
            </div>
          </Fade>
        </Modal>



      </div>
    </div >
  )
}

export default DisplayProjects

这是表格。我已经将 props 解构为变量,并将它们放入一个名为 details 的状态对象中,这样它们就可以被覆盖并提交到数据库。

import React, { useState } from 'react'
import { useParams } from 'react-router-dom'
import { useMutation, useQuery } from '@apollo/client'
import { EDIT_PROJECT, GET_ALL_PROJECTS, GET_PROJECT_BY_ID} from '../helpers/queries'


const AddForm = (props) => {
  const params = useParams()
  const id = params.toString()
  // console.log(id);
  const [editProjectItem] = useMutation(EDIT_PROJECT)
  const {loading, data, error} = useQuery(GET_PROJECT_BY_ID, {
        variables: {
        id
      },
    })

  const [details, setDetails] = useState({})


  if (loading) return '...Loading';
  if (error) return <p>ERROR: {error.message}</p>;
  if (!data) return <p>Not found</p>;
  setDetails(data.projectById)
  console.log(data.projectById)


  
  const submitForm = e => {
    e.preventDefault()
    try {
    editProjectItem({
      variables: { id, proj_name, description, gh_link, live_link, image_url},
      refetchQueries: [{query: GET_ALL_PROJECTS}]
    })
  }
  catch (err) {
        console.log('You Goofed')
    }

    // setDetails({
    //   proj_name: '',
    //   description: '',
    //   gh_link: '',
    //   live_link: '',
    //   image_url: ''
    // })
    props.close()
  }

  const changeDetails = (e) => {
    setDetails({
      ...details,
      [e.target.name]: e.target.value
    })
  }
  const {_id, proj_name, description, gh_link, live_link, image_url} = details

  return (
    <div key = {_id}>

      <h2>Edit {proj_name}</h2>

      <form onSubmit = {submitForm} >

      <label>
        Project Name:
        <input
          name = 'proj_name'
          value = {proj_name}
          onChange = {changeDetails}
          />
        </label>
      <label>Description</label>
      <input
        name = 'description'
        value = {description}
        onChange = {changeDetails}
        />
        <label>GitHub Link</label>
      <input
        name  = 'gh_link'
        value = {gh_link}
        onChange = {changeDetails}
        />
        <label>Live Link</label>
      <input
        name = 'live_link'
        value = {live_link}
        onChange = {changeDetails}
        />
        <label>Preview Image</label>
      <input
        name = 'image_url'
        value = {image_url}
        onChange = {changeDetails}
        />
        <button type = 'submit'>Submit</button>
      </form>
    </div>
  )
  }

export default AddForm

我遇到的问题是,当我访问模式时,道具是从字面上的每个对象发送的,而不是一个,并显示最后一条记录的数据而不是我要编辑的那个你可以看到什么发生在这里(我记录了 props.id 以进行测试)https://imgur.com/a/pcEKl89

我错过了什么?(免责声明:我还是个学生,正在学习这门手艺……请对我的代码温柔一点)

编辑:我刚刚意识到我没有指出这是 EditForm 组件的最终形式。我还没有添加逻辑来进行更新,我只是想先让数据正确显示。

EDIT2:我对 ID 的传递方式进行了一些更改,我已经在使用 React-Router,所以我继续进行路由到 /edit/:id,然后使用 useParams(),我以这种方式获得了 ID。它似乎正在工作,但是现在我收到了太多重新渲染消息。更新了上面的 AddForm 代码以反映更改..

标签: javascriptreactjsmodal-dialogreact-props

解决方案


我发现了重新渲染问题..就像将 setDetails 函数放入 useEffect Hook 一样简单:

useEffect(()=> {
    if(data){
      setDetails(data.projectById)
    }
  },[data])

推荐阅读