添加评论而不刷新页面

时间:2018-07-21 13:34:05

标签: reactjs redux react-redux

我有一个评论表单,可以添加评论,但是我必须刷新页面才能显示它们

评论表单如下所示

class CommentForm extends PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      state: this.props.state
    };
   this.handleChange = this.handleChange.bind(this);
  }

  handleSubmit = e => {
    e.preventDefault();
    this.props.onSubmit(this.state);


  };

  handleChange = event => {
    const { name, value } = event.target;

    this.setState({
      [name]: value
    });
  };

  render() {


    return (
      <div>
        <Paper className="styles" elevation={4}>
          <form onSubmit={this.handleSubmit}>
            <div>
              <TextField
                label="Comment"
                name="comment"
                value={this.state.comment || ""}
                onChange={this.handleChange}
              />
            </div>
            <br />
            <Button type="submit">Save</Button>
          </form>

        </Paper>
      </div>
    );
  }
}

const mapStateToProps = state => {
  return {
    state: state
  };
};

export default connect(
  mapStateToProps,
  { getTicket }
)(CommentForm);

该组件用于显示保存在数据库中的注释 displayComments

class DisplayComments extends PureComponent {
  componentWillMount() {
    this.props.getAllComments();
  }
  getComment(commentId) {
    this.props.getComment(commentId);
  }

  render() {
    const { comments } = this.props;
    const commentsOnTicket = this.props.data.match.params.id
    const filterComments = comments.filter(comment => comment.tickets.id == commentsOnTicket);

    const commentsList = filterComments.sort((a, b) => {
      return a.id - b.id;
    });
    return (
      <div>
        <Paper className="styles" elevation={4}>
          <h1>comments</h1>
          <table>
            <thead />
            <tbody>
              {commentsList.map(comment => (
                <tr key={comment.id}>
                  <td style={{ border: "2px solid black" }}>
                    {comment.comment}
                  </td>
                  <td />
                </tr>
              ))}
            </tbody>
          </table>
          <br />
          <br />
        </Paper>
      </div>
    );
  }
}

const mapStateToProps = (state, props) => {
  return {
    comments: state.comments,
    comment: state.comment,
    users: state.users === null ? null : state.users,
  };
};

export default connect(
  mapStateToProps,
  {
    getAllComments,
    getComment,
  }
)(DisplayComments);

我对React的了解有限,因为我刚开始学习它 所以我想应该通过生命周期挂钩来完成 但是我还不太了解它们。

这是父母组件,用于呈现评论表格并显示评论

class TicketDetails extends PureComponent {
  componentWillMount() {
    this.props.getAllComments();
  }
  addComment = comment => {
    this.props.addComment(comment);
  };
  render() {
    const { ticket, tickets, comments } = this.props;
    const { users } = ticket;


    return <div>
        <Card className="outer-card">
          <h1>Ticket: {ticket.id}</h1>
          <h2>Price: €{ticket.price}</h2>
          <p>Description: {ticket.description}</p>
          <h2>Image: {ticket.image}</h2>
          <p>Risk: {getRiskfactor(tickets, ticket, users, comments)} %</p>
          <hr />
        </Card>
      <DisplayComments data={this.props}  />
        <CommentForm onSubmit={this.addComment} />
      </div>;
  }
}
const mapStateToProps = state => {
  return {
    ticket: state.ticket,
    users: state.users,
    tickets: state.tickets,
    comments: state.comments
  };
};
export default connect(
  mapStateToProps,
  {
    addComment,
    getAllComments
  }
)(TicketDetails);

TicketDetails App 组件中呈现

class App extends Component {
  render() {
    return (
      <Router>
      <div>
       <TopBar />
       <br/><br/>
          <Route exact path="/login" component={LoginPage} />
          <Route exact path="/logout" component={LogoutPage} />
          <Route exact path="/signup" component={SignupPage} />

          <Route exact path="/events" component={EventsList} />
          <Route exact path="/addEvent" component={AddEvent} />

           <Route exact path="/events/:id" component={TicketsList} />
          <Route exact path="/tickets/:id" component={TicketDetails} />
          <Route exact path="/addTicket" component={AddTicket} />

          <Route exact path="/" render={() => <Redirect to="/events" />} />

      </div>

      </Router>
    );
  }
}

Action / comments.js

