React项目中拍照上传至MongoDB存储及展示的实现问题
Hey there! Let's walk through how to get that camera-captured photo into MongoDB and displayed on your Twitter-inspired app. I’ve built similar workflows before, so here’s a step-by-step solution tailored to your setup:
First, let’s make sure you’re capturing the photo data in a format that’s easy to upload. Most React camera libraries (like react-camera-pro) return a Blob when you take a photo—we’ll convert this to a File object to work with standard upload tools.
Here’s updated code for your camera component, including preview and upload preparation:
import { Camera } from 'react-camera-pro'; import { useState } from 'react'; function PostCreator() { const [cameraRef, setCameraRef] = useState(null); const [capturedImage, setCapturedImage] = useState(null); const takePhoto = async () => { if (!cameraRef) return; // Capture photo as a Blob const photoBlob = await cameraRef.takePhoto(); // Convert Blob to File with a unique filename const imageFile = new File( [photoBlob], `post-photo-${Date.now()}.jpg`, { type: 'image/jpeg' } ); setCapturedImage(imageFile); }; return ( <div className="post-creator"> <Camera ref={setCameraRef} /> <button onClick={takePhoto}>Snap Photo</button> {/* Preview the captured image */} {capturedImage && ( <img src={URL.createObjectURL(capturedImage)} alt="Captured preview" style={{ maxWidth: '300px', marginTop: '1rem' }} /> )} <button onClick={handleUpload} disabled={!capturedImage}> Post with Photo </button> </div> ); }
We’ll use Node.js + Express (a common pairing with React) and Mongoose for MongoDB interactions. We’ll also use multer to handle file uploads.
First, install dependencies:
npm install express multer mongoose cors
2.1 Create a MongoDB Post Model
Define a schema to store your post content and image URL (we’ll store images locally first, then reference their URLs in MongoDB):
// models/Post.js const mongoose = require('mongoose'); const postSchema = new mongoose.Schema({ textContent: String, imageUrl: String, // Stores the public URL of the uploaded image createdAt: { type: Date, default: Date.now } }); module.exports = mongoose.model('Post', postSchema);
2.2 Set Up the Upload Endpoint
Configure multer to save images to a public/uploads folder, then create an API route to save post data to MongoDB:
// server.js const express = require('express'); const mongoose = require('mongoose'); const multer = require('multer'); const cors = require('cors'); const Post = require('./models/Post'); const fs = require('fs'); const app = express(); app.use(cors()); app.use(express.json()); // Serve uploaded images publicly app.use('/uploads', express.static('public/uploads')); // Create uploads folder if it doesn't exist fs.mkdirSync('public/uploads', { recursive: true }); // Configure multer for file storage const storage = multer.diskStorage({ destination: (req, file, cb) => cb(null, 'public/uploads/'), filename: (req, file, cb) => { // Generate unique filename to avoid conflicts const uniqueName = `${Date.now()}-${Math.round(Math.random() * 1e9)}.jpg`; cb(null, uniqueName); } }); const upload = multer({ storage }); // Connect to MongoDB mongoose.connect('mongodb://localhost:27017/twitter-clone') .then(() => console.log('Connected to MongoDB')) .catch(err => console.error('MongoDB connection error:', err)); // API route to create a post with image app.post('/api/posts', upload.single('image'), async (req, res) => { try { const { textContent } = req.body; const imageUrl = `/uploads/${req.file.filename}`; // Relative URL for MongoDB const newPost = new Post({ textContent, imageUrl }); await newPost.save(); res.status(201).json(newPost); } catch (err) { res.status(500).json({ message: 'Failed to create post' }); } }); // API route to fetch all posts app.get('/api/posts', async (req, res) => { try { const posts = await Post.find().sort({ createdAt: -1 }); res.json(posts); } catch (err) { res.status(500).json({ message: 'Failed to fetch posts' }); } }); app.listen(5000, () => console.log('Server running on port 5000'));
Add the handleUpload function to your PostCreator component to send the image and post data to your backend:
// Inside PostCreator component const handleUpload = async () => { if (!capturedImage) return; const formData = new FormData(); formData.append('image', capturedImage); formData.append('textContent', 'My new post with a photo!'); // Replace with user input try { const response = await fetch('http://localhost:5000/api/posts', { method: 'POST', body: formData }); if (response.ok) { const newPost = await response.json(); console.log('Post created successfully:', newPost); // Reset state or refresh post list here setCapturedImage(null); } else { throw new Error('Upload failed'); } } catch (err) { console.error('Error uploading post:', err); } };
Create a component to fetch and render posts from MongoDB:
import { useState, useEffect } from 'react'; function PostFeed() { const [posts, setPosts] = useState([]); useEffect(() => { const fetchPosts = async () => { try { const response = await fetch('http://localhost:5000/api/posts'); const data = await response.json(); setPosts(data); } catch (err) { console.error('Error fetching posts:', err); } }; fetchPosts(); }, []); return ( <div className="post-feed"> {posts.map(post => ( <div key={post._id} className="post-card"> <p>{post.textContent}</p> {post.imageUrl && ( <img src={`http://localhost:5000${post.imageUrl}`} alt="Post image" style={{ maxWidth: '100%', borderRadius: '8px' }} /> )} <small>{new Date(post.createdAt).toLocaleString()}</small> </div> ))} </div> ); } export default PostFeed;
For a real-world app, avoid storing images locally—use a cloud service like Cloudinary or AWS S3 instead. You’d modify the backend to upload the image to the cloud, then store the cloud-provided URL in MongoDB (the frontend code stays almost identical).
内容的提问来源于stack exchange,提问作者Zazz

