Peter Zacharias
Peter Zacharias

Reputation: 795

Object.assign does not update my state (React)

I have an app which has a few users. I would now like to be able to create a new user. So I have created this actionCreator:

export const createUser = (first, last) => {
    console.log("You are about to create user: XX ");
    return {
        type: 'USER_CREATE',
        first: first,
        last: last,
        payload: null
    }
};

I am dealing only with first & last names for now. The actionCreator gets its parameters from the container. There is a button which calls the actionCreator like so:

        <button onClick={() =>this.props.createUser(this.state.inputTextFirstName, this.state.inputTextLastName)}>Submit</button>

My UserReducer looks like this:

/*
 * The users reducer will always return an array of users no matter what
 * You need to return something, so if there are no users then just return an empty array
 * */
export default function (state = null, action) {

    if(state==null)
    {
        state = [
            {
                id: 1,
                first: "Bucky",
                last: "Roberts",
                age: 71,
                description: "Bucky is a React developer and YouTuber",
                thumbnail: "http://i.imgur.com/7yUvePI.jpg"
            },
            {
                id: 2,
                first: "Joby",
                last: "Wasilenko",
                age: 27,
                description: "Joby loves the Packers, cheese, and turtles.",
                thumbnail: "http://i.imgur.com/52xRlm8.png"
            },
            {
                id: 3,
                first: "Madison",
                last: "Williams",
                age: 24,
                description: "Madi likes her dog but it is really annoying.",
                thumbnail: "http://i.imgur.com/4EMtxHB.png"
            }
        ]
    }

    switch (action.type) {
        case 'USER_DELETED':
            return state.filter(user => user.id !== action.userIdToDelete);
        case 'USER_CREATE':
            console.log("Action first:" + action.first);
            console.log("Action last:" + action.last);
            Object.assign({}, state, {
                    id: 4,
                    first: action.first,
                    last: action.last,
                    age: 24,
                    description: "Some new Text",
                    thumbnail: "http://i.imgur.com/4EMtxHB.png"
                });
            return state;
    }

    return state;
}

Now I have a few questions. 1) Is this the proper way to do this, or am I writing bad code somewhere? Keep in mind that I am trying to use Redux here, I am not entirely sure though whether I am not sometimes falling back into React without Redux

2) Am I doing the state thing correctly? I initially used a tutorial and am now building upon that, but I am not sure why state seems to be an array:

state = [   <--- Does this mean that my state is an array?
                {
                    id: 1,
                    // and so on ...

I am very confused by this, since in other Tutorials state is just an object containing other smaller objects and its all done with parentheses { }

3) What would be the best way to create a new user. My Object.assign does not work, it does not update anything, and I am not sure where the mistake lies.

4) And, relatedly, how could I update one individual user or a property of one individual user?

Upvotes: 2

Views: 3277

Answers (2)

Mark Williams
Mark Williams

Reputation: 2308

As Flyer53 states you need to set the state to the return value of Object.assign() as this is designed to not mutate state it will not change the value of the state you're passing in.

  1. The code's fine; I'd tend to use just one property on the action in addition to its type, so have a property of (say) user that is an object containing all the user data (first name, last name etc).

    I believe it's quite idiomatic to define a default state outside of the reducer and then set this as the default value for the state parameter in the reducer function:

    export default function (state = initialState, action) {

    For a brilliant introduction by its creator, see https://egghead.io/courses/getting-started-with-redux

  2. State can be any shape you like. As an application grows in complexity it will usually be represented as an object composed of different sections of data. So, for example, in your case in could be comprised of an array of users and, say, an 'order by' that could apply to some UI state):

    { users: [], orderBy: 'lastName' }

  3. If you carry on using an array of users as the state then you can use the ES6 spread operator to append the new user, for example:

    newState = [ ...state, action.user ];

    whereas if you move to using an object for state, the following would similarly append a user:

    newState = Object.assign({}, state, { users: [ ...state.users, action.user ] };

  4. Finally, to update a single user you could just use map against the array of users as follows (this is obviously hardcoded, but you could match, say, on id and update the appropriate properties).

    let modifiedUsers = state.users.map((user) => {
        if (user.id === 3) {
            user.name = user.name + '*';
        }
        return user;
    });
    let newState = Object.assign({}, state, { users: modifiedUsers });
    

Upvotes: 3

Flyer53
Flyer53

Reputation: 764

There's maybe an easier way to log the state(users) in an object (not in an array as in your example code above) that works without Object.assign() which is supposed to work with objects, not arrays:

var state = {
  user1: {
  	id: 1,
      first: "Bucky",
      last: "Roberts",
      age: 71,
      description: "Bucky is a React developer and YouTuber",
      thumbnail: "http://i.imgur.com/7yUvePI.jpg"
    }
};

state['user' + 2] = {
  id: 2,
  first: "Joby",
  last: "Wasilenko",
  age: 27,
  description: "Joby loves the Packers, cheese, and turtles.",
  thumbnail: "http://i.imgur.com/52xRlm8.png"
};

console.log(state);
console.log(state.user2);

Just an idea ...

Upvotes: 0

Related Questions