You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React新手求助:如何整合Firebase与reactstrap搭建冰箱物品管理应用

Hey there! 作为React新手能想到做这个实用的练手项目真的很棒,我来给你梳理下整合的核心步骤,帮你把现有部分串起来~

核心整合步骤指引

1. 配置Firebase并封装API层

首先确保你已经在React项目里安装了Firebase依赖:

npm install firebase

然后在项目里创建一个firebase.js文件,初始化Firebase(替换成你自己的项目配置):

import { initializeApp } from "firebase/app";
import { getFirestore } from "firebase/firestore";
import { getStorage } from "firebase/storage"; // 存图片需要用到Storage

const firebaseConfig = {
  apiKey: "YOUR_API_KEY",
  authDomain: "YOUR_AUTH_DOMAIN",
  projectId: "YOUR_PROJECT_ID",
  storageBucket: "YOUR_STORAGE_BUCKET",
  messagingSenderId: "YOUR_SENDER_ID",
  appId: "YOUR_APP_ID"
};

const app = initializeApp(firebaseConfig);
export const db = getFirestore(app);
export const storage = getStorage(app);

接下来封装一个处理物品操作的API文件,比如fridgeItemsApi.js,先实现添加物品的逻辑:

import { db, storage } from './firebase';
import { collection, addDoc } from "firebase/firestore";
import { ref, uploadBytes, getDownloadURL } from "firebase/storage";

// 添加物品到Firestore,同时上传图片到Storage
export const addFridgeItem = async (itemData) => {
  let imageUrl = '';
  // 如果有上传图片,先传到Storage拿到链接
  if (itemData.image) {
    const storageRef = ref(storage, `fridge-items/${Date.now()}-${itemData.image.name}`);
    await uploadBytes(storageRef, itemData.image);
    imageUrl = await getDownloadURL(storageRef);
  }

  // 将物品数据(含图片链接)写入Firestore集合
  await addDoc(collection(db, "fridgeItems"), {
    ...itemData,
    image: imageUrl,
    createdAt: new Date()
  });
};

2. 关联reactstrap表单与Firebase API

你已经用reactstrap搭了UI,现在把表单的提交事件和上面的API绑定起来。示例表单组件:

import { useState } from 'react';
import { Form, FormGroup, Label, Input, Button } from 'reactstrap';
import { addFridgeItem } from './fridgeItemsApi';

const ItemForm = () => {
  const [formData, setFormData] = useState({
    name: '',
    description: '',
    purchaseDate: '',
    location: '冰箱', // 默认选中冰箱
    image: null
  });

  const handleInputChange = (e) => {
    const { name, value, type, files } = e.target;
    setFormData(prev => ({
      ...prev,
      [name]: type === 'file' ? files[0] : value
    }));
  };

  const handleSubmit = async (e) => {
    e.preventDefault();
    try {
      await addFridgeItem(formData);
      // 提交成功后重置表单
      setFormData({
        name: '',
        description: '',
        purchaseDate: '',
        location: '冰箱',
        image: null
      });
      alert('物品添加成功!');
    } catch (error) {
      console.error('添加失败:', error);
      alert('添加出错,请重试');
    }
  };

  return (
    <Form onSubmit={handleSubmit} className="mb-5">
      <FormGroup>
        <Label for="itemName">物品名称</Label>
        <Input
          type="text"
          name="name"
          id="itemName"
          value={formData.name}
          onChange={handleInputChange}
          required
        />
      </FormGroup>
      <FormGroup>
        <Label for="itemDescription">物品描述</Label>
        <Input
          type="textarea"
          name="description"
          id="itemDescription"
          value={formData.description}
          onChange={handleInputChange}
        />
      </FormGroup>
      <FormGroup>
        <Label for="purchaseDate">购买日期</Label>
        <Input
          type="date"
          name="purchaseDate"
          id="purchaseDate"
          value={formData.purchaseDate}
          onChange={handleInputChange}
          required
        />
      </FormGroup>
      <FormGroup>
        <Label for="location">存放位置</Label>
        <Input
          type="select"
          name="location"
          id="location"
          value={formData.location}
          onChange={handleInputChange}
        >
          <option value="冰箱">冰箱</option>
          <option value="冰柜">冰柜</option>
        </Input>
      </FormGroup>
      <FormGroup>
        <Label for="itemImage">物品图片</Label>
        <Input
          type="file"
          name="image"
          id="itemImage"
          accept="image/*"
          onChange={handleInputChange}
        />
      </FormGroup>
      <Button type="submit" color="primary">添加物品</Button>
    </Form>
  );
};

