Redux-toolkit: createEntityAdapter "updateOne" API doesn't work

Created on 31 Mar 2020  路  7Comments  路  Source: reduxjs/redux-toolkit

createEntityAdapter "updateOne" API doesn't work, data won't update? Where am I doing wrong?
codesandbox:
https://codesandbox.io/s/hopeful-kowalevski-yet3g

import React from 'react';
import { Provider, useDispatch, useSelector } from 'react-redux';
import {
  configureStore,
  createSlice,
  createEntityAdapter
} from '@reduxjs/toolkit';

const todosAdapter = createEntityAdapter();

const todosSlice = createSlice({
  name: 'todos',
  initialState: todosAdapter.getInitialState(),
  reducers: {
    todoAdded: todosAdapter.addOne,
    todoUpdated: todosAdapter.updateOne
  }
});

const { todoAdded, todoUpdated } = todosSlice.actions;

const store = configureStore({
  reducer: { todos: todosSlice.reducer }
});

const Updated = () => {
  const dispatch = useDispatch();
  const todos = useSelector(store => store.todos);
  console.log('todos: ', todos);

  return (
    <div>
      <button onClick={() => dispatch(todoAdded({ id: 1, todo: 'one' }))}>
        todoAdded
      </button>
      <button onClick={() => dispatch(todoUpdated({ id: 1, todo: 'two' }))}>
        todoUpdated
      </button>

      <h5>Todos: {JSON.stringify(todos)}</h5>
    </div>
  );
};

export default () => (
  <Provider store={store}>
    <Updated />
  </Provider>
);

Most helpful comment

As a side note, this is a good use case for using upsertOne as it's easier to deal with.

All 7 comments

It looks like you're using the API the wrong way.

updateOne takes a parameter that looks like this:

export type Update<T> = { id: EntityId; changes: Partial<T> }

So, you _should_ be dispatching:

dispatch(todoUpdated({id: 1, changes: {todo: "two"}))

I'm disturbed that TS isn't catching that.

@phryneas , do we need to do something similar to the EntityState tweaks to ensure that the user is passing in the right type here? Do any of the other CRUD methods need similar changes?

As a side note, this is a good use case for using upsertOne as it's easier to deal with.

@phryneas , do we need to do something similar to the EntityState tweaks to ensure that the user is passing in the right type here? Do any of the other CRUD methods need similar changes?

That's JavaScript code. You just reached the level of not even considering the possibility of someone using plain JS any more, welcome to my world :rofl:

Oh duh :)

Yeah, @ouweiya : ultimately the issue is you're dispatching a wrong payload, from plain JS, and so it's not getting caught by the TS compiler.

Would be helpful to add the sample code above to the documentation; I only read

In other words, they accept a state that looks like {ids: [], entities: {}}, and calculate and return a new state.

and then wondered for quite a while why I can addOne, but updateOne doesn't seem to do anything. No one to blame but myself of course for not RTFMing - the info is clearly in there; one short piece of sample code IMO would better catch the eye, though...

@dd-ssc yeah, the createEntityAdapter doc page could use some more examples. Could you file a PR that adds some?

Was just about to update my comment above; you beat me to it. Didn't comment there, but you really helped me a lot with your clarification on enhancers / middleware and I'd like to return the favor; as soon as the customer is happy with the next release of the app, I'll try to make time and send a PR.

Was this page helpful?
0 / 5 - 0 ratings