import * as request from "superagent";
import {baseUrl} from "../constants";
import {logout} from "./users";
import {isExpired} from "../jwt";

export const GET_ALL_COMMENTS = "GET_ALL_COMMENTS";
export const GET_COMMENT = "GET_COMMENT";
export const ADD_COMMENT = "ADD_COMMENT";

export const getAllComments = () => (dispatch, getState) => {
    const state = getState();
    if (!state.currentUser) return null;
    const jwt = state.currentUser.jwt;
    if (isExpired(jwt)) return dispatch(logout());
    request
        .get(`${baseUrl}/comments`)
        .set("Authorization", `Bearer ${jwt}`)
        .then(response =>
            dispatch({
                type: GET_ALL_COMMENTS,
                payload: response.body.comments
            })
        )

        .catch(err => alert(err));
};

export const getComment = commentId => (dispatch, getState) => {
    const state = getState();
    if (!state.currentUser) return null;
    const jwt = state.currentUser.jwt;

    if (isExpired(jwt)) return dispatch(logout());

    request
        .get(`${baseUrl}/comments/${commentId}`)
        .set("Authorization", `Bearer ${jwt}`)
        .then(response =>
            dispatch({
                type: GET_COMMENT,
                payload: response.body
            })
        )
        .catch(err => alert(err));
};

export const addComment = comment => (dispatch, getState) => {
    const state = getState();
    const jwt = state.currentUser.jwt;

    if (isExpired(jwt)) return dispatch(logout());

    request
        .post(`${baseUrl}/comments`)
        .set("Authorization", `Bearer ${jwt}`)
        .send({
            comment: comment.comment,
            tickets: state.ticket
        })
        .then(response =>
            dispatch({
                type: ADD_COMMENT,
                payload: response.body
            })
        );
};

reducers / comments.js

import { GET_ALL_COMMENTS } from "../actions/comments";

export default function(state = [], action) {
  switch (action.type) {
    case  GET_ALL_COMMENTS:
      return action.payload;

    default:
      return state;
  }
}

reducers / comment.js

import { GET_COMMENT,ADD_COMMENT } from "../actions/comments";

const comment = {};

export default function(state = comment, action) {
  switch (action.type) {
    case GET_COMMENT:
      return action.payload;

    case ADD_COMMENT:
      return action.payload;

    default:
      return state;
  }
}

1 个答案:

答案 0 :(得分:2)

尽管您的问题似乎不完整,但在实现上仍然存在一些错误。

  1. 您尚未正确使用道具进行派遣。这是为了将分派连接到您的函数,这样您就不必在函数中显式调用this.props.dispatch(func())

    const mapDispatchToProps = (dispatch) => {
        return {
             addComment: (comment) => dispatch(addComment(comment))
        }
    }
    
  2. 将道具传递到两到三个级别似乎不是一个好习惯。由于您的课程是静态课程,因此您可以轻松地在您的组件中获取它,甚至可以轻松调用它。

  3. 为什么要采取措施从存储中获取数据。动作和简化程序应在存储中进行更改,例如添加,删除和更新,而不是用于获取数据。为了获取数据,您需要将状态连接到道具。

更新****

// Add import of the action here like import {addComment} from '../.whatever';
class TicketDetails extends PureComponent {
      componentWillMount() {
        this.props.getAllComments();
      }
      addComment = comment => {
        this.props.addComment(comment);
      };
      render() {
        const { ticket, tickets, comments } = this.props;
        const { users } = ticket;


        return <div>
            <Card className="outer-card">
              <h1>Ticket: {ticket.id}</h1>
              <h2>Price: €{ticket.price}</h2>
              <p>Description: {ticket.description}</p>
              <h2>Image: {ticket.image}</h2>
              <p>Risk: {getRiskfactor(tickets, ticket, users, comments)} %</p>
              <hr />
            </Card>
          <DisplayComments data={this.props}  />
            <CommentForm onSubmit={this.addComment} />
          </div>;
      }
    }
    const mapStateToProps = state => {
      return {
        ticket: state.ticket,
        users: state.users,
        tickets: state.tickets,
        comments: state.comments
      };
    };
    const mapDispatchToProps = (dispatch) => {
      return {
        addComment: (comment) => dispatch(addComment(comment)),
        getAllComments: () => dispatch(getAllComments())
      };
    };
    export default connect(
      mapStateToProps,
      mapDispatchToProps 
    )(TicketDetails);