从Firestore集合获取的列表被复制。

huangapple go评论71阅读模式
英文:

List getting duplicated from Firestore Collections

问题

I can help you with the translation of your code. Here are the code portions you provided:

// 以下是添加数据到集合的代码
import Sidebar from './../../components/sidebar/Sidebar';
import Navbar from './../../components/navbar/Navbar';
import "./new.scss";
import { useState } from 'react';
import DriveFolderUploadIcon from '@mui/icons-material/DriveFolderUpload';
import { addDoc, collection, serverTimestamp } from "firebase/firestore"; 
import { db } from '../../firebase';
import { useNavigate } from 'react-router-dom';

const New = ({inputs}) => {
  const [file, setFile] = useState("");
  const [data, setData] = useState({});
  const navigate = useNavigate();

  const handleInput = (e) =>{
    const id = e.target.id;
    const value = e.target.value;
    setData({...data, [id]:value});
  }

  const handleAdd = async(e) => {
      e.preventDefault();
      // 在集合 "clients" 中添加新文档
      await addDoc(collection(db, "clients"), {
        ...data,
        timeStamp: serverTimestamp(),
      });
      navigate("/users");
  }

  return (
    <div className='new'>
      <Sidebar/>
      <div className="newContainer">
        <Navbar/>
        <div className="top">
          <h1>Add New Client</h1>
        </div>
        <div className="bottom">
          <div className="left">
            <img src={file ? URL.createObjectURL(file): "https://icon-library.com/images/no-image-icon/no-image-icon-0.jpg"} alt=''/>
          </div>
          <div className="right">
            <form onSubmit={handleAdd}>
              <div className="formInput">
                <label htmlFor="file">
                  Image: <DriveFolderUploadIcon className="icon" />
                </label>
                <input
                  type="file"
                  id="file"
                  onChange={(e) => setFile(e.target.files[0])}
                  style={{ display: "none" }}
                />
              </div>
              {inputs.map((input) => (
                <div className="formInput" key={input.id}>
                  <label>{input.label}</label>
                  <input
                    id={input.id}
                    type={input.type}
                    placeholder={input.placeholder}
                    onChange={handleInput}
                  />
                </div>
              ))}
              <button type="submit">
                Send
              </button>
            </form>
          </div>
        </div>
      </div>
    </div>
  )
}

export default New

// 以下是从集合中获取数据的代码
import { DataGrid } from "@mui/x-data-grid";
import "./datatable.scss";
import { userColumns } from "../../datatablesource";
import VisibilityIcon from '@mui/icons-material/Visibility';
import EditNoteIcon from '@mui/icons-material/EditNote';
import DeleteIcon from '@mui/icons-material/Delete';
import { Link } from "react-router-dom";
import { useEffect, useState } from "react";
import { Tooltip } from "@mui/material";
import { collection, getDocs } from "firebase/firestore";
import { doc, deleteDoc } from "firebase/firestore";
import { db } from "../../firebase";

const Datatable = () => {
  const [data, setData] = useState([]);
  let list = [];
  
  useEffect(() =>{
    const fetchData = async () =>{
      const querySnapshot = await getDocs(collection(db, "clients"));
      querySnapshot.forEach((doc) => {
        list.push({ id: doc.id, ...doc.data()})
      });
      setData(list);
    }
    fetchData();
  }, [])

  const handleDelete = async (id) => {
    try {
      await deleteDoc(doc(db, "clients", id));
      setData(data.filter((item) => item.id !== id));
    } catch (err) {
      console.log(err);
    }
  };

  const actionColumn = [
    { field: "action", headerName: "Action", width: 150, renderCell:(params)=>{
      return (
        <div className="cellAction">
          <Link>
            <Tooltip title="View Client" placement="bottom">
              <div className="viewButton"><VisibilityIcon/></div>
            </Tooltip>
          </Link>
          <Link>
            <Tooltip title="Edit Client" placement="bottom">
              <div className="editButton"><EditNoteIcon/></div>
            </Tooltip>
          </Link>
          <Link>
            <Tooltip title="Delete Client" placement="bottom">
              <div className="deleteButton"  onClick={() => handleDelete(params.row.id)}><DeleteIcon/></div>
            </Tooltip>
          </Link>
        </div>
      )
    }}
  ]

  return (
    <div className="datatable">
      <div className="datatableTitle">
        Add New Client
        <Link to="/users/new" className="link">
          Add New
        </Link>
      </div>
      <DataGrid
        className="datagrid"
        rows={data}
        columns={userColumns.concat(actionColumn)}
        pageSize={9}
        rowsPerPageOptions={[9]}
        checkboxSelection
      />
    </div>
  )
}

