Реагируйте на редукцию правильного обновления записи и отражения изменений на экране - PullRequest
1 голос
/ 12 мая 2019

В целях обучения я создал это веб-приложение, в котором я пытаюсь реализовать грубые операции.Все работает правильно, кроме UPDATE, где запись MongoDB обновляется, но изменения на экране не отражаются до обновления.Я все еще учусь, поэтому не все предельно ясно, я подозреваю, что проблема в REDUCER ... или в компоненте mapStateToProp объект ...

Что я здесь не так делаю?

routs / api Item.findByIdAndUpdate для правильного обновления базы данных, но должно ли оно также возвращать что-либо, чтобы редуктор / действие могло на него отреагировать?

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 Ответ

1 голос
/ 12 мая 2019

Да, вы хотите вернуть обновленный элемент из базы данных 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
           }
       }
    })
  };

При этом вы сможете взять обновленную историю со своего бэкэнда и отразить ее на переднем крае.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...