{"id":38187,"date":"2023-09-19T00:53:59","date_gmt":"2023-02-23T14:26:07","guid":{"rendered":"https:\/\/www.silicloud.com\/zh\/blog\/%e9%80%8f%e9%81%8e%e9%96%8b%e7%99%bc2023%e5%b9%b4%e5%ba%a6%e7%9a%84%e3%80%90react-x-firebase%e3%80%91todo%e6%87%89%e7%94%a8%e7%a8%8b%e5%bc%8f%ef%bc%8c%e4%be%86%e5%ad%b8%e7%bf%92%e3%80%82\/"},"modified":"2024-05-04T00:25:42","modified_gmt":"2024-05-03T16:25:42","slug":"%e9%80%8f%e9%81%8e%e9%96%8b%e7%99%bc2023%e5%b9%b4%e5%ba%a6%e7%9a%84%e3%80%90react-x-firebase%e3%80%91todo%e6%87%89%e7%94%a8%e7%a8%8b%e5%bc%8f%ef%bc%8c%e4%be%86%e5%ad%b8%e7%bf%92%e3%80%82","status":"publish","type":"post","link":"https:\/\/www.silicloud.com\/zh\/blog\/%e9%80%8f%e9%81%8e%e9%96%8b%e7%99%bc2023%e5%b9%b4%e5%ba%a6%e7%9a%84%e3%80%90react-x-firebase%e3%80%91todo%e6%87%89%e7%94%a8%e7%a8%8b%e5%bc%8f%ef%bc%8c%e4%be%86%e5%ad%b8%e7%bf%92%e3%80%82\/","title":{"rendered":"\u900f\u904e\u958b\u767c2023\u5e74\u5ea6\u7684\u3010React x Firebase\u3011Todo\u61c9\u7528\u7a0b\u5f0f\uff0c\u4f86\u5b78\u7fd2"},"content":{"rendered":"<h1>\u9996\u5148<\/h1>\n<p>\u8fd9\u6b21\u4f5c\u4e3a\u5b66\u4e60React\u7684\u7b2c\u4e00\u6b65\uff0c\u6211\u5c1d\u8bd5\u521b\u5efa\u4e86\u4e00\u4e2a&#8221;Todo\u5e94\u7528&#8221;\u3002\u6211\u4f7f\u7528\u4e86\u4e24\u5e74\u524d\u5728YouTube\u4e0a\u7684\u89c6\u9891\u4e2d\u65e0\u6cd5\u4f7f\u7528\u7684\u4ee3\u7801\u7b49\u3002<\/p>\n<p>&nbsp;<\/p>\n<p>\u6211\u5011\u7684\u76ee\u6a19\u662f\u5be6\u73fe\u300c\u767b\u5165\/\u767b\u51fa\u529f\u80fd\u300d\u4ee5\u53ca\u76f8\u95dc\u7684\u300c\u7528\u6236\u72c0\u614b\u7ba1\u7406\u300d\u3002\u901a\u904e\u4f7f\u7528Firebase Firestore\uff0c\u6211\u5011\u53ef\u4ee5\u5be6\u73fe\u4fdd\u5b58\u300c\u7528\u6236\u4fe1\u606f\u300d\u548c\u300c\u5f85\u8fa6\u4e8b\u9805\u4fe1\u606f\u300d\u7684\u529f\u80fd\u3002<\/p>\n<p>\u7531\u4e8e\u5c1a\u672a\u7f16\u5199Firestore\u89c4\u5219\uff0c\u6b64\u7f51\u7edc\u5e94\u7528\u7a0b\u5e8f\u5c1a\u4e0d\u5b8c\u5584\uff0c\u4f46\u6700\u7ec8\u4ea7\u54c1\u5982\u4e0b\u6240\u793a\u3002<\/p>\n<p>\u8fd9\u6b21\u7684\u6210\u54c1<br \/>\nhttps:\/\/react-todolist-a2dda.web.app\/<\/p>\n<div><img decoding=\"async\" class=\"post-images\" title=\"\" src=\"https:\/\/cdn.silicloud.com\/blog-img\/blog\/img\/657d332137434c4406c64849\/6-0.png\" alt=\"TodoApp (2).PNG\" \/><\/div>\n<h1>\u5b9e\u9645\u64cd\u4f5c\u6307\u5357\u7684\u8d44\u6599<\/h1>\n<p>\u6211\u76f8\u4fe1\u603b\u4f1a\u6709\u4eba\u60f3\u8981\u5b66\u4e60\uff0c\u6240\u4ee5\u6211\u5c06\u5b9e\u8df5\u64cd\u4f5c\u7684\u6b65\u9aa4\u6309\u7167\u6bcf\u4e2a\u9636\u6bb5\u8fdb\u884c\u4e86\u8bf4\u660e\u3002<\/p>\n<p>\u5982\u679c\u53ea\u662f\u5236\u4f5c\u7684\u8bdd\uff0c\u53ef\u4ee5\u901a\u8fc7\u590d\u5236\u7c98\u8d34\u5e76\u4fee\u6539\u6570\u503c\u6765\u5b8c\u6210\uff0c\u4f46\u6211\u4e2a\u4eba\u8ba4\u4e3a\u4e86\u89e3\u5236\u4f5c\u8fc7\u7a0b\u5728\u7f16\u7a0b\u5b66\u4e60\u4e2d\u4e5f\u662f\u91cd\u8981\u7684\uff0c\u6240\u4ee5\u6211\u4f1a\u628a\u5b83\u5199\u4e0a\u3002<\/p>\n<p>\u7531\u65bc\u9019\u7bc7\u6587\u7ae0\u7684\u89e3\u8aaa\u4e0d\u8db3\uff0c\u6211\u6703\u88dc\u5145\u4e00\u4e9b\u5167\u5bb9\u3002<\/p>\n<p>\u2191\u2191\u2191\u6211\u5c06\u89e3\u91caCodeLab\u5f62\u5f0f\u7684\u89e3\u91ca\u65b9\u6cd5\u3002<\/p>\n<h1>React\u7684\u53c2\u8003\u8d44\u6599<\/h1>\n<h3>\u5b98\u65b9\u7f51\u7ad9<\/h3>\n<p>\u5728\u5b66\u4e60React\u7684\u8fc7\u7a0b\u4e2d\uff0c\u6211\u4e5f\u7ecf\u5e38\u8bbf\u95eeReact\u5b98\u65b9\u7f51\u7ad9\u3002\u6211\u8ba4\u4e3a\uff0c\u57fa\u672c\u4e0a\u5728\u8fd9\u91cc\u67e5\u627e\u6240\u9700\u7684\u4fe1\u606f\u662f\u5f88\u597d\u7684\u3002<\/p>\n<p>&nbsp;<\/p>\n<h3>\u4e2a\u4eba\u89c2\u70b9\u662f\uff0c\u503c\u5f97\u6ce8\u610f\u7684\u7f51\u7ad9<\/h3>\n<p>\u5f53\u4f60\u60f3\u76f4\u89c2\u5730\u7406\u89e3React\u662f\u4ec0\u4e48\u65f6\uff0c\u4ee5\u4e0b\u8d44\u6599\u662f\u5f88\u597d\u7684\u53c2\u8003\u3002<br \/>\n\u5728\u5f00\u59cb\u5b66\u4e60\u4e4b\u524d\uff0c\u6211\u5efa\u8bae\u5148\u8f7b\u677e\u5730\u6d4f\u89c8\u4e00\u4e0b&#8221;#01&#8243;\u548c&#8221;#02&#8243;\uff0c\u6216\u8005\u5c1d\u8bd5\u4e00\u4e9b\u5b9e\u8df5\u3002<\/p>\n<div>\u8fd9\u4efd\u8d44\u6599\u662f\u5728\u300c2018\u5e74\u300d\u64b0\u5199\u7684\u3002\u5c3d\u7ba1\u6839\u672c\u90e8\u5206\u6ca1\u6709\u592a\u5927\u53d8\u5316\uff0c\u4e0d\u5efa\u8bae\u5b8c\u5168\u6309\u539f\u6837\u7ee7\u7eed\u8fdb\u884c\u3002<\/div>\n<p>&nbsp;<\/p>\n<h1>\u5fc5\u987b\u7684\u63a7\u5236\u53f0\u64cd\u4f5c\u548c\u4ee3\u7801\u5b8c\u6210\u54c1<\/h1>\n<h2>\u9700\u8981\u4f5c\u4e3a\u524d\u63d0\u6761\u4ef6\u7684\u4e1c\u897f<\/h2>\n<h3>\u67e5\u770b\u8282\u70b9\u7248\u672c<\/h3>\n<div>\u8bf7\u5728Windows\u7684cmd\u547d\u4ee4\u63d0\u793a\u7b26\u4e2d\u6267\u884c\u547d\u4ee4\u5e76\u8fdb\u884c\u786e\u8ba4\uff0c<\/div>\n<pre class=\"post-pre\"><code>node <span class=\"nt\">-v<\/span>\r\n<\/code><\/pre>\n<h2>\u6211\u8ba4\u4e3a\u5728VScode\u7684cmd\u5185\u6267\u884c\u4ee5\u4e0b\u547d\u4ee4\u662f\u66f4\u597d\u7684\u9009\u9879\u3002<\/h2>\n<h3>npm create-react-app . = \u4f7f\u7528npm\u521b\u5efa\u4e00\u4e2aReact\u5e94\u7528\u7a0b\u5e8f\u3002<br \/>\nnpm create-react-app \u30d5\u30a1\u30a4\u30eb\u540d = \u4f7f\u7528npm\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a\u30d5\u30a1\u30a4\u30eb\u540d\u7684React\u5e94\u7528\u7a0b\u5e8f\u3002<\/h3>\n<p>\u5b66\u4e60React\u65f6\uff0c\u8bf7\u5148\u6267\u884c\u8fd9\u4e2a\u547d\u4ee4\u3002<\/p>\n<p>&nbsp;<\/p>\n<p>\u5728\u5f53\u524d\u6587\u4ef6\u5939\u4e0b\u521b\u5efa\u2193\u2193\u2193<\/p>\n<pre class=\"post-pre\"><code>npm creat-react-app <span class=\"nb\">.<\/span>\r\n<\/code><\/pre>\n<p>\u5982\u679c\u4f60\u5728\u4f7f\u7528cd\u547d\u4ee4\u7b49\u79fb\u52a8\u5230\u4e00\u4e2a\u6587\u4ef6\u5939\u5185\u90e8\uff0c\u60f3\u8981\u65b0\u5efa\u4e00\u4e2a\u6587\u4ef6\u5939\u7684\u8bdd\u2193\u2193\u2193<\/p>\n<pre class=\"post-pre\"><code>npm creat-react-app &lt;\u30d5\u30a1\u30a4\u30eb\u540d&gt;\r\n<\/code><\/pre>\n<h3>\u4f7f\u7528npm\u5b89\u88c5react-router-dom<\/h3>\n<p>\u8fd9\u662f\u7f51\u7ad9\u5185\u9875\u9762\u8df3\u8f6c\u6240\u5fc5\u9700\u7684\u4e1c\u897f\u3002<\/p>\n<h3>\u5b89\u88c5bootstrap\u7684npm\u5305<\/h3>\n<p>\u8fd9\u662f\u7f51\u7ad9\u88c5\u9970\u6240\u9700\u7684\u7269\u54c1\u3002<\/p>\n<h1>\u6570\u636e\u5e93\u8bbe\u8ba1<\/h1>\n<div><img decoding=\"async\" class=\"post-images\" title=\"\" src=\"https:\/\/cdn.silicloud.com\/blog-img\/blog\/img\/657d332137434c4406c64849\/39-0.jpeg\" alt=\"React-TodoApp-Firestore.jpg\" \/><\/div>\n<p>\u5bf9\u4e8e\u7528\u62371\u6765\u8bf4\uff0c\u4ed6\u6709\u591a\u4e2a\u5f85\u529e\u4e8b\u9879\u7684\u4fe1\u606f\u3002<\/p>\n<h1>\u6587\u4ef6\u7ed3\u6784<\/h1>\n<p>\u5728\u8fd9\u91cc\u8fd9\u5927\u90e8\u5206\u9700\u8981\u521b\u5efa\u7684\u6587\u4ef6\u90fd\u6709\u4e86\uff0c\u5b9e\u9645\u4e0a\u4f7f\u7528create-react-app\u547d\u4ee4\u4f1a\u751f\u6210\u4e00\u4e9b\u6587\u4ef6\u548c\u6587\u4ef6\u5939\uff0c\u4f46\u4e0d\u9700\u8981\u7684\u53ef\u4ee5\u5220\u9664\u3002<\/p>\n<pre class=\"post-pre\"><code>C:react-todolist\/src\r\n\u2502  App.css\r\n\u2502  App.js\r\n\u2502  index.css\r\n\u2502  index.js\r\n\u2502  reportWebVitals.js\r\n\u2502  setupTests.js\r\n\u2502\r\n\u251c\u2500Components\r\n\u2502      Header.js\r\n\u2502      Home.js\r\n\u2502      IndividualTodo.js\r\n\u2502      Login.js\r\n\u2502      Modal.js\r\n\u2502      NotFound.js\r\n\u2502      Signup.js\r\n\u2502      Todos.js\r\n\u2502\r\n\u251c\u2500images\r\n\u2502      TodoAppicon.png\r\n\u2502\r\n\u2514\u2500services\r\n        firebase.config.js\r\n<\/code><\/pre>\n<h1>\u4ee3\u7801\u7684\u5b8c\u6574\u4ea7\u54c1 (Code&#8217;s finished product)<\/h1>\n<p>\u5982\u679c\u4f60\u6309\u7167\u5b9e\u9645\u64cd\u4f5c\u6307\u5357\u7684\u8d44\u6599\u8fdb\u884c\u64cd\u4f5c\uff0c\u57fa\u672c\u4e0a\u5e94\u8be5\u4e0d\u4f1a\u6709\u95ee\u9898\u3002<\/p>\n<p>\u53ea\u9700\u8fdb\u884c\u5fc5\u8981\u7684\u5b89\u88c5\uff0c\u521b\u5efa\u6587\u4ef6\u5939\u548c\u6587\u4ef6\uff0c\u7136\u540e\u590d\u5236\u7c98\u8d34\uff0c\u5c31\u53ef\u4ee5\u5b8c\u6210\u4e86\u3002<\/p>\n<h2>\u6e90\u4ee3\u7801 \/ App.js<\/h2>\n<details>App.jsapp.jsx<br \/>\n\u4ece&#8217;react&#8217;\u4e2d\u5bfc\u5165React\u548cComponent<br \/>\n\u4ece&#8217;.\/index.css&#8217;\u4e2d\u5bfc\u5165&#8217;.\/Components\/Home&#8217;\u548c&#8217;.\/Components\/Login&#8217;\u548c&#8217;.\/Components\/Signup&#8217;\u548c&#8217;.\/Components\/NotFound&#8217;\u5e76\u547d\u540d\u4e3aHome\u548cLogin\u548cSignup\u548cNotFound<br \/>\n\u4ece&#8217;.\/services\/firebase.config&#8217;\u4e2d\u5bfc\u5165auth\u548cdb<br \/>\n\u4ece&#8217;firebase\/firestore&#8217;\u4e2d\u5bfc\u5165doc\u548cgetDoc\u548cdeleteDoc\u548cquery\u548cwhere\u548ccollection\u548conSnapshot<br \/>\n\u521b\u5efa\u4e00\u4e2a\u540d\u4e3aApp\u7684\u7c7b\uff0c\u7ee7\u627fComponent\u7c7b<\/p>\n<p>\u72b6\u6001 = {<br \/>\ncurrentUser: null,<br \/>\ntodos: [],<br \/>\neditTodoValue: null<br \/>\n}<\/p>\n<p>componentDidMount() {<br \/>\nauth.onAuthStateChanged(user =&gt; {<br \/>\nif (user) {<br \/>\ngetDoc(doc(db, &#8216;users&#8217;, user.uid)).then(snapshot =&gt; {<br \/>\nthis.setState({<br \/>\ncurrentUser: snapshot.data().userName<br \/>\n})<br \/>\n})<br \/>\n}<br \/>\nelse {<br \/>\nconsole.log(&#8220;\u672a\u767b\u5f55\u7528\u6237&#8221;)<br \/>\n}<br \/>\n})<\/p>\n<p>auth.onAuthStateChanged(user =&gt; {<br \/>\nif (user) {<br \/>\nconst todoList = [];<br \/>\nconst q = query(<br \/>\ncollection(db, &#8216;todos of&#8217; + user.uid),<br \/>\nwhere(&#8216;userId&#8217;, &#8216;==&#8217;, user.uid)<br \/>\n);<br \/>\nconst unsubscribe = onSnapshot(q, (snapshot) =&gt; {<br \/>\nsnapshot.docChanges().forEach((change) =&gt; {<br \/>\nif (change.type === &#8216;added&#8217;) {<br \/>\ntodoList.push({<br \/>\nid: change.doc.id,<br \/>\nTodo: change.doc.data().Todo,<br \/>\n});<br \/>\n}<br \/>\nif (change.type === &#8216;removed&#8217;) {<br \/>\n\/\/console.log(change.type);<br \/>\nfor (let i = 0; i &lt; todoList.length; i++) { if (todoList[i].id === change.doc.id) { todoList.splice(i, 1); } } } }); \/\/ console.log(&#8216;\u5f85\u529e\u4e8b\u9879\u5217\u8868:&#8217;, todoList); this.setState({ todos: todoList }); }); return unsubscribe; } else { console.log(&#8216;\u672a\u767b\u5f55\u7528\u6237&#8217;); } }); } deleteTodo = (id) =&gt; {<br \/>\n\/\/ console.log(id);<br \/>\nauth.onAuthStateChanged((user) =&gt; {<br \/>\nif (user) {<br \/>\nconst docRef = doc(db, &#8216;todos of&#8217; + user.uid, id);<br \/>\ndeleteDoc(docRef)<br \/>\n.then(() =&gt; {<br \/>\nconsole.log(&#8216;\u6587\u6863\u5220\u9664\u6210\u529f\uff01&#8217;);<br \/>\n})<br \/>\n.catch((error) =&gt; {<br \/>\nconsole.error(&#8216;\u5220\u9664\u6587\u6863\u65f6\u51fa\u9519: &#8216;, error);<br \/>\n});<br \/>\n} else {<br \/>\nconsole.log(&#8216;\u672a\u767b\u5f55\u7528\u6237&#8217;);<br \/>\n}<br \/>\n});<br \/>\n};<\/p>\n<p>editModal = (obj) =&gt; {<br \/>\nthis.setState({<br \/>\neditTodoValue: obj<br \/>\n})<br \/>\n}<\/p>\n<p>updateTodoHandler = (editTodo, id) =&gt; {<br \/>\n\/\/ console.log(editTodo, id);<br \/>\nconst todoList = this.state.todos;<br \/>\nfor(let i=0;i&lt;todoList.length;i++){<br \/>\nif(todoList[i].id===id){<br \/>\ntodoList.splice(i,1,{id,Todo: editTodo});<br \/>\n}<br \/>\nthis.setState({<br \/>\ntodos:todoList<br \/>\n})<br \/>\n}<br \/>\n}<\/p>\n<p>render() {<br \/>\n\u8fd4\u56de (<\/p>\n<p>} \/&gt;<br \/>\n} \/&gt;<br \/>\n} \/&gt;<br \/>\n} \/&gt;<\/p>\n<p>)<br \/>\n}<br \/>\n}<\/p>\n<p>\u5bfc\u51fa\u9ed8\u8ba4\u7684App<\/p>\n<\/details>\n<h2>\u6e90\u7801\/\u7d22\u5f15.css<\/h2>\n<details>\u7d22\u5f15.css<br \/>\n* {<br \/>\n\u8fb9\u8ddd: 0;<br \/>\n\u586b\u5145: 0;<br \/>\n}div.\u5305\u88c5\u5668 {<br \/>\n\u6a2a\u5411\u6ea2\u51fa: \u9690\u85cf;<br \/>\n\u7eb5\u5411\u6ea2\u51fa: \u81ea\u52a8;<br \/>\n}<\/p>\n<p>\/* \u5934\u90e8 *\/<br \/>\n.\u5934\u90e8-\u76d2\u5b50 {<br \/>\n\u5bbd\u5ea6: 100%;<br \/>\n\u9ad8\u5ea6: \u81ea\u52a8;<br \/>\n\u586b\u5145: 50px;<br \/>\n\u663e\u793a: \u5f39\u6027;<br \/>\n\u5bf9\u9f50\u5185\u5bb9: \u7a7a\u9699\u5206\u5e03;<br \/>\n\u5bf9\u9f50\u9879\u76ee: \u5c45\u4e2d;<br \/>\n\u80cc\u666f\u989c\u8272: #0170ad;<br \/>\n}<\/p>\n<p>@media(max-width:768px){<br \/>\n.\u5934\u90e8-\u76d2\u5b50{<br \/>\n\u5f39\u6027\u65b9\u5411: \u5782\u76f4;<br \/>\n\u5bf9\u9f50\u5185\u5bb9: \u5c45\u4e2d;<br \/>\n}<br \/>\n}<\/p>\n<p>.\u5934\u90e8-\u76d2\u5b50 .\u5de6\u4fa7 {<br \/>\n\u5f39\u6027: 1;<br \/>\n\u663e\u793a: \u5f39\u6027;<br \/>\n\u5bf9\u9f50\u5185\u5bb9: \u5f39\u6027\u5f00\u59cb;<br \/>\n\u5bf9\u9f50\u9879\u76ee: \u5c45\u4e2d;<br \/>\n}<\/p>\n<p>@media(max-width: 768px){<br \/>\n.\u5934\u90e8-\u76d2\u5b50 .\u5de6\u4fa7{<br \/>\n\u5bbd\u5ea6: 100%;<br \/>\n\u5f39\u6027\u65b9\u5411: \u5782\u76f4-\u53cd\u5411;<br \/>\n\u5bf9\u9f50\u5185\u5bb9: \u5c45\u4e2d;<br \/>\n\u6587\u672c\u5bf9\u9f50: \u4e2d\u5fc3;<br \/>\n\u4e0b\u8fb9\u8ddd: 20px;<br \/>\n}<br \/>\n}<\/p>\n<p>.\u5934\u90e8-\u76d2\u5b50 .\u5de6\u4fa7 .\u56fe\u50cf {<br \/>\n\u5bbd\u5ea6: 170px;<br \/>\n\u9ad8\u5ea6: 170px;<br \/>\n}<\/p>\n<p>.\u5934\u90e8-\u76d2\u5b50 .\u5de6\u4fa7 .\u56fe\u50cf \u56fe\u7247 {<br \/>\n\u5bbd\u5ea6: 100%;<br \/>\n\u9ad8\u5ea6: 100%;<br \/>\n}<\/p>\n<p>.\u5934\u90e8-\u76d2\u5b50 .\u5de6\u4fa7 .\u5185\u5bb9 {<br \/>\n\u989c\u8272: #fff;<br \/>\n}<\/p>\n<p>.\u5934\u90e8-\u76d2\u5b50 .\u5de6\u4fa7 .\u5185\u5bb9 .\u5927\u6807\u9898 {<br \/>\n\u5b57\u4f53\u5927\u5c0f: 42px;<br \/>\n}<\/p>\n<p>.\u5934\u90e8-\u76d2\u5b50 .\u5de6\u4fa7 .\u5185\u5bb9 .\u5c0f\u6807\u9898 {<br \/>\n\u5b57\u4f53\u5927\u5c0f: 24px;<br \/>\n}<\/p>\n<p>.\u5934\u90e8-\u76d2\u5b50 .\u53f3\u4fa7 {<br \/>\n\u5f39\u6027: 1;<br \/>\n\u663e\u793a: \u5f39\u6027;<br \/>\n\u5f39\u6027\u65b9\u5411: \u5782\u76f4;<br \/>\n\u5bf9\u9f50\u5185\u5bb9: \u5c45\u4e2d;<br \/>\n\u5bf9\u9f50\u9879\u76ee: \u5c45\u4e2d;<br \/>\n}<\/p>\n<p>@media(max-width:768px){<br \/>\n.\u5934\u90e8-\u76d2\u5b50 .\u53f3\u4fa7{<br \/>\n\u5bbd\u5ea6: 100%;<br \/>\n\u6587\u672c\u5bf9\u9f50: \u4e2d\u5fc3;<br \/>\n}<br \/>\n}<\/p>\n<p>.\u5934\u90e8-\u76d2\u5b50 .\u53f3\u4fa7 .\u6309\u94ae, .\u5934\u90e8-\u76d2\u5b50 .\u53f3\u4fa7 .\u6309\u94ae:hover{<br \/>\n\u5bbd\u5ea6: 100px;<br \/>\n\u4e0b\u8fb9\u8ddd: 5px;<br \/>\n\u989c\u8272: #fff;<br \/>\n\u6587\u672c\u88c5\u9970: \u65e0;<br \/>\n}<\/p>\n<p>.\u65e5\u671f-\u533a\u5757{<br \/>\n\u989c\u8272: #fff;<br \/>\n}<\/p>\n<p>.\u65e5\u671f-\u533a\u5757 span{<br \/>\n\u5de6\u8fb9\u8ddd: 4px;<br \/>\n}<\/p>\n<p>\/* \u6ce8\u518c *\/<br \/>\n@media(max-width:539px){<br \/>\n.\u6ce8\u518c{<br \/>\n\u5bbd\u5ea6:100%<br \/>\n}<br \/>\n}<\/p>\n<p>.\u9519\u8bef-\u6d88\u606f{<br \/>\n\u989c\u8272: \u7ea2\u8272;<br \/>\n\u5bbd\u5ea6:100%;<br \/>\n\u5b57\u4f53\u5927\u5c0f:14px;<br \/>\n\u5b57\u4f53\u7c97\u7ec6: 600;<br \/>\n}<\/p>\n<p>.\u6b22\u8fce-\u533a\u5757{<br \/>\n\u989c\u8272: #fff;<br \/>\n\u5b57\u6bcd\u95f4\u8ddd: 0.09em;<br \/>\n}<\/p>\n<p>\/* \u5f85\u529e\u4e8b\u9879 *\/<br \/>\n.\u5f85\u529e\u4e8b\u9879{<br \/>\n\u80cc\u666f\u989c\u8272: #e4e4e4;<br \/>\n\u5b57\u4f53\u7c97\u7ec6: 600;<br \/>\n\u5b57\u4f53\u5927\u5c0f: 16px;<br \/>\n\u8fb9\u8ddd: 10px 0px;<br \/>\n\u586b\u5145: 10px;<br \/>\n\u663e\u793a: \u5f39\u6027;<br \/>\n\u5bf9\u9f50\u5185\u5bb9: \u7a7a\u9699\u5206\u5e03;<br \/>\n\u5bf9\u9f50\u9879\u76ee: \u5c45\u4e2d;<br \/>\n}<\/p>\n<p>.\u5f85\u529e\u4e8b\u9879 .\u64cd\u4f5c-\u533a\u5757{<br \/>\n\u663e\u793a: \u5f39\u6027;<br \/>\n\u5bf9\u9f50\u5185\u5bb9: \u5f39\u6027\u5f00\u59cb;<br \/>\n\u5bf9\u9f50\u9879\u76ee: \u5c45\u4e2d;<br \/>\n}<\/p>\n<p>.\u5f85\u529e\u4e8b\u9879 .\u64cd\u4f5c-\u533a\u5757 div{<br \/>\n\u8fb9\u8ddd: 0px 10px;<br \/>\n\u5149\u6807: \u6307\u9488;<br \/>\n}<\/p>\n<p>.\u5220\u9664-\u6309\u94ae{<br \/>\n\u989c\u8272: rgb(165, 2, 2);<br \/>\n\u5149\u6807: \u6307\u9488;<br \/>\n}<\/p>\n<p>.\u6a21\u6001-\u5bb9\u5668{<br \/>\n\u5bbd\u5ea6: 100%;<br \/>\n\u9ad8\u5ea6: 100vh;<br \/>\n\u4f4d\u7f6e: \u56fa\u5b9a;<br \/>\n\u9876\u90e8: 0;<br \/>\n\u5de6\u4fa7: 0;<br \/>\n\u80cc\u666f\u989c\u8272: rgba(0,0,0,0.7);<br \/>\n\u663e\u793a: \u5f39\u6027;<br \/>\n\u5bf9\u9f50\u5185\u5bb9: \u5c45\u4e2d;<br \/>\n\u5bf9\u9f50\u9879\u76ee: \u5c45\u4e2d;<br \/>\n}<\/p>\n<p>.\u6a21\u6001-\u5bb9\u5668 .\u6a21\u6001{<br \/>\n\u663e\u793a: \u5757;<br \/>\n\u5bbd\u5ea6: 70%;<br \/>\n\u9ad8\u5ea6: 70vh;<br \/>\n\u80cc\u666f\u989c\u8272: #fff;<br \/>\n\u8fb9\u6846\u534a\u5f84: 20px;<br \/>\n\u8fb9\u8ddd: 60px 15%;<br \/>\n}<\/p>\n<p>@media(max-width: 768px){<br \/>\n.\u6a21\u6001-\u5bb9\u5668 .\u6a21\u6001{<br \/>\n\u5bbd\u5ea6: 100%;<br \/>\n\u9ad8\u5ea6: 100vh;<br \/>\n\u8fb9\u8ddd: 0;<br \/>\n\u8fb9\u6846\u534a\u5f84: 0px;<br \/>\n}<br \/>\n}<\/p>\n<p>.\u6a21\u6001-\u5bb9\u5668 .\u6a21\u6001 .\u5934\u90e8{<br \/>\n\u5bbd\u5ea6: 100%;<br \/>\n\u9ad8\u5ea6: \u81ea\u52a8;<br \/>\n\u586b\u5145: 20px;<br \/>\n\u663e\u793a: \u5f39\u6027;<br \/>\n\u5bf9\u9f50\u5185\u5bb9: \u7a7a\u9699\u5206\u5e03;<br \/>\n\u5bf9\u9f50\u9879\u76ee: \u5c45\u4e2d;<br \/>\n}<\/p>\n<p>.\u6a21\u6001-\u5bb9\u5668 .\u6a21\u6001 .\u5934\u90e8 .\u66f4\u65b0-\u6587\u672c{<br \/>\n\u5b57\u4f53\u5927\u5c0f: 24px;<br \/>\n\u5b57\u4f53\u7c97\u7ec6: 600;<br \/>\n\u5bbd\u5ea6: 100%;<br \/>\n}<\/p>\n<p>.\u6a21\u6001-\u5bb9\u5668 .\u6a21\u6001 .\u5934\u90e8 .\u5173\u95ed-\u6309\u94ae{<br \/>\n\u989c\u8272: rgb(165, 2, 2);<br \/>\n\u5149\u6807: \u6307\u9488;<br \/>\n}<\/p>\n<\/details>\n<h2>\u7ec4\u4ef6\/ Header.js<\/h2>\n<details>Header.jsHeader.jsx<br \/>\nimport React, { useEffect, useState } from &#8216;react&#8217;<br \/>\nimport { Link } from &#8216;react-router-dom&#8217;<\/p>\n<p>import todoIcon from &#8216;..\/images\/TodoAppicon.png&#8217;<br \/>\nimport &#8216;bootstrap\/dist\/css\/bootstrap.css&#8217;<br \/>\nimport &#8216;..\/index.css&#8217;<\/p>\n<p>import {auth} from &#8216;..\/services\/firebase.config&#8217;<\/p>\n<p>export const Header = ({ currentUser }) =&gt; {<\/p>\n<p>const [year, setYear] = useState(null);<br \/>\nconst [date, setDate] = useState(null);<br \/>\nconst [month, setMonth] = useState(null);<br \/>\nconst [day, setDay] = useState(null);<\/p>\n<p>useEffect(() =&gt; {<br \/>\nconst currentDate = new Date();<br \/>\nconst currentYear = currentDate.getFullYear();<br \/>\nconst currentDateOfMonth = currentDate.getDate();<br \/>\nconst currentMonth = currentDate.toLocaleString(&#8216;ja-JP&#8217;, { month: &#8216;long&#8217; });<br \/>\nconst currentDay = currentDate.toLocaleDateString(&#8216;js-JP&#8217;, { weekday: &#8216;long&#8217; });<\/p>\n<p>setYear(currentYear);<br \/>\nsetDate(currentDateOfMonth);<br \/>\nsetMonth(currentMonth);<br \/>\nsetDay(currentDay);<br \/>\n}, [])<\/p>\n<p>const handleLogout = () =&gt; {<br \/>\nauth.signOut().then(() =&gt; {<br \/>\nwindow.location.reload();<br \/>\n});<br \/>\n}<\/p>\n<p>return (<\/p>\n<div>\n<div>\n<div><img decoding=\"async\" src=\"{todoIcon}\" alt=\"todoIcon\" \/><\/div>\n<div>\n<div>\u8fd8\u6709\u4efb\u52a1\u8981\u505a\uff1f<\/div>\n<div>\u505a\u4e2a\u5217\u8868\u5427\uff01<\/div>\n<\/div>\n<\/div>\n<div>\n<p>{!currentUser &amp;&amp; &lt;&gt;<br \/>\n\u6ce8\u518c<br \/>\n\u767b\u5f55<\/p>\n<div>{year}\u5e74<br \/>\n{month}<br \/>\n{date}\u65e5<br \/>\n{day}<\/div>\n<p>&lt;\/&gt;}<\/p>\n<p>{currentUser &amp;&amp;<\/p>\n<div>\n<h2>\u6b22\u8fce<\/h2>\n<h5>{currentUser}<\/h5>\n<p>&nbsp;<\/p>\n<div>{year}\u5e74<br \/>\n{month}<br \/>\n{date}\u65e5<br \/>\n{day}<\/div>\n<p><button>\u9000\u51fa<\/button><\/p>\n<\/div>\n<p>}<\/p>\n<\/div>\n<\/div>\n<p>)<br \/>\n}<\/p>\n<\/details>\n<h2>\u7ec4\u4ef6 \/ Home.js<\/h2>\n<details>Home.jsHome.jsx<br \/>\nimport React, { useState } from &#8216;react&#8217;<\/p>\n<p>import &#8216;..\/index.css&#8217;<\/p>\n<p>import { Header } from &#8216;.\/Header&#8217;<br \/>\nimport { Todos } from &#8216;.\/Todos&#8217;<br \/>\nimport { Modal } from &#8216;.\/Modal&#8217;<\/p>\n<p>import { auth, db } from &#8216;..\/services\/firebase.config&#8217;<br \/>\nimport { collection, addDoc } from &#8216;firebase\/firestore&#8217;<\/p>\n<p>export const Home = ({ currentUser, todos,deleteTodo,editTodoValue,editModal,updateTodoHandler }) =&gt; {<\/p>\n<p>const [todo, setTodo] = useState(&#8221;);<br \/>\nconst [todoError, setTodoError] = useState(&#8221;);<\/p>\n<p>const handleTodoSubmit = async (e) =&gt; {<br \/>\ne.preventDefault();<br \/>\nawait auth.onAuthStateChanged(user =&gt; {<br \/>\nif (user) {<br \/>\naddDoc(collection(db, &#8216;\u7528\u6237&#8217; + user.uid + &#8216;\u7684\u5f85\u529e\u4e8b\u9879&#8217;), {<br \/>\n\u5f85\u529e\u4e8b\u9879: todo,<br \/>\n\u7528\u6237ID: user.uid<br \/>\n}).then(setTodo(&#8221;)).catch(err =&gt; setTodoError(err.message))<br \/>\n}<br \/>\nelse {<br \/>\nconsole.log(&#8220;\u7528\u6237\u672a\u767b\u5f55&#8221;);<br \/>\n}<br \/>\n})<br \/>\n}<\/p>\n<p>return (<\/p>\n<div>\n<header><\/header>\n<div>\n<form autocomplete=\"off\">{currentUser &amp;&amp; &lt;&gt;<br \/>\n<input required=\"\" type=\"text\" placeholder=\"\u8f93\u5165\u5f85\u529e\u4e8b\u9879\" \/> setTodo(e.target.value)}<br \/>\nvalue={todo}<br \/>\n\/&gt;<\/p>\n<div><button type=\"submit\"><br \/>\n\u6dfb\u52a0<br \/>\n<\/button><\/div>\n<p>&lt;\/&gt;}<\/p>\n<p>{!currentUser &amp;&amp; &lt;&gt;<br \/>\n<input disabled=\"disabled\" required=\"\" type=\"text\" placeholder=\"\u8f93\u5165\u5f85\u529e\u4e8b\u9879\" \/><\/p>\n<div><button disabled=\"disabled\" type=\"submit\"><br \/>\n\u6dfb\u52a0<br \/>\n<\/button><\/div>\n<div>\u8bf7\u6ce8\u518c\u60a8\u7684\u8d26\u6237\u6216\u767b\u5f55\u4ee5\u4f7f\u7528\u5e94\u7528\u7a0b\u5e8f<\/div>\n<p>&lt;\/&gt;}<\/p>\n<\/form>\n<p>{todoError &amp;&amp;<\/p>\n<div><\/div>\n<p>}<\/p>\n<\/div>\n<p>{editTodoValue &amp;&amp; }<\/p>\n<\/div>\n<p>)<br \/>\n}<\/p>\n<\/details>\n<h2>\u7ec4\u4ef6 \/ IndividualTodo.js<\/h2>\n<details>IndividualTodo.jsIndividualTodo.jsx<br \/>\nimport React from &#8216;react&#8217;<\/p>\n<p>import {FiEdit} from &#8216;react-icons\/fi&#8217;<br \/>\nimport {FaTrashAlt} from &#8216;react-icons\/fa&#8217;<\/p>\n<p>export const IndividualTodo = ({ individualTodo,deleteTodo,editModal }) =&gt; {<\/p>\n<p>const handleDelete=()=&gt;{<br \/>\ndeleteTodo(individualTodo.id);<br \/>\n}<\/p>\n<p>const handleEditModal=()=&gt;{<br \/>\neditModal(individualTodo);<br \/>\n}<\/p>\n<p>return (<\/p>\n<div>\n<div>{individualTodo.Todo}<\/div>\n<div>\n<div><\/div>\n<div><\/div>\n<\/div>\n<\/div>\n<p>)<br \/>\n}<\/p>\n<\/details>\n<h2>\u7ec4\u4ef6 \/ \u767b\u5f55.js<\/h2>\n<details>Login.jsLogin.jsx<br \/>\nimport React, { useState } from &#8216;react&#8217;<br \/>\nimport { Link, useNavigate } from &#8216;react-router-dom&#8217;<\/p>\n<p>import { signInWithEmailAndPassword } from &#8216;firebase\/auth&#8217;;<br \/>\nimport { auth } from &#8216;..\/services\/firebase.config&#8217;<\/p>\n<p>export const Login = () =&gt; {<br \/>\nconst [email, setEmail] = useState(&#8221;);<br \/>\nconst [password, setPassword] = useState(&#8221;);<\/p>\n<p>const [loginError, setLoginError] = useState(&#8221;);<\/p>\n<p>const navigate = useNavigate();<\/p>\n<p>const handleLogin = async (e) =&gt; {<br \/>\ne.preventDefault();<br \/>\ntry {<br \/>\nawait signInWithEmailAndPassword(auth, email, password);<br \/>\nsetEmail(&#8221;);<br \/>\nsetPassword(&#8221;);<br \/>\nsetLoginError(&#8221;);<br \/>\nnavigate(&#8216;\/&#8217;);<br \/>\n} catch (error) {<br \/>\nsetLoginError(error.message);<br \/>\n}<br \/>\n};<\/p>\n<p>return (<\/p>\n<div>\n<h2>\u5728\u8fd9\u91cc\u767b\u5f55<\/h2>\n<p>&nbsp;<\/p>\n<form autocomplete=\"off\"><label>\u8f93\u5165\u90ae\u7bb1<\/label><br \/>\n<input required=\"\" type=\"email\" \/> setEmail(e.target.value)}<br \/>\nvalue={email}<br \/>\n\/&gt;<\/p>\n<p>&nbsp;<\/p>\n<p><label>\u8f93\u5165\u5bc6\u7801<\/label><br \/>\n<input required=\"\" type=\"password\" \/> setPassword(e.target.value)}<br \/>\nvalue={password}<br \/>\n\/&gt;<\/p>\n<p>&nbsp;<\/p>\n<p><button type=\"submit\"><br \/>\n\u767b\u5f55<br \/>\n<\/button><\/p>\n<\/form>\n<p>{loginError &amp;&amp;<\/p>\n<div>{loginError}<\/div>\n<p>}<\/p>\n<p>\u8fd8\u6ca1\u6709\u8d26\u6237? \u521b\u5efa\u4e00\u4e2a<br \/>\n\u8fd9\u91cc<\/p>\n<\/div>\n<p>)<br \/>\n}<\/p>\n<\/details>\n<h2>\u7ec4\u4ef6 \/ Modal.js<\/h2>\n<details>Modal.jsModal.jsx<br \/>\nimport React, { useState } from &#8216;react&#8217;<\/p>\n<p>import { FiXCircle } from &#8216;react-icons\/fi&#8217;<\/p>\n<p>import { doc, updateDoc } from &#8220;firebase\/firestore&#8221;;<br \/>\nimport { db, auth } from &#8216;..\/services\/firebase.config&#8217;<\/p>\n<p>export const Modal = ({ editTodoValue, editModal,updateTodoHandler }) =&gt; {<\/p>\n<p>const [editTodo, setEditTodo] = useState(editTodoValue.Todo);<\/p>\n<p>const handleClose = () =&gt; {<br \/>\neditModal(null)<br \/>\n}<\/p>\n<p>const handleEditTodoSubmit = async (e) =&gt; {<br \/>\ne.preventDefault();<br \/>\nhandleClose();<br \/>\nupdateTodoHandler(editTodo, editTodoValue.id);<br \/>\nawait auth.onAuthStateChanged(user =&gt; {<br \/>\nif (user) {<br \/>\nconst todoRef = doc(db, &#8216;todos of&#8217; + user.uid,editTodoValue.id);<br \/>\nupdateDoc(todoRef, {<br \/>\nTodo: editTodo<br \/>\n})<\/p>\n<p>}<br \/>\nelse {<br \/>\nconsole.log(&#8220;user is not signed&#8221;);<br \/>\n}<br \/>\n})<br \/>\n}<\/p>\n<p>return (<\/p>\n<div>\n<div>\n<div>\n<div>\u66f4\u65b0\u5f85\u529e\u4e8b\u9879<\/div>\n<div><\/div>\n<\/div>\n<div>\n<form autocomplete=\"off\"><input required=\"\" type=\"text\" value=\"{editTodo}\" placeholder=\"\u66f4\u65b0\u5f85\u529e\u4e8b\u9879\" \/>setEditTodo(e.target.value)}<br \/>\n\/&gt;&nbsp;<\/p>\n<p><button type=\"submit\"><br \/>\n\u66f4\u65b0<br \/>\n<\/button><\/p>\n<\/form>\n<\/div>\n<\/div>\n<\/div>\n<p>)<br \/>\n}<\/p>\n<\/details>\n<h2>\u7ec4\u4ef6 \/ NotFound.js<\/h2>\n<details>\u672a\u627e\u5230.jsNotFound.jsx<br \/>\nimport React from &#8216;react&#8217;<\/p>\n<p>export const NotFound = () =&gt; {<br \/>\nreturn (<\/p>\n<div>\u672a\u627e\u5230<\/div>\n<p>)<br \/>\n}<\/p>\n<\/details>\n<h2>\u7ec4\u4ef6 \/ \u6ce8\u518c.js<\/h2>\n<details>\u7b7e\u7f72.js\u7b7e\u7f72.jsx<br \/>\nimport React, { useState } from &#8216;react&#8217;;<br \/>\nimport { Link } from &#8216;react-router-dom&#8217;;<br \/>\nimport { useNavigate } from &#8216;react-router-dom&#8217;;<\/p>\n<p>import { createUserWithEmailAndPassword } from &#8216;firebase\/auth&#8217;;<br \/>\nimport { doc, setDoc } from &#8216;firebase\/firestore&#8217;;<br \/>\nimport { auth, db } from &#8216;..\/services\/firebase.config&#8217;;<\/p>\n<p>export const Signup = () =&gt; {<br \/>\nconst [userName, setUserName] = useState(&#8221;);<br \/>\nconst [email, setEmail] = useState(&#8221;);<br \/>\nconst [password, setPassword] = useState(&#8221;);<br \/>\nconst [registerError, setRegisterError] = useState(&#8221;);<br \/>\nconst navigate = useNavigate();<\/p>\n<p>const handleRegister = async (e) =&gt; {<br \/>\ne.preventDefault();<br \/>\ntry {<br \/>\nconst userCredential = await createUserWithEmailAndPassword(auth, email, password);<br \/>\nconst { uid } = userCredential.user;<br \/>\nconsole.log(userName, email, password, uid);<br \/>\nawait setDoc(doc(db, &#8216;users&#8217;, uid), {<br \/>\nuserName: userName,<br \/>\nEmail: email,<br \/>\nPassword: password,<br \/>\n});<br \/>\nsetUserName(&#8221;);<br \/>\nsetEmail(&#8221;);<br \/>\nsetPassword(&#8221;);<br \/>\nsetRegisterError(&#8221;);<br \/>\nnavigate(&#8216;\/login&#8217;);<br \/>\n} catch (error) {<br \/>\nsetRegisterError(error.message);<br \/>\n}<br \/>\n};<\/p>\n<p>return (<\/p>\n<div>\n<h2>\u73b0\u5728\u6ce8\u518c\uff01<\/h2>\n<p>&nbsp;<\/p>\n<form autocomplete=\"off\"><label>\u7528\u6237\u540d<\/label><br \/>\n<input required=\"\" type=\"text\" \/> setUserName(e.target.value)}<br \/>\nvalue={userName}<br \/>\n\/&gt;<\/p>\n<p>&nbsp;<\/p>\n<p><label>\u7535\u5b50\u90ae\u4ef6<\/label><br \/>\n<input required=\"\" type=\"email\" \/> setEmail(e.target.value)}<br \/>\nvalue={email}<br \/>\n\/&gt;<\/p>\n<p>&nbsp;<\/p>\n<p><label>\u5bc6\u7801<\/label><br \/>\n<input required=\"\" type=\"password\" \/> setPassword(e.target.value)}<br \/>\nvalue={password}<br \/>\n\/&gt;<\/p>\n<p>&nbsp;<\/p>\n<p><button type=\"submit\"><br \/>\n\u6ce8\u518c<br \/>\n<\/button><\/p>\n<\/form>\n<p>{registerError &amp;&amp; (<\/p>\n<div>{registerError}<\/div>\n<p>)}<\/p>\n<p>\u5df2\u7ecf\u62e5\u6709\u8d26\u6237\uff1f \u5728\u8fd9\u91cc\u767b\u5f55<\/p>\n<\/div>\n<p>);<br \/>\n};<\/p>\n<\/details>\n<h2>\u7ec4\u4ef6\/ Todos.js<\/h2>\n<details>Todos.jsTodos.jsx<br \/>\nimport React from &#8216;react&#8217;<br \/>\nimport { IndividualTodo } from &#8216;.\/IndividualTodo&#8217;<\/p>\n<p>export const Todos = ({todos,deleteTodo,editModal}) =&gt; {<br \/>\nreturn todos.map((individualTodo)=&gt;{<br \/>\nreturn (<\/p>\n<p>)<br \/>\n})<br \/>\n}<\/p>\n<\/details>\n<h2>\u670d\u52a1 \/ firebase.config.js<\/h2>\n<details>firebase.config.jsfirebase.config.js<br \/>\nimport { initializeApp } from &#8216;firebase\/app&#8217;<br \/>\nimport { getAuth } from &#8216;firebase\/auth&#8217;<br \/>\nimport { getFirestore } from &#8216;firebase\/firestore&#8217;<\/p>\n<p>const firebaseConfig = {<br \/>\napiKey: &#8220;\u4f60\u7684\u914d\u7f6e\u4ee3\u7801&#8221;,<br \/>\nauthDomain: &#8220;\u4f60\u7684\u914d\u7f6e\u4ee3\u7801&#8221;,<br \/>\nprojectId: &#8220;\u4f60\u7684\u914d\u7f6e\u4ee3\u7801&#8221;,<br \/>\nstorageBucket: &#8220;\u4f60\u7684\u914d\u7f6e\u4ee3\u7801&#8221;,<br \/>\nmessagingSenderId: &#8220;\u4f60\u7684\u914d\u7f6e\u4ee3\u7801&#8221;,<br \/>\nappId: &#8220;\u4f60\u7684\u914d\u7f6e\u4ee3\u7801&#8221;,<br \/>\nmeasurementId: &#8220;\u4f60\u7684\u914d\u7f6e\u4ee3\u7801&#8221;<br \/>\n};<\/p>\n<p>const app = initializeApp(firebaseConfig)<br \/>\nconst auth = getAuth(app)<br \/>\nconst db = getFirestore(app)<\/p>\n<p>export { auth, db }<\/p>\n<\/details>\n<h1>\u7ed3\u675f<\/h1>\n<p>\u901a\u8fc7\u5236\u4f5cTodo\u5e94\u7528\u5e76\u6dfb\u52a0\u5404\u79cd\u529f\u80fd\uff0c\u6211\u80fd\u591f\u7406\u89e3React\u548cFirestore\u6570\u636e\u5e93\u64cd\u4f5c\u7684\u5404\u79cd\u521b\u5efa\u65b9\u6cd5\u3002<\/p>\n<p>\u60f3\u8981\u5236\u4f5c\u60f3\u8c61\u4e2d\u7684\u4e8b\u7269\uff0c\u9700\u8981\u76f8\u5e94\u7684\u5148\u51b3\u77e5\u8bc6\uff0c\u6240\u4ee5\u5b66\u4e60\u662f\u4e0d\u53ef\u6216\u7f3a\u7684\u3002<\/p>\n<p>\u6211\u4e4b\u524d\u5236\u4f5c\u4e86\u4e00\u4e2a\u5b66\u98df\u552e\u7f44\u4fe1\u606f\u786e\u8ba4\u5e94\u7528\u7a0b\u5e8f\uff0c\u540d\u4e3a\u201c\u968f\u65f6\u68c0\u67e5\u5348\u9910\u201d\uff0c\u4f46\u5728\u5b66\u4e60React\u7684\u8fc7\u7a0b\u4e2d\uff0c\u6211\u610f\u8bc6\u5230\u4e0e\u4ec5\u4f7f\u7528JavaScript\u76f8\u6bd4\uff0c\u4f7f\u7528React\u53ef\u4ee5\u66f4\u5bb9\u6613\u5730\u6309\u529f\u80fd\u8fdb\u884c\u521b\u5efa\u5e76\u8fdb\u884c\u7ba1\u7406\u3002\u56e0\u6b64\uff0c\u6211\u5e0c\u671b\u4eca\u540e\u80fd\u4f7f\u7528React\u8fdb\u884c\u5236\u4f5c\u3002<\/p>\n<p>\u5404\u4f4d\uff0c\u5728\u73b0\u4ee3(2023\/05\/22)\u8fd9\u4e2a\u65f6\u4ee3\uff0c\u6709\u8bb8\u591a\u4fe1\u606f\u53ef\u4ee5\u4f9b\u60a8\u53c2\u8003\uff0c\u8bf7\u60a8\u5c1d\u8bd5\u81ea\u884c\u67e5\u8be2\u6216\u54a8\u8be2\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u9996\u5148 \u8fd9\u6b21\u4f5c\u4e3a\u5b66\u4e60React\u7684\u7b2c\u4e00\u6b65\uff0c\u6211\u5c1d\u8bd5\u521b\u5efa\u4e86\u4e00\u4e2a&#8221;Todo\u5e94\u7528&#8221;\u3002\u6211\u4f7f\u7528\u4e86\u4e24\u5e74\u524d [&hellip;]<\/p>\n","protected":false},"author":11,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-38187","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v21.5 (Yoast SEO v21.5) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>\u900f\u904e\u958b\u767c2023\u5e74\u5ea6\u7684\u3010React x Firebase\u3011Todo\u61c9\u7528\u7a0b\u5f0f\uff0c\u4f86\u5b78\u7fd2 - Blog - Silicon Cloud<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.silicloud.com\/zh\/blog\/\u900f\u904e\u958b\u767c2023\u5e74\u5ea6\u7684\u3010react-x-firebase\u3011todo\u61c9\u7528\u7a0b\u5f0f\uff0c\u4f86\u5b78\u7fd2\u3002\/\" \/>\n<meta property=\"og:locale\" content=\"zh_CN\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"\u900f\u904e\u958b\u767c2023\u5e74\u5ea6\u7684\u3010React x Firebase\u3011Todo\u61c9\u7528\u7a0b\u5f0f\uff0c\u4f86\u5b78\u7fd2\" \/>\n<meta property=\"og:description\" content=\"\u9996\u5148 \u8fd9\u6b21\u4f5c\u4e3a\u5b66\u4e60React\u7684\u7b2c\u4e00\u6b65\uff0c\u6211\u5c1d\u8bd5\u521b\u5efa\u4e86\u4e00\u4e2a&#8221;Todo\u5e94\u7528&#8221;\u3002\u6211\u4f7f\u7528\u4e86\u4e24\u5e74\u524d [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.silicloud.com\/zh\/blog\/\u900f\u904e\u958b\u767c2023\u5e74\u5ea6\u7684\u3010react-x-firebase\u3011todo\u61c9\u7528\u7a0b\u5f0f\uff0c\u4f86\u5b78\u7fd2\u3002\/\" \/>\n<meta property=\"og:site_name\" content=\"Blog - Silicon Cloud\" \/>\n<meta property=\"article:published_time\" content=\"2023-02-23T14:26:07+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-05-03T16:25:42+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/cdn.silicloud.com\/blog-img\/blog\/img\/657d332137434c4406c64849\/6-0.png\" \/>\n<meta name=\"author\" content=\"\u65b0, \u97f5\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"\u4f5c\u8005\" \/>\n\t<meta name=\"twitter:data1\" content=\"\u65b0, \u97f5\" \/>\n\t<meta name=\"twitter:label2\" content=\"\u9884\u8ba1\u9605\u8bfb\u65f6\u95f4\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 \u5206\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/%e9%80%8f%e9%81%8e%e9%96%8b%e7%99%bc2023%e5%b9%b4%e5%ba%a6%e7%9a%84%e3%80%90react-x-firebase%e3%80%91todo%e6%87%89%e7%94%a8%e7%a8%8b%e5%bc%8f%ef%bc%8c%e4%be%86%e5%ad%b8%e7%bf%92%e3%80%82\/\",\"url\":\"https:\/\/www.silicloud.com\/zh\/blog\/%e9%80%8f%e9%81%8e%e9%96%8b%e7%99%bc2023%e5%b9%b4%e5%ba%a6%e7%9a%84%e3%80%90react-x-firebase%e3%80%91todo%e6%87%89%e7%94%a8%e7%a8%8b%e5%bc%8f%ef%bc%8c%e4%be%86%e5%ad%b8%e7%bf%92%e3%80%82\/\",\"name\":\"\u900f\u904e\u958b\u767c2023\u5e74\u5ea6\u7684\u3010React x Firebase\u3011Todo\u61c9\u7528\u7a0b\u5f0f\uff0c\u4f86\u5b78\u7fd2 - Blog - Silicon Cloud\",\"isPartOf\":{\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/#website\"},\"datePublished\":\"2023-02-23T14:26:07+00:00\",\"dateModified\":\"2024-05-03T16:25:42+00:00\",\"author\":{\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/#\/schema\/person\/4ba4019495123db3038fd0809e6959c9\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/%e9%80%8f%e9%81%8e%e9%96%8b%e7%99%bc2023%e5%b9%b4%e5%ba%a6%e7%9a%84%e3%80%90react-x-firebase%e3%80%91todo%e6%87%89%e7%94%a8%e7%a8%8b%e5%bc%8f%ef%bc%8c%e4%be%86%e5%ad%b8%e7%bf%92%e3%80%82\/#breadcrumb\"},\"inLanguage\":\"zh-Hans\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.silicloud.com\/zh\/blog\/%e9%80%8f%e9%81%8e%e9%96%8b%e7%99%bc2023%e5%b9%b4%e5%ba%a6%e7%9a%84%e3%80%90react-x-firebase%e3%80%91todo%e6%87%89%e7%94%a8%e7%a8%8b%e5%bc%8f%ef%bc%8c%e4%be%86%e5%ad%b8%e7%bf%92%e3%80%82\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/%e9%80%8f%e9%81%8e%e9%96%8b%e7%99%bc2023%e5%b9%b4%e5%ba%a6%e7%9a%84%e3%80%90react-x-firebase%e3%80%91todo%e6%87%89%e7%94%a8%e7%a8%8b%e5%bc%8f%ef%bc%8c%e4%be%86%e5%ad%b8%e7%bf%92%e3%80%82\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"\u9996\u9875\",\"item\":\"https:\/\/www.silicloud.com\/zh\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"\u900f\u904e\u958b\u767c2023\u5e74\u5ea6\u7684\u3010React x Firebase\u3011Todo\u61c9\u7528\u7a0b\u5f0f\uff0c\u4f86\u5b78\u7fd2\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/#website\",\"url\":\"https:\/\/www.silicloud.com\/zh\/blog\/\",\"name\":\"Blog - Silicon Cloud\",\"description\":\"\",\"inLanguage\":\"zh-Hans\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/#\/schema\/person\/4ba4019495123db3038fd0809e6959c9\",\"name\":\"\u65b0, \u97f5\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"zh-Hans\",\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/d484b6c6e4ae82e8a9efea989e1d2af46d9b6ef128101e63b18f559fca0ae627?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/d484b6c6e4ae82e8a9efea989e1d2af46d9b6ef128101e63b18f559fca0ae627?s=96&d=mm&r=g\",\"caption\":\"\u65b0, \u97f5\"},\"url\":\"https:\/\/www.silicloud.com\/zh\/blog\/author\/yunxin\/\"},{\"@type\":\"ImageObject\",\"inLanguage\":\"zh-Hans\",\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/%e9%80%8f%e9%81%8e%e9%96%8b%e7%99%bc2023%e5%b9%b4%e5%ba%a6%e7%9a%84%e3%80%90react-x-firebase%e3%80%91todo%e6%87%89%e7%94%a8%e7%a8%8b%e5%bc%8f%ef%bc%8c%e4%be%86%e5%ad%b8%e7%bf%92%e3%80%82\/#local-main-organization-logo\",\"url\":\"\",\"contentUrl\":\"\",\"caption\":\"Blog - Silicon Cloud\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"\u900f\u904e\u958b\u767c2023\u5e74\u5ea6\u7684\u3010React x Firebase\u3011Todo\u61c9\u7528\u7a0b\u5f0f\uff0c\u4f86\u5b78\u7fd2 - Blog - Silicon Cloud","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.silicloud.com\/zh\/blog\/\u900f\u904e\u958b\u767c2023\u5e74\u5ea6\u7684\u3010react-x-firebase\u3011todo\u61c9\u7528\u7a0b\u5f0f\uff0c\u4f86\u5b78\u7fd2\u3002\/","og_locale":"zh_CN","og_type":"article","og_title":"\u900f\u904e\u958b\u767c2023\u5e74\u5ea6\u7684\u3010React x Firebase\u3011Todo\u61c9\u7528\u7a0b\u5f0f\uff0c\u4f86\u5b78\u7fd2","og_description":"\u9996\u5148 \u8fd9\u6b21\u4f5c\u4e3a\u5b66\u4e60React\u7684\u7b2c\u4e00\u6b65\uff0c\u6211\u5c1d\u8bd5\u521b\u5efa\u4e86\u4e00\u4e2a&#8221;Todo\u5e94\u7528&#8221;\u3002\u6211\u4f7f\u7528\u4e86\u4e24\u5e74\u524d [&hellip;]","og_url":"https:\/\/www.silicloud.com\/zh\/blog\/\u900f\u904e\u958b\u767c2023\u5e74\u5ea6\u7684\u3010react-x-firebase\u3011todo\u61c9\u7528\u7a0b\u5f0f\uff0c\u4f86\u5b78\u7fd2\u3002\/","og_site_name":"Blog - Silicon Cloud","article_published_time":"2023-02-23T14:26:07+00:00","article_modified_time":"2024-05-03T16:25:42+00:00","og_image":[{"url":"https:\/\/cdn.silicloud.com\/blog-img\/blog\/img\/657d332137434c4406c64849\/6-0.png"}],"author":"\u65b0, \u97f5","twitter_card":"summary_large_image","twitter_misc":{"\u4f5c\u8005":"\u65b0, \u97f5","\u9884\u8ba1\u9605\u8bfb\u65f6\u95f4":"6 \u5206"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.silicloud.com\/zh\/blog\/%e9%80%8f%e9%81%8e%e9%96%8b%e7%99%bc2023%e5%b9%b4%e5%ba%a6%e7%9a%84%e3%80%90react-x-firebase%e3%80%91todo%e6%87%89%e7%94%a8%e7%a8%8b%e5%bc%8f%ef%bc%8c%e4%be%86%e5%ad%b8%e7%bf%92%e3%80%82\/","url":"https:\/\/www.silicloud.com\/zh\/blog\/%e9%80%8f%e9%81%8e%e9%96%8b%e7%99%bc2023%e5%b9%b4%e5%ba%a6%e7%9a%84%e3%80%90react-x-firebase%e3%80%91todo%e6%87%89%e7%94%a8%e7%a8%8b%e5%bc%8f%ef%bc%8c%e4%be%86%e5%ad%b8%e7%bf%92%e3%80%82\/","name":"\u900f\u904e\u958b\u767c2023\u5e74\u5ea6\u7684\u3010React x Firebase\u3011Todo\u61c9\u7528\u7a0b\u5f0f\uff0c\u4f86\u5b78\u7fd2 - Blog - Silicon Cloud","isPartOf":{"@id":"https:\/\/www.silicloud.com\/zh\/blog\/#website"},"datePublished":"2023-02-23T14:26:07+00:00","dateModified":"2024-05-03T16:25:42+00:00","author":{"@id":"https:\/\/www.silicloud.com\/zh\/blog\/#\/schema\/person\/4ba4019495123db3038fd0809e6959c9"},"breadcrumb":{"@id":"https:\/\/www.silicloud.com\/zh\/blog\/%e9%80%8f%e9%81%8e%e9%96%8b%e7%99%bc2023%e5%b9%b4%e5%ba%a6%e7%9a%84%e3%80%90react-x-firebase%e3%80%91todo%e6%87%89%e7%94%a8%e7%a8%8b%e5%bc%8f%ef%bc%8c%e4%be%86%e5%ad%b8%e7%bf%92%e3%80%82\/#breadcrumb"},"inLanguage":"zh-Hans","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.silicloud.com\/zh\/blog\/%e9%80%8f%e9%81%8e%e9%96%8b%e7%99%bc2023%e5%b9%b4%e5%ba%a6%e7%9a%84%e3%80%90react-x-firebase%e3%80%91todo%e6%87%89%e7%94%a8%e7%a8%8b%e5%bc%8f%ef%bc%8c%e4%be%86%e5%ad%b8%e7%bf%92%e3%80%82\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.silicloud.com\/zh\/blog\/%e9%80%8f%e9%81%8e%e9%96%8b%e7%99%bc2023%e5%b9%b4%e5%ba%a6%e7%9a%84%e3%80%90react-x-firebase%e3%80%91todo%e6%87%89%e7%94%a8%e7%a8%8b%e5%bc%8f%ef%bc%8c%e4%be%86%e5%ad%b8%e7%bf%92%e3%80%82\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"\u9996\u9875","item":"https:\/\/www.silicloud.com\/zh\/blog\/"},{"@type":"ListItem","position":2,"name":"\u900f\u904e\u958b\u767c2023\u5e74\u5ea6\u7684\u3010React x Firebase\u3011Todo\u61c9\u7528\u7a0b\u5f0f\uff0c\u4f86\u5b78\u7fd2"}]},{"@type":"WebSite","@id":"https:\/\/www.silicloud.com\/zh\/blog\/#website","url":"https:\/\/www.silicloud.com\/zh\/blog\/","name":"Blog - Silicon Cloud","description":"","inLanguage":"zh-Hans"},{"@type":"Person","@id":"https:\/\/www.silicloud.com\/zh\/blog\/#\/schema\/person\/4ba4019495123db3038fd0809e6959c9","name":"\u65b0, \u97f5","image":{"@type":"ImageObject","inLanguage":"zh-Hans","@id":"https:\/\/www.silicloud.com\/zh\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/d484b6c6e4ae82e8a9efea989e1d2af46d9b6ef128101e63b18f559fca0ae627?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/d484b6c6e4ae82e8a9efea989e1d2af46d9b6ef128101e63b18f559fca0ae627?s=96&d=mm&r=g","caption":"\u65b0, \u97f5"},"url":"https:\/\/www.silicloud.com\/zh\/blog\/author\/yunxin\/"},{"@type":"ImageObject","inLanguage":"zh-Hans","@id":"https:\/\/www.silicloud.com\/zh\/blog\/%e9%80%8f%e9%81%8e%e9%96%8b%e7%99%bc2023%e5%b9%b4%e5%ba%a6%e7%9a%84%e3%80%90react-x-firebase%e3%80%91todo%e6%87%89%e7%94%a8%e7%a8%8b%e5%bc%8f%ef%bc%8c%e4%be%86%e5%ad%b8%e7%bf%92%e3%80%82\/#local-main-organization-logo","url":"","contentUrl":"","caption":"Blog - Silicon Cloud"}]}},"_links":{"self":[{"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/posts\/38187","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/users\/11"}],"replies":[{"embeddable":true,"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/comments?post=38187"}],"version-history":[{"count":2,"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/posts\/38187\/revisions"}],"predecessor-version":[{"id":95004,"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/posts\/38187\/revisions\/95004"}],"wp:attachment":[{"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/media?parent=38187"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/categories?post=38187"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/tags?post=38187"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}