反应redux正确的更新记录并在屏幕上反映出更改

时间:2019-05-12 05:50:00

标签: reactjs react-redux

出于学习目的,我制作了这个Web应用程序,试图在其中实现杂项操作。除UPDATE以外,其他所有功能均正常工作,在UPDATE上,MongoDB记录已更新,但屏幕上的更改直到刷新后才反映出来。 我仍在学习,因此并非一切都非常清晰,我怀疑REDUCER ...或组件mapStateToProp对象中的问题...

我在这里做什么错了?

路线/ API Item.findByIdAndUpdate可以确保正确更新数据库,但它是否还应返回任何内容,以使reducer / action能够对此做出反应?

const express = require("express");
const router = express.Router();
const auth = require("../../middleware/auth");

// Item Model
const Item = require("../../models/stories");

// @route   GET api/items
// @desc    Get All Items
// @access  Public
router.get("/", (req, res) => {
  Item.find()
    .sort({ date: -1 })
    .then(items => res.json(items));
});

// @route   PUT api/items
// @desc    Update An Item
// @access  Private
router.put("/:_id", auth, (req, res) => {

  Item.findByIdAndUpdate(
    req.params._id,
    req.body,
    { new: false, useFindAndModify: false },
    () => {}
  );
});
module.exports = router;

减速器

import {
  GET_STORIES,
  ADD_STORY,
  DELETE_STORY,
  STORIES_LOADING,
  UPDATE_STORY
} from "../actions/types";

const initialState = {
  stories: [],
  loading: false
};

export default function(state = initialState, action) {
  switch (action.type) {
    case GET_STORIES:
      return {
        ...state,
        stories: action.payload,
        loading: false
      };
    case DELETE_STORY:
      return {
        ...state,
        stories: state.stories.filter(story => story._id !== action.payload)
      };
    case ADD_STORY:
      return {
        ...state,
        stories: [action.payload, ...state.stories]
      };
    case UPDATE_STORY:
      return {
        ...state,
        stories: action.payload
      };
    case STORIES_LOADING:
      return {
        ...state,
        loading: true
      };
    default:
      return state;
  }
}

动作

import axios from "axios";
import {
  GET_STORIES,
  ADD_STORY,
  DELETE_STORY,
  UPDATE_STORY,
  STORIES_LOADING
} from "./types";
import { tokenConfig } from "./authActions";
import { returnErrors } from "./errorActions";

export const getStories = () => dispatch => {
  dispatch(setStoriesLoading());
  axios
    .get("/api/stories")
    .then(res =>
      dispatch({
        type: GET_STORIES,
        payload: res.data
      })
    )
    .catch(err =>
      dispatch(returnErrors(err.response.data, err.response.status))
    );
};

export const addStory = story => (dispatch, getState) => {
  axios
    .post("/api/stories", story, tokenConfig(getState))
    .then(res => {
      dispatch({
        type: ADD_STORY,
        payload: res.data
      });
    })
    .catch(err =>
      dispatch(returnErrors(err.response.data, err.response.status))
    );
};
export const updateStory = story => (dispatch, getState) => {
  axios
    .put(`/api/stories/${story.id}`, story, tokenConfig(getState))
    .then(res => {
      dispatch({
        type: UPDATE_STORY,
        payload: story
      });
    })
    .catch(err =>
      dispatch(returnErrors(err.response.data, err.response.status))
    );
};

export const deleteStory = id => (dispatch, getState) => {
  axios
    .delete(`/api/stories/${id}`, tokenConfig(getState))
    .then(res => {
      dispatch({
        type: DELETE_STORY,
        payload: id
      });
    })
    .catch(err =>
      dispatch(returnErrors(err.response.data, err.response.status))
    );
};

export const setStoriesLoading = () => {
  return {
    type: STORIES_LOADING
  };
};

组件

import React, { Component } from "react";
import {
  Modal,
  ModalHeader,
  ModalBody,
  Form,
  FormGroup,
  Label,
  Input
} from "reactstrap";
import { connect } from "react-redux";
import { updateStory } from "../../actions/storyActions";
import PropTypes from "prop-types";

class UpdateStoryModal extends Component {
  constructor(props) {
    super(props);
  }

  state = {
    id: this.props.idVal,
    modal: false,
    title: this.props.titleVal,
    body: this.props.bodyVal
  };
  static propTypes = {
    isAuthenticated: PropTypes.bool
  };

  toggle = () => {
    this.setState({
      modal: !this.state.modal
    });
  };

  onChange = e => {
    this.setState({ [e.target.name]: e.target.value });
  };

  onSubmit = e => {
    e.preventDefault();

    const obj = {
      id: this.props.idVal,
      title: this.state.title,
      body: this.state.body
    };

    this.props.updateStory(obj);
    this.toggle();
  };

  render() {
    return (
      <div>
        {this.props.isAuthenticated ? (
          <button
            type="button"
            className="btn btn-primary"
            size="sm"
            onClick={this.toggle}
          >
            Edit Story
          </button>
        ) : (
          <h4 className="mb-3 ml-4">Please log in to manage stories</h4>
        )}

        <Modal isOpen={this.state.modal} toggle={this.toggle}>
          <ModalHeader toggle={this.toggle}>Edit story</ModalHeader>
          <ModalBody>
            <Form>
              <FormGroup>
                <Label for="story">Title</Label>
                <Input
                  type="text"
                  name="title"
                  id="story"
                  onChange={this.onChange}
                  value={this.state.title}
                />
                <Label for="story">Story</Label>
                <Input
                  type="textarea"
                  name="body"
                  rows="20"
                  value={this.state.body}
                  onChange={this.onChange}
                />
                <button
                  type="button"
                  className="btn btn-dark"
                  style={{ marginTop: "2rem" }}
                  onClick={this.onSubmit}
                >
                  Edit story
                </button>
              </FormGroup>
            </Form>
          </ModalBody>
        </Modal>
      </div>
    );
  }
}

const mapStateToProps = state => ({
  story: state.story,
  isAuthenticated: state.auth.isAuthenticated
});

export default connect(
  mapStateToProps,
  { updateStory }
)(UpdateStoryModal);

1 个答案:

答案 0 :(得分:1)

是的,您想从MongoDB数据库返回更新后的项目,以便在化简器中使用某些东西。看起来您已经设置了动作创建者,以为这种逻辑做准备。因此,我们只需要进行一些更新:

在您的快递路线中,您需要以下物品:

router.put("/:_id", auth, (req, res) => {
  //this returns a promise
  Item.findByIdAndUpdate(
    req.params._id,
    req.body,
    { new: false, useFindAndModify: false },
    () => {}
  )
  .then((updatedItem) => {
     res.json(updatedItem) //we capture this via our promise-handler on the action
  })
  .catch((error) => {
     return res.status(400).json({ couldnotupdate: "could not update item"})
  })
});

然后,我们可以使用动作创建者诺言处理程序中的res.data来访问更新的项目

export const updateStory = story => (dispatch, getState) => {
  axios
    .put(`/api/stories/${story.id}`, story, tokenConfig(getState))
    .then(res => {
      dispatch({
        type: UPDATE_STORY,
        payload: res.data
      });
    })
    .catch(err =>
      dispatch(returnErrors(err.response.data, err.response.status))
    );
};

现在您已将更新的项目作为动作有效负载,我们需要更新您的减速器:

case UPDATE_STORY:
  return {
    ...state,
    stories: state.stories.map((story) => {
        if(story._id == action.payload._id){
           return{
               ...story,
               ...action.payload
           } else {
               return story
           }
       }
    })
  };

这样,您应该能够从后端获取更新的故事,并将其反映到前端。