2

enter image description hereenter image description hereI am working on a blog page where you can click on a button and open a modal to edit the comment under the post.

On the Post Details Page I have:

openEditCommentModal = (id) => {
    this.setState(() => ({
    editCommentModalOpen: true,
}))
    this.props.fetchCommentById(id)
}

On the edit comment file I have:

const mapStateToProps = state => {
    return {
        initialValues: state.commentContainer.selectedComment
    }
}

So I do two things: 1. open modal 2. call fetchCommentById(id) so that I can update the state.commentContainer.selectedComment

Post Details page is the parent component, and the edit comment form is the child component.

I need to give initialValue to the edit form. The initialValue is the original content of the comment, and then user can edit it.

Weird thing is that when I click the edit button the first time, NO initialValue. It's an empty object. Therefore I have an empty form. When I close the modal and re open it, initialValue is being updated to be the comment I want, and the edit comment form is now having all the original content.

I don't understand why openEditCommentModal cannot update the state the first time. Can anyone help?

==============

Problem solved: In reduxForm, do this:

enableReinitialize : true

On Post Details page:

openEditCommentModal = (id) => {
        this.setState(() => ({
        editCommentModalOpen: true,
    }))
        this.props.fetchCommentById(id)
    }

.........

<Modal
          className='modal'
          overlayClassName='overlay'
          isOpen={editCommentModalOpen}
          onRequestClose={this.closeEditCommentModal}
          contentLabel='Modal'
        >
         <div>
           <EditComment />
           <button onClick={() => this.closeEditCommentModal()}>Close</button>
           </div>
        </Modal>

...............

const mapDispatchToProps = dispatch => {
    return {
        fetchByPostId: id => dispatch(fetchByPostId(id)),
        deleteByPostId: id => dispatch(deleteByPostId(id)),
        deleteByCommentId: id => dispatch(deleteByCommentId(id)),
        vote: (id, option) => dispatch(vote(id, option)),
        fetchComments: id => dispatch(fetchComments(id)),
        fetchCommentById: id => dispatch(fetchCommentById(id))
    };
 };

Edit Comment Component :

import React, { Component } from "react";
import { Field, reduxForm } from 'redux-form'
import { Link } from 'react-router-dom'
import { connect } from 'react-redux'
import { fetchCommentById } from '../Actions'
// import { updateComment } from '../Actions'
const randomID = require("random-id")

class EditComment extends Component {


  renderField = (field) => {
    const { meta: { touched, error } }  = field
    const className = `form-group ${ touched && error ? 'has-danger' : '' }`

    return (
      <div className={className}>
        <label>{field.label}</label>
        <input 
          className="form-control"
          type="text"
          {...field.input}
        />
        <div className="text-help">
          {touched ? error : ''}
        </div>
      </div>
    )
  }

  onSubmit = (values) => {
    const id = values.id
    let newValues = {}
    newValues.body = values.body
  //  this.props.updatePost(newValues, id, this.props.history.push(`/post/${id}`) )
  }

  render() {

    console.log('this.props.initialValue', this.props.initialValues)

    if(!this.props.initialValues) {
      return <div></div>
    } 




    const { handleSubmit, categories, id } = this.props

    return (
      <div>
        <h1>Edit Comment</h1>
        <form onSubmit={handleSubmit(this.onSubmit)}>
          <Field
            label="Content"
            name="body"
            component={this.renderField}
          />
          <span>Author: </span><span>{this.props.initialValues.author}  </span>
          <span>Time: </span><span>{this.props.initialValues.timestamp}</span>
          <div>
          <button type="submit">Submit</button> 

          </div>
        </form>
      </div> 
    )
  }
}
const validate = (values) => {
  const errors = {}

  if(!values.title) {
    errors.title = "Enter a title"
  }
  if(!values.category) {
    errors.category = "Enter a category"
  }
  if(!values.content) {
    errors.content = "Enter some content"
  }
  return errors
}

const mapStateToProps = state => {
  return {
    initialValues: state.commentContainer.selectedComment
  }
}


EditComment = reduxForm({
  validate,
  form: 'CommentEditForm',
  enableReinitialize : true
})(EditComment)


