joshhunt joshhunt - 1 month ago 9
React JSX Question

Redux: Add value in first reducer and then pass the newly created value to second reducer



Example redux tree with contact Adam in the Friends group:

{
groups: {
1: {
name: "Friends"
contacts: [1]
}
}
contacts: {
1: {
name: "Adam"
}
}
}


Now I would like to create a new contact in the Friends group and the result would be something like:

{
groups: {
1: {
name: "Friends"
contacts: [1, 2]
}
}
contacts: {
1: {
name: "Adam"
},
2: {
name: "Bethany"
}
}
}


Currently I am creating the new contact id before I run the redux action on both reducers. However this feels really messy, is there a better way to go about doing this? My current code is below:

contact.js

import { connect } from 'react-redux';

function Contact({ createContact, groupId, newContactId }) {
function onContactCreate(name) {
createContact(newContactId, groupId, name);
}
// ...
}

const mapStateToProps = (state) => {
return {
newContactId: state.get('contacts').size + 1
};
};

export function mapDispatchToProps(dispatch) {
return {
createContact: (newContactId, groupId, name) => dispatch({
type: 'CREATE_CONTACT',
newContactId,
groupId,
name
})
};
}

export default connect(mapStateToProps, mapDispatchToProps)(Contact);


contact-reducer.js

import { fromJS } from 'immutable';

const initialState = fromJS({});

function contactReducer(state = initialState, action) {
switch (action.type) {
case 'CREATE_CONTACT': {
return state
.set(action.id, fromJS({
name: action.name
}));
}
default:
return state;
}
}

export default contactReducer;


group-reducer.js

import { fromJS } from 'immutable';

const initialState = fromJS({});

function groupReducer(state = initialState, action) {
switch (action.type) {
case 'CREATE_CONTACT': {
let id = action.groupId;
return state
.updateIn([id, 'contacts'], (contacts) => contacts.push(action.id));
}
default:
return state;
}
}

export default groupReducer;

DDS DDS
Answer

You do indeed have to create the ID before you dispatch the action. The ID shouldn't depend on the current state. If you use time travel or Redux Dev tools to edit history, the same action could create an item with a different ID. This would lead subsequent actions to use the incorrect ID.

In general, the identity of an object should be bound to the object and not created separately.