在React应用中设置正确的MongoDB实现

时间:2018-10-18 17:57:36

标签: reactjs mongodb mern

所以,目前我正在研究React React(MERN)应用程序,这是一个简单的待办事项列表,可以创建,删除和编辑待办事项。我将发布一些代码,但您也可以在GitHub上查看完整代码:https://github.com/Wonderio619/magisale-internship-todo

下一个任务是将我的应用程序连接到MongoDB。我有一些“样板”代码-我与MongoDB建立了连接,还拥有Express路由器,其路由类似于获取所有待办事项列表,将待办事项发送到数据库,更新具有ID的待办事项,获得具有ID的待办事项:

const express = require("express");
const router = express.Router();
let Todo = require('../models/model')

// get all todo list with id
router.get('/', function (req, res) {
  Todo.find()
    .then((todos) => res.json(todos))
    .catch((error) => res.send(error))
})

// send todo to database
router.post('/', function (req, res) {
  let todo = new Todo();
  todo.titleText = req.body.title;
  todo.todoText = req.body.body;

  todo.save(function (err) {
    if (err)
      res.send(err);
    res.send('Todo successfully added!');
  });
})

// get todo with id
router.get('/:todoId', function (req, res) {
  Todo.findById(req.params.todoId)
    .then(foundTodo => res.json(foundTodo))
    .catch(error => res.send(error));
})

// updates todo with id
router.put('/:todoId', function (req, res) {
  Todo.findOneAndUpdate({ _id: req.params.todoId }, req.body, { new: true })
    .then((todo) => res.json(todo))
    .catch((error) => res.send(error))
})

// deletes todo with id
router.delete('/:todoId', function (req, res) {
  Todo.remove({ _id: req.params.todoId })
    .then(() => res.json({ message: 'todo is deleted' }))
    .catch((error) => res.send(error))
})

module.exports = router;

从todo应用程序调用相应方法时使用的这些路由:

import React, { Component } from 'react';
import './ToDo.css';
import Logo from './assets/logo.png';
import ToDoItem from './components/ToDoItem';
import AppBar from './components/AppBar';
import Popover from './components/Popover';
import { connect } from 'react-redux';

class ToDo extends Component {
  constructor(props) {
    super(props);
    this.state = {
      list: [],
      title: '',
      todo: '',
    };
  };

  componentDidMount = () => {
    fetch("/api/todos")
      .then(data => data.json())
      .then(res => this.setState({ list: res.data }));
    console.log(this.state.list)
  };


  createNewToDoItem = () => {
    fetch("/api/todos", {
      method: "post",
      headers: new Headers({
        "Content-Type": "application/json"
      }),
      body: JSON.stringify({
        title: this.state.title,
        body: this.state.todo
      })
    })
      .catch(err => {
        console.error(err);
      });

    if (this.state.title !== '' & this.state.todo !== '') {
      this.props.createTodoItem(this.state.title, this.state.todo);
      this.setState({ title: '', todo: '' });
    }
  };

  handleTitleInput = e => {
    this.setState({
      title: e.target.value,
    });
  };

  handleTodoInput = e => {
    this.setState({
      todo: e.target.value,
    });
  };

  editItem = (i, updTitle, updToDo) => {
    const modifyURL = "/api/todos/" + i;
    fetch(modifyURL, {
      method: "put",
      headers: new Headers({
        "Content-Type": "application/json"
      }),
      body: JSON.stringify({
        title: updTitle,
        todo: updToDo
      })
    })
      .then(resp => {
        if (!resp.ok) {
          if (resp.status >= 400 && resp.status < 500) {
            return resp.json().then(data => {
              let error = { errorMessage: data.message };
              throw error;
            });
          } else {
            let error = {
              errorMessage: "Please try again later. Server is not online"
            };
            throw error;
          }
        }
        return resp.json();
      })
      .then(newTodo => {
        let arr = this.props.list;
        arr[i].title = updTitle;
        arr[i].todo = updToDo;
        this.setState({ updateList: true });
      });
  };

  deleteItem = indexToDelete => {
    const deleteURL = "/api/todos/" + indexToDelete;
    fetch(deleteURL, {
      method: "delete"
    })
      .then(resp => {
        if (!resp.ok) {
          if (resp.status >= 400 && resp.status < 500) {
            return resp.json().then(data => {
              let error = { errorMessage: data.message };
              throw error;
            });
          } else {
            let error = {
              errorMessage: "Please try again later. Server is not online"
            };
            throw error;
          }
        }
        return resp.json();
      })
      .then(() => {
        this.props.deleteTodoItem(indexToDelete);
      });
  };

