2015-11-13 18 views
5

Ich bin immer noch sehr viel eine Reaktion/redux noob. Auf einer Seite habe ich eine Tonne Texteingaben. Nach einer Weile begann zu bemerken, ich meine Aktion Dateifunktionen das gleiche tun haben, aber für verschiedene Eingänge:Gemeinsame Aktionen und Reduzierungen mit react/redux

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

Mit meinem Minderer sieht aus wie:

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

Und meine Komponente hatte diese mehrere Eingänge:

Das ist nicht sehr trocken und ich dachte sofort, dass ich etwas falsch gemacht habe. Gibt es eine gute Möglichkeit, eine gemeinsame setInputValue Aktion für alle Texteingaben auf jeder Seite und Komponente meiner App zu haben? Ich möchte auch einen gemeinsamen Reduzierer für jeden Eingang verwenden. Vielen Dank.

UPDATE

Hier ist mein Brutto Beispiel, das funktioniert, aber ich fühle mich wie das immer noch ein bisschen gewunden ist, und es muss ein besserer Weg sein. Grundsätzlich überprüfe ich im Reduktor, ob dieser Eingang verwendet wurde und dem Zustand noch hinzugefügt wurde. Wenn nicht, füge ich es hinzu. Wenn ja, aktualisiere ich einfach seinen Wert. EDIT Ich habe gelogen dies funktioniert eigentlich nicht.

// 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> 
); 
} 
... 

Antwort

5

Ok hier ist ein Beispiel, wie verlangt. Lassen Sie uns sagen, dass ich ein Benutzerdatenmodell haben, ist es so etwas wie folgt aussieht:

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

momentan Sie, wie Sie es haben Setup Sie SET_USER_NAME haben müssten, SET_USER_EMAIL, SET_USER_AGE Aktionen. Keine Notwendigkeit für alle, wenn Sie eine UPDATE_USER-Aktion haben können, die ein Objekt der aktualisierten Werte als Argument erhält.

Um einen neuen Namen für den ersten Benutzer legen Sie die update_user Aktion wie

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

In den Benutzer Sie den Benutzer Zustand würde aktualisieren Reducer nennen würde (eine Reihe von Benutzern) wie

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

Dies klärt die Dinge ziemlich ein bisschen. Was wäre, wenn ich mehrere nicht verwandte Formulare auf einer Seite hätte und nicht über ein bestimmtes Modell verfügte? Könnte ich immer noch eine gemeinsame Aktion/Reduktion verwenden? Ohne ein gigantisches Modell für die ganze Seite zu haben. –

+3

Jedes Modell sollte sein eigenes Reduzierstück haben, das sein eigenes Stück des Zustands erhält. Du könntest allerdings eine einzige Update-Funktion, die in den verschiedenen Reducern – slightlytyler

6

Ein kleiner erster Schritt zur Vereinfachung des Codes ist die Verwendung von Reduzierern/Funktionen höherer Ordnung.

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

importiert und verwendet werden kann. Das ist genial. Definitiv mit diesem. Vielen Dank –

1

ich kam vor kurzem mit einer solchen Aktion,

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

Und correspoding Minderer,

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

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

Es ist ganz allgemein gehalten ist und ich hoffe, könnte man braucht dienen.

0

Für die Eingabe in dem Zustand speichern, können Sie redux-form

verwenden Es scheint Ihre Frage nicht wirklich zu teilen Reduzierungen/Aktionen in Zusammenhang steht. Zum Teilen von Aktionen/Reduzierungen, schrieb ich eine und Sie können einen Blick redux-conditional

Verwandte Themen