Should I store function references in Redux store?

后端 未结 3 1230
悲哀的现实
悲哀的现实 2020-12-03 06:50

I\'m trying to build keyboard shortcut support into my React/Redux app in an idiomatic React/Redux way. The way I am planning to do this is

相关标签:
3条回答
  • 2020-12-03 06:57

    No, you should not store function references in the redux store. They are not serializable, and as you mentioned state should be serializable at all time. The most redux friendly approach I can think of is just to keep the map of hotkeys to their actionCreatorFuncNames.

    0 讨论(0)
  • 2020-12-03 07:06

    I'm new to redux, but the way I see it, you could pass the key code and an action type. Then a reducer could be listening for that action type and make changes accordingly.

    Here is an example using the library Mousetrap:

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

    This way, keyboard shortcuts will dispatch an action. The reducer will make the changes necessary to the state. And finally, the application can re-render.

    0 讨论(0)
  • 2020-12-03 07:13

    TL;DR: You don't. The store state must be serializable at all times (as Nathan answered). The Redux way is via enhancers, or the Redux-Observable way via dependencies.

    NL;PR: Based on the Redux docs example, what you want is to pass the reference in your action(1), ignore it your reducer(2) and use it in your enhancer(3):

        //... in your action:
        const data={val:1}, ref=()=>{};
        const action = {type:'ACTION_WITH_REF', data, ref}; //(1)
    
        //... in your reducer:
           case 'ACTION_WITH_REF':
           return {...state, data: action.data}; //(2)
    
        //... and in your enhancer:
        import { createStore, applyMiddleware } from 'redux';
        import reducers from './reducers';
        export const myRefStore= {};
         
        function refHandler({ getState }) {
          return next => action => {
            switch(action.type){ 
               // this can be done more elegantly with a redux-observable
               case 'ACTION_WITH_REF':
                 myRefStore.aRef = action.ref; // (3)
                 break;
             }
            // be sure to maintain the chain of the store
            const returnValue = next(action);   
            // otherwise, your miffffdeware will break the store
            return returnValue;
          };
        } 
    
        const store = createStore(
          reducers,
          initialState,
          applyMiddleware(refHandler)
        );
    

    Note: As far as there are no side-effects in your enhancers, you are good to go. Be aware that you could have obtained the refs directly in the reducers, but such an approach keeps the reference at the reducer-level and misses the point of combineReducers(). With an enhancer, you keep them all in one place(myRefStore).

    One final observation is that a redux store is not an any-data store but a state store, thus why we need to handle functions and other non-state related stuff in enhancers. You can leverage the enhancer backbone to Redux-Observable and inject myRefStore via dependencies.

    0 讨论(0)
提交回复
热议问题