  randId() {
    return Math.random().toString(36).replace(/[^a-z]+/g, '').substr(2, 10);
  }

  eachToDo = (item, i) => {
    return <ToDoItem
      key={this.randId()}
      title={item.title}
      todo={item.todo}
      deleteItem={this.deleteItem.bind(this, i)}
      editItem={this.editItem.bind(this, i)}
    />
  };

  render() {
    const { list } = this.props;
    return (
      <div className="ToDo">
        <img className="Logo" src={Logo} alt="React logo" />
        <AppBar />
        <div className="ToDo-Container">

          <div className="ToDo-Content">
            {list.map(this.eachToDo)}
          </div>

          <div>
            <Popover
              toDoValue={this.state.todo}
              titleValue={this.state.title}
              titleOnChange={this.handleTitleInput}
              toDoOnChange={this.handleTodoInput}
              addHandler={this.createNewToDoItem}
            />
          </div>
        </div>
      </div>
    );
  }
}

const mapStateToProps = (state) => {
  return {
    list: state.list
  }
}

const mapDispatchToProps = dispatch => {
  return {
    deleteTodoItem: id => {
      dispatch({ type: "DELETE_TODO", id: id });
    },
    createTodoItem: (title, todo) => {
      dispatch({ type: "CREATE_TODO", title: title, todo: todo });
    }
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(ToDo);

请注意,实际上并没有真正使用状态中的“列表”数组,因为在这里,我在Redux状态中具有初始列表状态(可能实现不正确,但是无论如何):

const initState = {
    list: [
        {
            title: 'Cup cleaning',
            todo: "Wash and take away the Kurzhiy's cup from WC"
        },
        {
            title: 'Smoking rollton',
            todo: 'Do some rollton and cigarettes'
        },
        {
            title: 'Curious dream',
            todo: 'Build a time machine'
        }
    ],
};

const rootReducer = (state = initState, action) => {

    switch (action.type) {

        case "DELETE_TODO":
            let newList = state.list.filter((todo, index) => action.id !== index)
            return {
                ...state,
                list: newList
            }

        case "CREATE_TODO":
            const title = action.title;
            const todo = action.todo;

            let createdList = [
                ...state.list,
                {
                    title,
                    todo
                }
            ]
            return {
                ...state,
                list: createdList
            }

        default:
            return state;

    }
}

export default rootReducer;

因此,现在我需要一些帮助-如果我正确理解所有内容,则我的列表状态现在应该存储在MongoDB数据库中。但是目前它在Redux中,我应该如何从当前状态实现正确切换到MongoDB?

我还了解到我的MongoDB实现远非完美,我只是新手,但我需要解决以下问题: 1)我试图从ComponentDidMount方法中从数据库中获取所有待办事项,并将其保存在数组中,但是console.log始终显示数组是空的,肯定存在错误。 2)并没有真正建立与数据库的连接,因为通常我只能将待办事项添加到数据库,但是删除或编辑功能不起作用,因为我对如何实现此索引的东西不太了解,应该使用ObjectId属性来自MongoDB,还是应该将索引从主要组件传递到数据库,以及如何传递?

关于适当的mongodb实现的所有全局建议以及对我的代码的建议或修复,将不胜感激:)

1 个答案:

答案 0 :(得分:1)

这不是res.data,而是您应该在状态中注入的res。 res.data是未定义的,因此不会更新state.list。

componentDidMount = () => {
    fetch("/api/todos")
      .then(data => data.json())
      .then(jsonData => {
        console.log('jsonData --', jsonData)
        console.log('jsonData.data is empty!', jsonData.data)
        this.setState({ list: jsonData })
      });
  };

1-为了能够更新,您正在发送一个ID。如果您要查找待办事项,可以在数据库中创建ID。

请注意,_idid不同。

_id mongodb的ObjectId,它不是整数类型,而是ObjectId类型。

id只是您创建的一个常规字段,称为id。

注意:您的req.params.todoId是一个整数。而ObjectId的类型为ObjectId!因此,您将无法查询类型错误的人。

var todoSchema = new Schema({
  id: Number,
  titleText: String,
  todoText: String
});

2-获取您的待办事项并通过ID更新。如果它不存在,将使用upsert选项来创建它。不要忘记进行铸造以匹配您的架构。 title: req.body.title不起作用,因为您在架构中将其定义为titleText

// updates todo with id
router.put('/:todoId', function (req, res) {
  const data = {
    titleText: req.body.title,
    todoText: req.body.todo
  }


  Todo.findOneAndUpdate(
    { id:  req.params.todoId }, // the query
    { $set: data }, // things to update
    { upsert: true } // upsert option
    ).then((todo) => res.json(todo))
    .catch((error) => res.send(error))
})