export default ItemForm;

3. 从Firebase拉取数据并展示

创建一个展示组件,用Firebase的onSnapshot实现实时更新物品列表:

import { useState, useEffect } from 'react';
import { db } from './firebase';
import { collection, query, where, onSnapshot } from "firebase/firestore";
import { Card, CardImg, CardBody, CardTitle, CardText, Row, Col } from 'reactstrap';

const ItemsDisplay = () => {
  const [fridgeItems, setFridgeItems] = useState([]);
  const [freezerItems, setFreezerItems] = useState([]);

  useEffect(() => {
    // 监听冰箱物品的实时变化
    const fridgeQuery = query(collection(db, "fridgeItems"), where("location", "==", "冰箱"));
    const fridgeUnsubscribe = onSnapshot(fridgeQuery, (snapshot) => {
      const items = snapshot.docs.map(doc => ({
        id: doc.id,
        ...doc.data()
      }));
      setFridgeItems(items);
    });

    // 监听冰柜物品的实时变化
    const freezerQuery = query(collection(db, "fridgeItems"), where("location", "==", "冰柜"));
    const freezerUnsubscribe = onSnapshot(freezerQuery, (snapshot) => {
      const items = snapshot.docs.map(doc => ({
        id: doc.id,
        ...doc.data()
      }));
      setFreezerItems(items);
    });

    // 组件卸载时取消监听
    return () => {
      fridgeUnsubscribe();
      freezerUnsubscribe();
    };
  }, []);

  return (
    <div>
      <h2 className="mb-3">冰箱物品</h2>
      <Row>
        {fridgeItems.map(item => (
          <Col md={4} key={item.id} className="mb-4">
            <Card>
              {item.image && <CardImg top src={item.image} alt={item.name} />}
              <CardBody>
                <CardTitle tag="h5">{item.name}</CardTitle>
                <CardText>{item.description}</CardText>
                <CardText className="text-muted">购买日期: {item.purchaseDate}</CardText>
              </CardBody>
            </Card>
          </Col>
        ))}
      </Row>

      <h2 className="mt-5 mb-3">冰柜物品</h2>
      <Row>
        {freezerItems.map(item => (
          <Col md={4} key={item.id} className="mb-4">
            <Card>
              {item.image && <CardImg top src={item.image} alt={item.name} />}
              <CardBody>
                <CardTitle tag="h5">{item.name}</CardTitle>
                <CardText>{item.description}</CardText>
                <CardText className="text-muted">购买日期: {item.purchaseDate}</CardText>
              </CardBody>
            </Card>
          </Col>
        ))}
      </Row>
    </div>
  );
};

export default ItemsDisplay;

4. 整合所有组件到主页面

最后在App.js里把表单和展示组件组合起来:

import { Container } from 'reactstrap';
import ItemForm from './ItemForm';
import ItemsDisplay from './ItemsDisplay';

function App() {
  return (
    <Container className="mt-4">
      <h1 className="mb-4">我的冰箱/冰柜物品管理</h1>
      <ItemForm />
      <ItemsDisplay />
    </Container>
  );
}

export default App;

类似项目扩展思路

这个项目是典型的React+Firebase CRUD+文件存储应用,新手可以沿着这个方向逐步扩展:

  • 添加物品编辑/删除功能(用Firebase的updateDoc和deleteDoc)
  • 过期提醒(根据购买日期计算并标记即将过期的物品)
  • 搜索过滤功能(用Firebase的查询条件实现按名称/分类搜索)
  • 物品分类标签(比如添加“蔬菜”“肉类”等分类字段)

这些功能都是在现有基础上叠加,非常适合新手逐步打磨技能~

内容的提问来源于stack exchange,提问作者user1568811

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:29:06