2015-11-13 5 views
5

Я все еще очень реагирую/уменьшаю noob. На одной странице у меня тонна текстовых входов. Через некоторое время я начал замечать мой файл действие имеет функции делают то же самое, но для разных входов:Совместное действие и редукторы с реакцией/редукцией

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

С моим Редуктор выглядит как:

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; 
    } 
} 

И мой компонент имел эти несколько входов:

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); 

Это не очень СУХОЙ, и я сразу же подумал, что делаю что-то неправильно. Есть ли хороший способ иметь общее действие setInputValue для всех текстовых входов на каждой странице и компоненте моего приложения? Я также хотел бы использовать общий редуктор для каждого входа. Спасибо.

UPDATE

Вот мой пример валовый, который работает, но я чувствую, что это еще немного запутанное и там должно быть лучшим способом. В основном в редукторе я проверяю, был ли этот вход использован и добавлен в состояние еще. Если нет, добавьте его. Если это так, я просто обновляю его значение. EDIT Я солгал, что на самом деле это не работает.

// 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

Хорошо, вот пример запроса. Скажем, у меня есть модель данных пользователя, это выглядит примерно так:

{ 
    id: 1, 
    name: 'Some Name', 
    email: '[email protected]', 
    age: 21 
} 

Они, как вы в настоящее время его установки вы должны иметь SET_USER_NAME, SET_USER_EMAIL, SET_USER_AGE действия. Не нужно для всех тех, когда вы можете иметь действие UPDATE_USER, которое получает объект обновленных значений в качестве аргумента.

Чтобы установить новое имя для первого пользователя, которого вы назвали бы действие UPDATE_USER как

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

В Пользователями Редуктор вы обновить состояние пользователей (массив пользователей), как

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

Это проясняет ситуацию совсем немного. Что делать, если у меня было несколько несвязанных форм на странице и у меня не было одной конкретной модели? Могу ли я по-прежнему использовать общее действие/редуктор? Без единой gianormous модели для всей страницы. –

+3

Каждая модель должна иметь свой собственный редуктор, который получает свой собственный срез состояния. Однако вы можете использовать одну функцию обновления, которую можно импортировать и использовать в различных редукторах. – slightlytyler

6

Небольшой первый шаг для упрощения кода заключается в использовании редукторов/функций более высокого порядка.

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'); 
+0

Это потрясающе. Определенно, используя это. спасибо –

1

Недавно я придумал такое действие,

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

И correspoding редуктор,

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

    return {...state, controls }; 
    } 
}; 

Это довольно общий характер, и я надеюсь, может служить вам нужно тоже.

0

Для сохранения входа в состояние, вы можете использовать redux-form

Кажется, что ваш вопрос на самом деле не связан с совместным восстановителямом/действий. Для обмена действиями/редукторами я написал один, и вы можете посмотреть redux-conditional

Смежные вопросы