Mithril Mithril - 5 months ago 14
Javascript Question

Write `state.tree` instead of `state.xxxReducer.tree` in `mapStateToProps` (react redux)

I have to write

mapStateToProps
like below

function mapStateToProps(state, ownProps) {
return {
node: ownProps.info? state.TreeNodeReducer.tree[ownProps.info.path] : {}
};
}


combine reducer:

import { combineReducers } from 'redux';
import TreeNodeReducer from './TreeNodeReducer'

const rootReducer = combineReducers({
TreeNodeReducer
});

export default rootReducer;


reducers/TreeNodeReducer.js

import { OPEN_NODE, CLOSE_NODE, GET_NODES } from '../constants/NodeActionTypes';

const initialState = {
open: false,
info: {}
}

class NodeModel {
constructor(path, type, right) {
this.name = path;
this.path = path;
this.type = type;
this.right = right;
}
}

let lastId = 0;

function getFileList() {
var testNodes = []
for (var i=0; i< 3; i++) {
testNodes.push(new NodeModel(lastId,'d', i.toString()))
lastId++;
}

return testNodes
}


const getNodes = (state, action) => {
var { path } = action
var tree = state.tree ? state.tree : {}
tree[path] = getFileList(path)
return {
...state,
tree:tree
};
};

export default function (state = initialState, action) {
switch (action.type) {
case OPEN_NODE:
return { ...getNodes(state, action), open:true };
case GET_NODES:
return getNodes(state, action);
case CLOSE_NODE:
return {
...state,
open:false
};
default:
return state;
}
}


because
state.TreeNodeReducer.tree
is a global state, which hold all node info, I want to access it by state directly.State return by a reducer would wrap by the reducer's name, which is not convenient for simple project. Office doc don't provide the way.Any idea?

PS: I have to say I want to keep using
combineReducers
, I see some project not use it, directly pass reducer to store which can achieve my purpose but not good.

Answer

Achieving what you desire depends a bit on the state handled by the TreeNodeReducer.

If that reducer just handles the tree property, like this:

function treeNodeReducer(state = initialState, action) {
  switch (action.type) {
    case SOME_ACTION:
      return Object.assign({}, state, { action.tree: ... })
    default:
      return state
  }
}

I'd say change it to eliminate that tree property and merge it directly with the state, like this:

function treeNodeReducer(state = initialState, action) {
  switch (action.type) {
    case SOME_ACTION:
      return Object.assign({}, state, action.tree)
    default:
      return state
  }
}

This way we can access the tree state in mapStateToProps with state.treeNodeReducer.

But this is still not what we want. We want to rename treeNodeReducer to tree. There are two solutions for that:

  1. Either this:

    import { combineReducers } from 'redux';
    import TreeNodeReducer from './TreeNodeReducer'
    
    const rootReducer = combineReducers({
      tree: TreeNodeReducer
    });
    

    export default rootReducer;

  2. Or this:

    import { combineReducers } from 'redux';
    import tree from './TreeNodeReducer'
    
    const rootReducer = combineReducers({
      tree
    });
    

    export default rootReducer;

This way we can access the tree state in mapStateToProps with state.tree.

Comments