4

I have a redux form from which I am retrieving data and trying to post it to my API server.The code for my redux-form is given below:

import React, { Component } from 'react';
import { Field, reduxForm } from 'redux-form';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import { createPosts } from '../actions/posts_action';

class CreatePost extends Component {
  constructor() {
    super();
    this.state = {
      selectValue : ''
  };
   this.renderCategory = this.renderCategory.bind(this);
}

  renderField(field) {
      return(
        <div className="title-design">
            <label className="label-design"> {field.label} </label>
            <input
              type="text"
              className="title-input"
              {...field.input}
            />
            <div className="text-help  has-danger">
              {field.meta.touched ? field.meta.error : ''}
            </div>
      </div>
      );
  }


  renderCategory(field) {
    return(
      <div className="title-design">
        <label className="label-design">{field.label} </label>
          <Field name="category" className="title-input" component="select">
            <option></option>
            <option value="react">React</option>
            <option value="redux">Redux</option>
            <option value="udacity">Udacity</option>
          </Field>

          <div className="text-help has-danger">
            {field.meta.touched ? field.meta.error : ''}
          </div>
      </div>
    );
  }

    onSubmit(values) {
      this.props.createPosts(values, () => {
          this.props.history.push('/');
      });
    }



    render() {
      const { handleSubmit } = this.props;

      return (
        <form onSubmit={handleSubmit(this.onSubmit.bind(this))}>
          <Field
            label="Title for Post"
            name="title"
            component={this.renderField}
          />

          <Field
            label="Post Content"
            name="body"
            component={this.renderField}
          />

          <Field
            label="Category"
            name="category"
            component={this.renderCategory}
            />

          <button type="submit" className="btn btn-primary">Submit</button>
          <Link  to="/">
            <button className="cancel-button">Cancel</button>
          </Link>
        </form>
      );
    }
}

function validate(values) {
  const errors = {} ;

  if (!values.title) {
      errors.title = "Enter a title";
  }

  if (!values.body) {
    errors.body = "Enter some content";
    }

  if(!values.category) {
    errors.category = "Please select a category";
  }
  return errors;
}

export default reduxForm({
  validate : validate,          //validate
  form : 'CreatePostForm'
})(
  connect(null,{ createPosts })(CreatePost)
);

My Action creator for posting data to the API server is:

//Action Creator for creating posts
export function createPosts(values, callback) {
  const request = axios.post(`${API}/posts`,values,{headers})
    .then(() => callback());
    console.log(request);    
  return dispatch => {
    return request.then(({data}) => {
      dispatch({
        type: CREATE_POST,
        payload: data
      })
    })
  }
}

My reducer for creating the post is:

import _ from 'lodash';
import { FETCH_POSTS, FETCH_POST, CREATE_POST } from '../actions/posts_action';

export default function(state = {}, action) {
  switch (action.type) {
    case FETCH_POST:
      // const post = action.payload.data;
      // const newState  = { ...state,  };
      // newState[post.id] = post;
      // return newState;
      return {...state, [action.payload.id]: action.payload};

    case FETCH_POSTS:
     return {posts: { ...state.posts, ...action.payload }};

    case CREATE_POST:
      return {posts: { ...state, ...action.payload}};

     default:
      return state;
  }

}

My index file for all the reducers combined together is:

import { combineReducers } from 'redux';
import PostReducer from './PostsReducer';
import { reducer as formReducer} from 'redux-form';
import CategoriesReducer from './CategoriesReducer';

const rootReducer = combineReducers({
    posts: PostReducer,
    categories: CategoriesReducer,
    form : formReducer
});

export default rootReducer;

Now the issue I am facing is,when I try to submit my form data, I get the error as shown in the screenshot below:

error_file

Can anyone please guide me with what I am doing wrong and how to proceed?

EDIT 1 Code index.js file for the whole project is given below:

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { BrowserRouter, Route } from 'react-router-dom';
import thunk from 'redux-thunk';
import './index.css';
import App from './App';
import reducers from './reducers/index.js'
import Posts from './components/posts_index';
import CreatePost from './components/new_post';
import PostDetail from './components/post_detail';
import CategoryView from './components/category';
import { compose } from 'redux';

//const createStoreWithMiddleware = createStore(reducers,applyMiddleware(thunk));

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
 const createStoreWithMiddleware = createStore(reducers, composeEnhancers(applyMiddleware(thunk)));