export default connect(mapStateToProps, { fetchCommentById })(EditComment)
scabiosa
  • 55
  • 3
  • 8
  • what errors you receive in your console? – Amr Aly Aug 28 '17 at 01:10
  • No error at all....When I console.log(this.props.initialValue) on my editComment file, I got an empty object when I clicked edit the first time. – scabiosa Aug 28 '17 at 01:20
  • If I close the modal and open it again, console.log(this.props.initialValue) will become the comment object I need – scabiosa Aug 28 '17 at 01:20
  • do you have any http request including in the process? – Amr Aly Aug 28 '17 at 01:21
  • export const fetchCommentById = id => dispatch => { ReadableAPI.getCommentById(id) .then(comment => { dispatch({ type: FETCH_COMMENT_BY_ID, payload: comment }); }) .catch(err => console.log(err)); }; – scabiosa Aug 28 '17 at 01:44
  • export const getCommentById = id => fetch(`${api}/comments/${id}`, { headers }) .then(res => res.json()) .then(data => data); export const getPostsByCat = category => fetch(`${api}/${category}/posts`, { headers }) .then(res => { const data = res.json(); return data; }) – scabiosa Aug 28 '17 at 01:44
  • When fetchCommentById is called, RESTful API is called – scabiosa Aug 28 '17 at 01:45
  • I have no problem getting the payload being the comment object – scabiosa Aug 28 '17 at 01:46
  • since you have a promise you may need to check for your `initialvalues` because it needs some amount of time to load up so in your `render` function you can do something like so `render(){ if(initialvalue) { return( your_jsx_for_the_comment ) } else { return(
    Loading...
    ) } }`
    – Amr Aly Aug 28 '17 at 02:00
  • I see....let me try it out. – scabiosa Aug 28 '17 at 02:06
  • Actually I tried this – scabiosa Aug 28 '17 at 02:09
  • render() { console.log('this.props', this.props.initialValues) if(!this.props.initialValues) { return
    } const { handleSubmit, categories, id } = this.props return (

    Edit Comment

    – scabiosa Aug 28 '17 at 02:09
  • But it doesn't work.... – scabiosa Aug 28 '17 at 02:09
  • so what the console logs prints out for the initialValues value? – Amr Aly Aug 28 '17 at 02:15
  • Click edit => initialization of from => initalValue is empty object => fetchCommentById is called after the initilaization => initialValue is the comment object I want – scabiosa Aug 28 '17 at 02:29
  • That means even though I call fetchCommentById when I open the modal, the initialization run before FETCH_COMMENT_BY_ID is being dispatched to reducer – scabiosa Aug 28 '17 at 02:31
  • it would be better to add a code snippet so it's easier to debug – Amr Aly Aug 28 '17 at 03:15
  • I have sent you an email. Please check it out. – scabiosa Aug 28 '17 at 04:17
  • So your initialValue is an empty object? Can you show us the code of your `fetchCommentById(id)` function? – Hana Alaydrus Aug 28 '17 at 04:37
  • See see above. I edited my post to add the function. – scabiosa Aug 28 '17 at 04:42
  • fetchCommentById(id) in action file call the API => dispatch "FETCH_COMMENT_BY_ID => reducer update state.commentContainer.selectedComment – scabiosa Aug 28 '17 at 04:51
  • @scabiosa sorry I'm not quite understand. So you are fetching data from API, but at the first render you got empty object? Does you got the initialValue from the API too? or you save the initialValue somewhere? – Hana Alaydrus Aug 28 '17 at 05:05
  • https://i.stack.imgur.com/pMwdY.png – scabiosa Aug 28 '17 at 05:19
  • Look at this image and you'll understand. – scabiosa Aug 28 '17 at 05:20
  • Problem solved btw. Please look at Amr's answer – scabiosa Aug 28 '17 at 05:20

1 Answers1

3

I have checked your code and searched for your problem and i have found this answer that you have to enable the initialization of you form to be bind with your data so what you need to do:

EditComment = reduxForm({
  validate,
  form: 'CommentEditForm',
  enableReinitialize : true // you need to add this property
})(EditComment)
Amr Aly
  • 3,871
  • 2
  • 16
  • 33