react redux数组嵌套树菜单

时间:2017-10-02 12:03:00

标签: javascript react-redux mutation

我是学习者的开发者,我正在构建一个带有树状菜单的应用程序(react + redux + sagas),但是我遇到了Mutation State的一些错误,我看到了什么是最佳实践尽可能地保持平坦状态,但我没有找到一个菜单树,这是一个平坦的状态,所以我的数据看起来像这样:

menuTree: [{
    id: 'id-root',
    name: 'root',
    toggled: true,
    children: [
        {
            id: 'id-parent1',
            name: 'parent1',
            toggled: true,
            children: [
                { 
                  id: '123',
                  name: 'parent1_child1' 
                },
                { 
                  id: '234',
                  name: 'parent1_child2' 
                }
            ]
        },
        {
            id: 'id-loading-parent',
            name: 'loading parent',
            loading: true,
            children: []
        },
        {
            id: 'id-parent2',
            name: 'parent2',
            toggled: true,
            children: [
                {
                    id: 'parent2_children1',
                    name: 'nested parent2',
                    children: [
                        { 
                          id: '345',
                          name: 'parent2 child 1 nested child 1' 
                        },
                        { 
                          id: '456',
                          name: 'parent2 child 1 nested child 2' 
                        }
                    ]
                }
            ]
        }
    ]
}],

我的还原行动:

case types.SOLUTION__MENUCURSOR__SET:
  // console.log('action payload', action.payload);
  // console.log('state', state);
  const cursor = action.payload.cursor;
  // console.log('set menu cursor action', cursor);
  return { 
    ...state,
    menuTree: state.menuTree.map(
      function buscaIdMenuTree(currentValue, index, arr){
        if(currentValue.id){
          if(currentValue.id.includes(cursor.id)){
            currentValue.toggled = action.payload.toggled;
            return arr;
          }else{
            if(currentValue.children)
            {
              currentValue.children.forEach(function(currentValue, index, arr){
                return buscaIdMenuTree(currentValue,  index, arr);
              });
            }        
          }
          return arr;
        }
      }
    )[0]
  };

代码有效,但我收到Mutation State Error,所以有人可以帮我修复它吗?

1 个答案:

答案 0 :(得分:1)

您可以将菜单重建为普通列表:

let menuTree = [{
    id: 'id-root',
    name: 'root',
    toggled: true,
    parent: null
},{
    id: 'id-parent1',
    name: 'parent1',
    toggled: true,
    parent: 'id-root'
},{ 
    id: '123',
    name: 'parent1_child1',
    parent: 'id-parent1'
},{ 
    id: '234',
    name: 'parent1_child1',
    parent: 'id-parent1'
},
{
    id: 'id-loading-parent',
    name: 'loading parent',
    loading: true,
    parent: 'id-root'
},{
    id: 'id-parent2',
    name: 'parent2',
    toggled: true,
    parent: 'id-root'
},{
    id: 'parent2_children1',
    name: 'nested parent2',
    parent: 'id-parent2'          
},{ 
    id: '345',
    name: 'parent2 child 1 nested child 1',
    parent: 'parent2_children1'
},
{ 
    id: '456',
    name: 'parent2 child 1 nested child 2',
    parent: 'parent2_children1'
}]

然后,如果您的菜单渲染器需要树,您可以将列表转换为树,因此在组件渲染器this.menuTree内部将是树:

const buildTree = (tree, cParent = null) => {
  return tree.filter(cNode => cNode.parent == cParent).reduce((curr, next) => {
    let cNode = {...next, children: buildTree(tree, next.id)}
    delete cNode.parent
    return [...curr, cNode]
  }, [])
}

function mapStateToProps(state) {
  return {
    mapTree: builTree(state.mapTree)
  };
}

export default connect(mapStateToProps)(YourComponent);

现在你需要创建一个需要切换的节点列表,然后相应地映射状态

case types.SOLUTION__MENUCURSOR__SET:
  // console.log('action payload', action.payload);
  // console.log('state', state);
  const cursor = action.payload.cursor;
  // console.log('set menu cursor action', cursor);

  const getToggleList = (tree, cursor) => {
    let target = tree.find(cNode => cNode.id == cursor.id)
    if(target.parent != null){
      let parent = tree.find(cNode => cNode.id == target.parent)
      return [target.parent, ...getToggleList(tree, parent)] 
    }else{
     return [] 
    }
  }

  let toggleList = [cursor.id, ...getToggleList(state.menuTree, cursor.id)]

  return { 
    ...state,
    menuTree: state.menuTree.map(node => ({...node, toggle: toggleList.includes(node.id)}))
  };