ReactDOM.render(
  <Provider store={createStoreWithMiddleware}>
      <BrowserRouter>
        <div>
          <Route  path="/new" component={CreatePost} />
          <Route path="/posts/:id" component={PostDetail} />
          <Route exact  path="/" component={Posts} />
          <Route path="/:category/posts" component={CategoryView} />
        </div>
      </BrowserRouter>
  </Provider>  , document.getElementById('root'));

Edit 2:

I am also adding the file for the API server below:

const clone = require('clone')

let db = {}

const defaultData = {
  "8xf0y6ziyjabvozdd253nd": {
    id: '8xf0y6ziyjabvozdd253nd',
    timestamp: 1467166872634,
    title: 'Udacity is the best place to learn React',
    body: 'Everyone says so after all.',
    author: 'thingtwo',
    category: 'react',
    voteScore: 6,
    deleted: false,
    commentCount: 2
  },
  "6ni6ok3ym7mf1p33lnez": {
    id: '6ni6ok3ym7mf1p33lnez',
    timestamp: 1468479767190,
    title: 'Learn Redux in 10 minutes!',
    body: 'Just kidding. It takes more than 10 minutes to learn technology.',
    author: 'thingone',
    category: 'redux',
    voteScore: -5,
    deleted: false,
    commentCount: 0
  }
}

function getData (token) {
  let data = db[token]
  if (data == null) {
    data = db[token] = clone(defaultData)
  }
  return data
}

function getByCategory (token, category) {
  return new Promise((res) => {
    let posts = getData(token)
    let keys = Object.keys(posts)
    let filtered_keys = keys.filter(key => posts[key].category === category && !posts[key].deleted)
    res(filtered_keys.map(key => posts[key]))
  })
}

function get (token, id) {
  return new Promise((res) => {
    const posts = getData(token)
    res(
      posts[id].deleted
        ? {}
        : posts[id]
    )
  })
}

function getAll (token) {
  return new Promise((res) => {
    const posts = getData(token)
    let keys = Object.keys(posts)
    let filtered_keys = keys.filter(key => !posts[key].deleted)
    res(filtered_keys.map(key => posts[key]))
  })
}

function add (token, post) {
  return new Promise((res) => {
    let posts = getData(token)

    posts[post.id] = {
      id: post.id,
      timestamp: post.timestamp,
      title: post.title,
      body: post.body,
      author: post.author,
      category: post.category,
      voteScore: 1,
      deleted: false,
      commentCount: 0
    }

    res(posts[post.id])
  })
}

function vote (token, id, option) {
  return new Promise((res) => {
    let posts = getData(token)
    post = posts[id]
    switch(option) {
        case "upVote":
            post.voteScore = post.voteScore + 1
            break
        case "downVote":
            post.voteScore = post.voteScore - 1
            break
        default:
            console.log(`posts.vote received incorrect parameter: ${option}`)
    }
    res(post)
  })
}

function disable (token, id) {
    return new Promise((res) => {
      let posts = getData(token)
      posts[id].deleted = true
      res(posts[id])
    })
}

function edit (token, id, post) {
    return new Promise((res) => {
        let posts = getData(token)
        for (prop in post) {
            posts[id][prop] = post[prop]
        }
        res(posts[id])
    })
}

function incrementCommentCounter(token, id, count) {
  const data = getData(token)
  if (data[id]) {
    data[id].commentCount += count
  }
}

module.exports = {
  get,
  getAll,
  getByCategory,
  add,
  vote,
  disable,
  edit,
  getAll,
  incrementCommentCounter
}

1 Answer 1

2

Update: Try this format for the action creator. :

export function createPosts(values, callback) {

  return dispatch => { //return function
    return axios.post(`${API}/posts`,values,{headers}) //return post request response
    .then((data) => { //pass data in as a parameter, call the callback, dispatch the action. 
        callback();

      dispatch({
        type: CREATE_POST,
        payload: data
      })
    })
  }
}
Sign up to request clarification or add additional context in comments.

7 Comments

Thanks for the reply.But I am already using redux-thunk.I have pasted the code for my index.js above in an edit whixh shows the use of redux-thunk file .Can you please have a look at it?
sure,give me few mins.Will try it and let you know.
The data gets posted to the server now.But there is still one issue.If I enter 2 sets of data,i.e. when I try to enter data second time,the previous data gets deleted,only the new set remains.Why is this happening?
I have also added my server file above in an edit for the posts that user post.Kindly have a look if there is something required from that file for the issue above.I am not able to figure out how to proceed.
okay,will open a new question and provide you the link.Can you please help me with that.And thanks for the help in solving this issue.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.