2016-02-10 7 views
24

Ich versuche Tastaturkürzel Unterstützung in meine React/Redux App in einem idiomatischen React/Redux Weg zu bauen. Die Art, wie ich dies zu tun bin die Planung ist die folgende Aktion Schöpfer zu haben und damit verbundene Aktion:Soll ich Funktionsreferenzen in Redux speichern?

registerShortcut(keyCode, actionCreatorFuncReference) 

Das Reduktionsmittel würde dann mit einer Abbildung von keycodes zu actionCreatorFuncReferences ein registeredShortcuts Objekt im redux Speicher aktualisieren. Dann würde meine Root-Komponente auf keyup warten und sehen, ob ein zugehöriger keyCode registriert ist, und wenn dies der Fall ist, dann verschicke die zugeordnete Aktion über die Aktion creator function reference.

Allerdings wäre dies das erste Mal, dass ich bin Speichern von Funktionsreferenzen in meinem Redux-Shop. Bisher hatte ich nur Objekte mit Schlüsseln mit Vanilla-Werten (Strings, Ints, etc).

Die Redux Dokumentation sagt: "Sie sollten Ihr Bestes tun, um den Status serialisierbar zu halten. Legen Sie nichts hinein, was Sie nicht einfach in JSON verwandeln können." Schlägt dies vor, dass es eine schlechte Idee ist, solche Funktionsreferenzen in meinem Redux Store zu speichern? Wenn ja, was ist ein besserer Weg, um das zu erreichen, was ich in React/Redux zu tun versuche? Ein alternativer Ansatz besteht lediglich darin, das Mapping von keyCodes und Funktionsreferenzen in der root-react-Komponente selbst zu speichern, was sich jedoch nicht sehr Redux-ähnlich anfühlt, da sich der Anwendungszustand nicht im Redux-Speicher befindet.

+1

Ich habe mich irgendwie über so etwas selbst gewundert. Während der Redux-Status definitiv serialisierbar sein muss, gibt es andere Dinge, die Sie vielleicht zeitweise behalten möchten (Versprechen, usw.). Ich habe diese Frage in https://github.com/rackt/redux/issues/1385 aufgeworfen - wir werden sehen, ob etwas passiert. – markerikson

Antwort

16

Nein, Sie sollten keine Funktionsreferenzen im Redux-Speicher speichern. Sie sind nicht serialisierbar, und wie Sie erwähnten, sollte der Status jederzeit serialisierbar sein. Der reduxfreundlichste Ansatz, den ich mir vorstellen kann, besteht lediglich darin, die Hotkey-Map auf ihrer actionCreatorFuncNames zu belassen.

+0

Das ist eine interessante Idee. Wie würde ich dann die Funktion tatsächlich aus der Zeichenfolge actionCreatorFuncNames ausführen? –

+1

Ich denke, das hängt von den Details Ihrer Anwendung ab. Es wäre einfach, alle Ihre Aktionen in ein einziges "Aktionen" -Objekt zu importieren, wo immer Sie diese Schlüsselereignisse behandeln. Der schwierige Teil besteht darin, den Knopf zu drücken und 'actions [actionCreatorFuncNameA]' mit den richtigen Argumenten aufzurufen. Auf der anderen Seite, wenn Hotkeys alle sind, müssen Sie keine Argumente aufrufen und das Problem ist gelöst. Macht das Sinn, oder bin ich von der Basis? –

+0

Ich experimentiere mit Proxies. Effektiv würde dies die Objekte serialisierbar machen und gleichzeitig eine Funktionsreferenz haben. – Marc

1

Ich bin neu in redux, aber die Art, wie ich es sehe, könnten Sie den Schlüssel-Code und eine Art von Aktion übergeben. Dann könnte ein Reduzierer auf diesen Aktionstyp warten und entsprechende Änderungen vornehmen.

Hier ist ein Beispiel der Bibliothek Mousetrap mit:

// On your Container 
function registerShortcut(element, dispatch, keyCode, actionType) { 
    Mousetrap(element).bind(keyCode, function(e) { 
    dispatch({ 
     type: actionType, 
     payload: { 
     keyCode: keyCode, 
     event: e 
     } 
    }); 
    }); 
}); 

mapDispatchToProps = function(dispatch) { 
    return { 
    onMount: function(element) { 
     registerShortcut(element, dispatch, ['command+f', 'ctrl+f'], 'OPEN_SEARCH'); 
    }, 
    onUnmount: function(element) { 
     Mousetrap(element).unbind(['command+f', 'ctrl+f']); 
    } 
    }; 
}; 


// On your Component 
componentDidMount() { 
    onMount(ReactDOM.findDOMNode(this)); 
}; 

componentWillUnmount() { 
    onUnmount(ReactDOM.findDOMNode(this)); 
}; 



// On your reducer 
function reducer(oldState, action)  { 
    if (action.type == 'OPEN_SEARCH') { 
    //... make changes ...// 
    return newState; 
    } 
    return oldState; 
}; 

Auf diese Weise Tastenkombinationen werden eine Aktion versenden. Der Reduzierer wird die für den Staat notwendigen Änderungen vornehmen. Und schließlich kann die Anwendung erneut gerendert werden.

0

Ich hatte einige wirklich gute Ergebnisse, Funktionen zu meinem redux Geschäft hinzuzufügen. Wenn Ihre Funktionen als Methoden dienen, die Logik auf die Daten anwenden, kann sie in Ihrer gesamten Anwendung unglaublich leistungsfähig sein (plus JSON.stringify werden die Funktionen ohnehin aussortiert, so dass Sie Ihren Speicher noch serialisieren und im lokalen Speicher speichern können.) Unten Ich habe einen currentUser Reducer, der eine Klasse als Ausgangszustand verwendet und eine hasPermissions-Methode enthält, die überall aufgerufen werden kann, wo der currentUser angeschlossen ist. Das ist besonders schön, denn wenn ich currentUser zu meinen Requisiten mappe, muss ich nicht daran denken, eine Art von util zu importieren, die den Benutzer analysiert, um zu sehen, ob er die Erlaubnis hat, etwas zu sehen. Die Methode ist bereits auf dem Benutzer.

class CurrentUser { 
    constructor() { 
     this.permissions = [] 
     this.roles = [] 
     this.admin = false 
    } 

    hasPermission = (permission) => { 
     if (this.admin) { return true } 
     if (Array.isArray(permission)) { 
     return permission.reduce((prev, curr) => { 
      if (!prev) { return false } 
      if (this.permissions.indexOf(curr) > -1) { return true } 
      return false 
     }, true) 
     } 
     return this.permissions.indexOf(permission) > -1 
    } 
    } 

    const initialState = new CurrentUser() 

    const curretUserReducer = (state = initialState, action) => { 
    const { type, payload } = action 
    switch (type) { 
     case ACTIONS.SET_CURRENT_USER: { 
     const { user } = payload 
     return Object.assign(new CurrentUser(), user) 
     } 
     case ACTIONS.CLEAR_CURRENT_USER: { 
     return new CurrentUser() 
     } 
     case ACTIONS.UPDATE_CURRENT_USER: { 
     const newCurrentUser = merge(state, payload.user) 
     storage.set('currentUser', JSON.stringify(newCurrentUser)) 
     return newCurrentUser 
     } 
     default: 
     return state 
    } 
    } 

    export default curretUserReducer 
Verwandte Themen