1

I have a blog application, with a Blog and a User model, both with references to one another. A User has a one to many relationship with Blog model. I need to display a full list of blogs on a Blogs page and a full list of users on a Users page.

If a logged user creates a blog post, my action creator from my Blogs reducer saves the blog to the database, and updates the BLOGS state. My post call to the back-end is saving the blog post AND the user data to the database but i don't have any actions in my User reducer file to update the user state.

On my app's initial render, i load all of the users and the blogs.

Thus my inital store's state upon user login looks like this:

LOGGED_USER
BLOGS
USERS

I am trying to update the state of the User associated with the new Blog post, but having difficulty in figuring out how to do so. I was thinking that I might have to reach into the shared store for the Blogs state in the update User action creator.

EDIT/UPDATE i realized that if i try to call an action creator to update the state of the blog, and then another separate one to call to update the state of the user, with the new blog, i start running into the potential of mismatched id's, since when a new blog post it is auto generating an ID. Thus i think (but could very well be wrong) that i do need to make a call to the store to pickup the updated blog state when trying to update the user.

SO, it would go like this:

CREATE BLOG POST FORM ON FRONT END with NEW BLOG CONTENT with addBlog handler

const addBlog = async event => {
    event.preventDefault();

    const blogObject = {
      url: newURL.value,
      title: newTitle.value,
      author: newAuthor.value
    };

    await props.createBlog(blogObject);
    await props.updateUser(props.loggedUser, blogObject);
    props.history.push("/blogs");
    setNotification(`New Blog Created!`, 4);
  };

CALL createBlog and updateUser action creators from my blogReducer and User Reducer files:

blogReducer.js

const blogReducer = (state = [], action) => {
  switch (action.type) {
    case "NEW_BLOG":
      return [...state, action.data];

export const createBlog = content => {
  return async dispatch => {
    const newBlog = await blogService.create(content);
    dispatch({
      type: "NEW_BLOG",
      data: newBlog
    });
  };
};

userReducer.js

 **export const updateUser = (id, blog) => {
      return async dispatch => {
        dispatch({
          type: "UPDATE_USER",
          data: {
            id: id,
            data: blog
          }
        });
      };
    };**

const userReducer = (state = [], action) => {
  switch (action.type) {
    case "NEW_USER":
      return [...state, action.data];
    case "UPDATE_USER":
      const {blogs} = store.getState().blogReducer.blogs
      const username = action.data.id.username;
      console.log("Action Data", action.data);
      const userToChangeBlogs = blogs.find(a => a.user.username === username);
      console.log("User to Change", userToChange);
      const changedUser = userToChangeBlogs.blogs.concat(action.data.data);
      console.log("Change User", changedUser);
      return state.map(user =>
        user.username !== username ? user : changedUser
      );
    case "DELETE_USER":
      const removeObject = action.data;
      return state.filter(user => user.id !== removeObject.id);
    case "INIT_USERS":
      return action.data;
    default:
      return state;
  }
};

yet as i start to work on this updateUser action creator, i'm stumbling as to how to handle this. ok, so i get the blogs state from the store, grab the username from the person who sent the new blog form and the new blog content. Then i'm looking in the blogs store state for that user from the submitted form

....and then i DO WHAT...i've reached a dead end! Do i just reach into that users state and replace with all of the updated blogs from the blogs store?

I feel LIKE i am making this way more complicated than it needs to be.

John Rogerson
  • 1,153
  • 2
  • 19
  • 51
  • 1
    What exactly are you trying to update in the user state? Can you explain how the "data is messed up"? What is it supposed to look like? – sallf Nov 18 '19 at 05:22
  • 1
    Assuming that you use a single store, you should be using combineReducers in a rootReducer to namespace the state that each reducer is responsible for. If not, then when you do state updates, be sure to destructure the existing state before adding the updates: ```return {...state, }```. This will prevent you from accidentally clobbering the old state. – Dov Rine Nov 18 '19 at 11:08
  • @sallf sorry, that part was confusing. I updated the description in my code above. When i go to post a new blog, i want the user state to update with the newly published blog post. As shown in image above, when adding a new post, it is adding the two objects, 'id' and 'data'. – John Rogerson Nov 18 '19 at 15:08
  • I guess my question is more on the application of that data. Why do you need it in `store.BLOGS` and `store.USERS`? Why not have a function in your component that takes a user `id` and returns the posts in `store.BLOGS` that have the same author `id`? Then you maintain a single point of truth. – sallf Nov 18 '19 at 17:12
  • Also, jic, I feel like the answer to the title of your question is using `getState`...but I don't think that's actually what you're looking for. https://stackoverflow.com/questions/35667249/accessing-redux-state-in-an-action-creator – sallf Nov 18 '19 at 17:14
  • I have a Blogs page and a Users page. On Blogs page, all of the blogs are listed, with associated User. On Users page, all of the users are posted. Thus on the Users page where I list all of the users i wouldn't be able to call on that store.BLOGS since it is only storing the user associated with the blog and not all of the users. – John Rogerson Nov 18 '19 at 17:18
  • and yes, i should re-word my title, i got typing and started answering some of my own initial questions, sorry for confusion – John Rogerson Nov 18 '19 at 17:19
  • ok, now i've really confused myself. especially when trying to save the blog to the user state...i think my initial question was actually where I need to take this. I'm just going to post some code above, if you have a chance to see if i'm even close with this, i'd appreciate it – John Rogerson Nov 18 '19 at 23:01

1 Answers1

1

Your action.data object has the data key you want itself, as well as the id key.

You should probably modify : const changedUser = userToChange.blogs.concat(action.data) by const changedUser = userToChange.blogs.concat(action.data.data)

Mathieu K.
  • 903
  • 8
  • 27
  • this is actually right, and solved my data issue, thanks for identifying that. my true problem is updating the state of the user associated with the blog posted. mind checking out my updated code? I think it was my error in how i worded this. – John Rogerson Nov 18 '19 at 23:19
  • @JohnRogerson Glad I could solve your issue. Can you mark the answer as correct? – Mathieu K. Nov 19 '19 at 13:34
  • Also the best way to allow for people to debug your code would be with a codepen or equivalent. – Mathieu K. Nov 19 '19 at 13:36
  • I don't quite understand what your new/edited problem is... maybe another question would be clearer? – Mathieu K. Nov 19 '19 at 13:54