export default Datatable

If you have any specific questions or need further assistance, please let me know.

英文:

currently I'm trying to get document from a collection on firestore, each time I add a document on my application, the list gets duplicated on my application yet I'm only viewing an ID for that document in the firestore collection...

Here's my code for add data to the collection:-

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

import Sidebar from &#39;./../../components/sidebar/Sidebar&#39;;
import Navbar from &#39;./../../components/navbar/Navbar&#39;;
import &quot;./new.scss&quot;
import { useState } from &#39;react&#39;;
import DriveFolderUploadIcon from &#39;@mui/icons-material/DriveFolderUpload&#39;;
import { addDoc, collection, serverTimestamp } from &quot;firebase/firestore&quot;; 
import { db } from &#39;../../firebase&#39;;
import { useNavigate } from &#39;react-router-dom&#39;;
const New = ({inputs}) =&gt; {
const [file, setFile] = useState(&quot;&quot;);
const [data, setData] = useState({});
const navigate = useNavigate();
const handleInput = (e) =&gt;{
const id = e.target.id;
const value = e.target.value
setData({...data, [id]:value});
}
const handleAdd = async(e) =&gt; {
e.preventDefault();
// Add a new document in collection &quot;cities&quot;
await addDoc(collection(db, &quot;clients&quot;), {
...data,
timeStamp: serverTimestamp(),
});
navigate(&quot;/users&quot;)
}
return (
&lt;div className=&#39;new&#39;&gt;
&lt;Sidebar/&gt;
&lt;div className=&quot;newContainer&quot;&gt;
&lt;Navbar/&gt;
&lt;div className=&quot;top&quot;&gt;
&lt;h1&gt;Add New Client&lt;/h1&gt;
&lt;/div&gt;
&lt;div className=&quot;bottom&quot;&gt;
&lt;div className=&quot;left&quot;&gt;
&lt;img src={file ? URL.createObjectURL(file): &quot;https://icon-library.com/images/no-image-icon/no-image-icon-0.jpg&quot;} alt=&#39;&#39;/&gt;
&lt;/div&gt;
&lt;div className=&quot;right&quot;&gt;
&lt;form onSubmit={handleAdd}&gt;
&lt;div className=&quot;formInput&quot;&gt;
&lt;label htmlFor=&quot;file&quot;&gt;
Image: &lt;DriveFolderUploadIcon className=&quot;icon&quot; /&gt;
&lt;/label&gt;
&lt;input
type=&quot;file&quot;
id=&quot;file&quot;
onChange={(e) =&gt; setFile(e.target.files[0])}
style={{ display: &quot;none&quot; }}
/&gt;
&lt;/div&gt;
{inputs.map((input) =&gt; (
&lt;div className=&quot;formInput&quot; key={input.id}&gt;
&lt;label&gt;{input.label}&lt;/label&gt;
&lt;input
id={input.id}
type={input.type}
placeholder={input.placeholder}
onChange={handleInput}
/&gt;
&lt;/div&gt;
))}
&lt;button type=&quot;submit&quot;&gt;
Send
&lt;/button&gt;
&lt;/form&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
)
}
export default New

<!-- end snippet -->

Here's also the code where I'm fetching the data from the collection:-

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

import { DataGrid } from &quot;@mui/x-data-grid&quot;;
import &quot;./datatable.scss&quot;;
import { userColumns } from &quot;../../datatablesource&quot;;
import VisibilityIcon from &#39;@mui/icons-material/Visibility&#39;;
import EditNoteIcon from &#39;@mui/icons-material/EditNote&#39;;
import DeleteIcon from &#39;@mui/icons-material/Delete&#39;;
import { Link } from &quot;react-router-dom&quot;;
import { useEffect, useState } from &quot;react&quot;;
import { Tooltip } from &quot;@mui/material&quot;;
import { collection, getDocs } from &quot;firebase/firestore&quot;;
import { doc, deleteDoc } from &quot;firebase/firestore&quot;;
import {db} from &quot;../../firebase&quot;
const Datatable = () =&gt; {
const [data, setData] = useState([]);
let list = []
useEffect(() =&gt;{
const fetchData = async () =&gt;{
const querySnapshot = await getDocs(collection(db, &quot;clients&quot;));
querySnapshot.forEach((doc) =&gt; {
list.push({ id: doc.id, ...doc.data()})
});
setData(list);
}
fetchData();
}, [])
const handleDelete = async (id) =&gt; {
try {
await deleteDoc(doc(db, &quot;clients&quot;, id));
setData(data.filter((item) =&gt; item.id !== id));
} catch (err) {
console.log(err);
}
};
const actionColumn = [
{ field: &quot;action&quot;, headerName: &quot;Action&quot;, width: 150, renderCell:(params)=&gt;{
return (
&lt;div className=&quot;cellAction&quot;&gt;
&lt;Link&gt;
&lt;Tooltip title=&quot;View Client&quot; placement=&quot;bottom&quot;&gt;
&lt;div className=&quot;viewButton&quot;&gt;&lt;VisibilityIcon/&gt;&lt;/div&gt;
&lt;/Tooltip&gt;
&lt;/Link&gt;
&lt;Link&gt;
&lt;Tooltip title=&quot;Edit Client&quot; placement=&quot;bottom&quot;&gt;
&lt;div className=&quot;editButton&quot;&gt;&lt;EditNoteIcon/&gt;&lt;/div&gt;
&lt;/Tooltip&gt;
&lt;/Link&gt;
&lt;Link&gt;
&lt;Tooltip title=&quot;Delete Client&quot; placement=&quot;bottom&quot;&gt;
&lt;div className=&quot;deleteButton&quot;  onClick={() =&gt; handleDelete(params.row.id)}&gt;&lt;DeleteIcon/&gt;&lt;/div&gt;
&lt;/Tooltip&gt;
&lt;/Link&gt;
&lt;/div&gt;
)
}}
]
return (
&lt;div className=&quot;datatable&quot;&gt;
&lt;div className=&quot;datatableTitle&quot;&gt;
Add New Client
&lt;Link to=&quot;/users/new&quot; className=&quot;link&quot;&gt;
Add New
&lt;/Link&gt;
&lt;/div&gt;
&lt;DataGrid
className=&quot;datagrid&quot;
rows={data}
columns={userColumns.concat(actionColumn)}
pageSize={9}
rowsPerPageOptions={[9]}
checkboxSelection
/&gt;
&lt;/div&gt;
)
}
export default Datatable

<!-- end snippet -->

Yet it's still getting duplicated on my list, can anyone assist me on this??

答案1

得分: 1

list 移动到 fetchData 函数内部:

  let list = []; // &lt;-- NOT HERE!

  useEffect(() =&gt;{
    const fetchData = async () =&gt;{
      let list = []; // &lt;-- MOVE HERE
      const querySnapshot = await getDocs(collection(db, &quot;clients&quot;));
      querySnapshot.forEach((doc) =&gt; {
        list.push({ id: doc.id, ...doc.data()})
      });
      setData(list);
    }
    fetchData();
  }, [])

在 React v18 中,组件会呈现两次(在 ReactStrict 模式下)。fetchData 外部的 list 创建了一个闭包并且两次追加(push)数据。


旁注:如果需要追加到 data 状态变量中,则使用状态设置器的回调版本:

setData( prevData =&gt; /* 使用 prevData 和 list 进行操作 */ );
英文:

Move the list inside the fetchData function:

  let list = []; // &lt;-- NOT HERE!

  useEffect(() =&gt;{
    const fetchData = async () =&gt;{
      let list = []; // &lt;-- MOVE HERE
      const querySnapshot = await getDocs(collection(db, &quot;clients&quot;));
      querySnapshot.forEach((doc) =&gt; {
        list.push({ id: doc.id, ...doc.data()})
      });
      setData(list);
    }
    fetchData();
  }, [])

In React v18, the Component will render twice (in ReactStrict mode). The list outside the fetchData creates a closure and appends (push) the data twice.


Sidenote: If you need to append to the data state variable, then use the callback version of the state setter:

setData( prevData =&gt; /* Do something with prevData and list */ );

huangapple
  • 本文由 发表于 2023年5月21日 04:44:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/76297283.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定