Combined actions and gears with reaction / reduction

I am still reacting very strongly / reducing noob. On one page I have a ton of text inputs. After a while, I began to notice that my action file has functions that perform the same thing, but for different inputs:

export function setInputName(string) { return { type: 'SET_CURRENT_NAME', payload: {value: string} }; } export function setInputCity(string) { return { type: 'SET_CURRENT_CITY', payload: {value: string} }; } 

With my gearbox it looks like:

 export function currentName(state='', {type, payload}) { switch (type) { case 'SET_CURRENT_NAME': return payload.value; default: return state; } } export function currentCity(state='', {type, payload}) { switch (type) { case 'SET_CURRENT_CITY': return payload.value; default: return state; } } 

And my component had these multiple inputs:

 import {Component, PropTypes} from 'react'; import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; import {setInputName, setInputCity} from 'actions/form'; export default class Form extends Component { static propTypes = { setInputName: PropTypes.func.isRequired, setInputCity: PropTypes.func.isRequired, currentName: PropTypes.string.isRequired, currentCity: PropTypes.string.isRequired } render() { let {setInputName, setInputCity, currentName, currentCity} = this.props; return ( <div> <input type="text" placeholder="Name" onChange={(e) => setInputName(e.currentTarget.value)} value={currentName} /> <input type="text" placeholder="City" onChange={(e) => setInputCity(e.currentTarget.value)} value={currentCity} /> </div> ); } } function select(state) { return { currentName: state.form.currentName, currentCity: state.form.currentCity }; } function actions(dispatch) { return bindActionCreators({ setInputName: setInputName, setInputCity: setInputCity, }, dispatch); } export default connect(select, actions)(Form); 

This is not very DRY, and I immediately thought that I was doing something wrong. Is there a good way to have a common setInputValue action for all text inputs on every page and component of my application? I would also like to use a common gearbox for each input. Thanks.

UPDATE

Here is my rude example that works, but I feel this is still a bit confusing and there should be a better way. Basically in the gearbox I check if this input has been used and added to the state yet. If not, add it. If so, I just update its value. EDIT I lied that this really didn't work.

 // actions export function updateTextInput(name, value) { return { type: 'SET_CURRENT_TEXT_INPUT', payload: {name: name, value: value} }; } // reducer export function currentTextInput(state=[], {type, payload}) { switch (type) { case 'SET_CURRENT_TEXT_INPUT': let newState = state; let curInput = state.findIndex(function(elem) { return elem.name === payload.name; }); if (curInput === -1) { newState.push({name: payload.name, value: payload.value}); } else { newState[curInput].value = payload.value; } return newState; default: return state; } } // component ... render() { let {updateTextInput, currentTextInput} = this.props; return ( <div> <input type="text" placeholder="Name" onChange={(e) => updateTextInput('name', e.currentTarget.value)} value={currentTextInput.name} /> <input type="text" placeholder="City" onChange={(e) => updateTextInput('city', e.currentTarget.value)} value={currentTextInput.city} /> </div> ); } ... 
+5
source share
4 answers

Well here is an example as requested. Say I have a user data model, it looks something like this:

 { id: 1, name: 'Some Name', email: ' someemail@some.com ', age: 21 } 

In accordance with how you are setting the setting now, you will need to have the SET_USER_NAME, SET_USER_EMAIL, SET_USER_AGE commands. There is no need for cases where you can have an UPDATE_USER action that takes an updated value object as an argument.

To set a new name for the first user, you must call the UPDATE_USER action, for example

updateUser(1, { name: 'New Name' })

In the Users reducer, you update the status of users (an array of users), for example

 function updateUser(usersState, id, attrs) { return usersState.map(user => user.id === id ? Object.assign({}, user, attrs) : user ); } 
+5
source

A small first step to simplify the code is to use higher order reducers / functions.

 function makePropReducer(actionType, prop) { return (state = '', {type, payload}) => { if (type === actionType) { return payload[prop]; } return state; }; } export const currentName = makePropReducer('SET_CURRENT_NAME', 'value'); export const currentCity = makePropReducer('SET_CURRENT_CITY', 'value'); 
+6
source

I recently came up with such an action,

 export function controlStateChange(controlName, propertyName, value) { return { type: 'CONTROL_STATE_CHANGE', payload: { controlName, propertyName, value } }; } 

And correlation corrector,

 const actionHandlers = { 'CONTROL_STATE_CHANGE': (state, payload) => { const controls = { [payload.controlName]: { [payload.propertyName]: payload.value } }; return {...state, controls }; } }; 

This is pretty general, and I hope it also serves you.

+1
source

To save input to state you can use redux-form

It seems your question is not related to gear / action division. For the exchange of actions / reducers, I wrote one, and you can look at redux-conditional

0
source

Source: https://habr.com/ru/post/1235922/


All Articles