2016-06-21 12 views
3

ご存知のように、私は、(私の目的は反応し、このプロジェクトを通じてReduxの習得することである)ファイルマネージャをreactxで自己完結型コンポーネントを実装する方法は?

をReduxのを反応させる上でのファイルマネージャWebUIの基盤を構築していますが、ツリーexplorer.Iが可能なコンポーネントを構築したい必要があります自己を含み、それぞれ自己の状態を持つ。以下のように:

TreeNodeがtoo.Each TreeNodeTreeNodeている子どもたちは、その状態{path, children_nodes, right .....}children_nodesがサーバから取得され保持含めることができ、pathは親によって渡されます。それが私の想像です。 構造体のような:

App: 
TreeNode 
--TreeNode 
----TreeNode 
----TreeNode 
TreeNode 
TreeNode 
--TreeNode 
TreeNode 
--TreeNode 
----TreeNode 
----TreeNode 

しかし、トラブルここに来て、ツリーのルートにReduxのconnect店ので、ルートの下にあるすべてのノードが同じ状態を受け取る...

たとえば、私がOPEN_NODEを持っていますgetFileList fucntionベースこのノードのパスを誘発し、このノードのstate.opentrueに設定するための設計であるアクション、。(注:getFileList fucntionちょうど今の偽のデータを与え、まだ実装していない) スクリーンショット: enter image description here

各要素をクリックします(ただし、states are equal)。

マイコード:

コンテナ/ App.js

import React, { Component, PropTypes } from 'react'; 
import { bindActionCreators } from 'redux'; 
import { connect } from 'react-redux'; 
import Footer from '../components/Footer'; 
import TreeNode from '../containers/TreeNode'; 
import Home from '../containers/Home'; 
import * as NodeActions from '../actions/NodeActions' 

export default class App extends Component { 

    componentWillMount() { 
    // this will update the nodes on state 
    this.props.actions.getNodes(); 
    } 

    render() { 
    const { nodes } = this.props 
    console.log(nodes) 
    return (
     <div className="main-app-container"> 
     <Home /> 
     <div className="main-app-nav">Simple Redux Boilerplate</div> 
     <div> 
      {nodes.map(node => 
      <TreeNode key={node.name} info={node} actions={this.props.actions}/> 
     )} 
     </div> 

     {/*<Footer />*/} 
     </div> 
    ); 
    } 
} 

function mapStateToProps(state) { 
    return { 
    nodes: state.opener.nodes, 
    open: state.opener.open 
    }; 
} 


function mapDispatchToProps(dispatch) { 
    return { 
    actions: bindActionCreators(NodeActions, dispatch) 
    }; 
} 

export default connect(
    mapStateToProps, 
    mapDispatchToProps 
)(App); 

コンテナ/ TreeNode.js

import React, { Component, PropTypes } from 'react' 
import { bindActionCreators } from 'redux' 
import { connect } from 'react-redux' 
import classNames from 'classnames/bind' 
import * as NodeActions from '../actions/NodeActions' 

export default class TreeNode extends Component { 

    constructor(props, context) { 
    super(props, context) 
    this.props = { 
     open: false, 
     nodes: [], 
     info:{} 
    } 
    } 

    handleClick() { 
    let {open} = this.props 
    if (open) { 
     this.props.actions.closeNode() 
    } else { 
     this.props.actions.openNode() 
    } 
    } 

    render() { 
    const { actions, nodes, info } = this.props 
    return (
     <div className={classNames('tree-node', { 'open':this.props.open})} onClick={() => {this.handleClick()} }> 
     <a>{info.name}</a> 
     {nodes && 
      <div>{nodes.map(node => <TreeNode info={node} />)}</div> 
     } 
     {!nodes && 
      <div>no children</div> 
     } 
     </div> 
    ); 
    } 
} 

TreeNode.propTypes = { 
    open:PropTypes.bool, 
    info:PropTypes.object.isRequired, 
    nodes:PropTypes.array, 
    actions: PropTypes.object.isRequired 
} 

アクション/ NodeActions.js

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

export function openNode() { 
    return { 
    type: OPEN_NODE 
    }; 
} 

export function closeNode() { 
    return { 
    type: CLOSE_NODE 
    }; 
} 


export function getNodes() { 
    return { 
    type: GET_NODES 
    }; 
} 

リデューサー/ TreeNodeReducer .js

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

const initialState = { 
    open: false, 
    nodes: [], 
    info: {} 
} 

const testNodes = [ 
    {name:'t1',type:'t1'}, 
    {name:'t2',type:'t2'}, 
    {name:'t3',type:'t3'}, 
] 


function getFileList() { 
    return { 
    nodes: testNodes 
    } 
} 


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

は完全なコードについては、私は例のカバーなどのコンポーネントが表示されていない私のgithubのhttps://github.com/eromoe/simple-redux-boilerplate

見て、Googleの結果は何も役に立ちます。 これを克服する考えですか?

更新: 私はこのHow to manage state in a tree component in reactjs

を参照してくださいしかし、解決策は、ファイルマネージャで使用できない、状態にツリー全体を渡すことです。

+0

ルック(http://redux.js.org/docs/recipes/ComputingDerivedData.html)でRedux。 –

答えて

1

私はReactとReduxを使ってGithubのようなアプリを実装しています。

今のところ、私はリポジトリをリストし、そのファイルを表示し、それらをナビゲートするだけです。

これは良いか悪い習慣とみなされているのか分かりませんが、これが私のTreeコンポーネントを実装した方法です。

各ツリーコンポーネントの内部には、自分自身へのリンクがあります。ルート上にいくつかのデータを渡すので、レンダリングすると次のツリーを取得できます。

App

コンポーネント

class Tree extends Component { 
    constructor(props) { 
    super(props); 

    this.renderList = this.renderList.bind(this); 
    } 

    componentWillMount() { 
    this.props.getTree(this.props.params.sha); 
    } 

    componentWillReceiveProps(nextProps) { 
    if(nextProps.params.sha !== this.props.params.sha) { 
     this.props.getTree(nextProps.params.sha); 
    } 
    } 

    renderList(file) { 
    return (
     <tr key={ file.sha }> 
     { file.type == 'tree' 
     ? <td><Link to={`/repository/${this.props.params.repoName}/tree/${file.path}/${file.sha}`}>{ file.path }</Link></td> 
     : <td><Link to={`/repository/${this.props.params.repoName}/blob/${file.sha}/${file.path}`}>{ file.path }</Link></td>} 
     </tr> 
    ) 
    } 

    render() { 
    const treeFile = this.props.tree; 
    const fileName = this.props.params.path; 

    return (
     <div className="row"> 
     <h3>{ fileName }</h3> 
     <div className="col-md-12"> 
      <table className="table table-hover table-bordered"> 
      <tbody> 
       { isEmpty(treeFile.tree) ? <tr>Loading</tr> : treeFile.tree.map(this.renderList) } 
      </tbody> 
      </table> 
     </div> 
     </div> 
    ) 
    } 
} 
export default Tree; 

アクション

const setTree = (tree) => { 
    return { 
    type: actionTypes.GET_TREE, 
    tree 
    }; 
}; 

export const getTree = (sha) => { 

    return (dispatch, getState) => { 
    const { repository, profile } = getState(); 
    const repo = GitHubApi.getRepo(profile.login, repository.name); 

    repo.getTree(sha, function(err, data) { 
     dispatch(setTree(data)); 
    }); 
    } 
} 

リデューサー

完全なコードについては210
const initialState = ""; 

export const tree = (state = initialState, action) => { 
    switch (action.type) { 
    case actionTypes.GET_TREE: 
     return getTree(state, action); 
    } 
    return state; 
} 

const getTree = (state, action) => { 
    const { tree } = action; 
    return tree; 
} 

、あなたはgithubの

https://github.com/glundgren93/Github-redux

0

の私のリポジトリを確認することができ、それらのすべてのためのあなたのmapStateToPropsが同じであるので、あなたのTreeNodeのすべてが再来から同じ状態を持っています。

mapStateToPropsは、第2のパラメータとしてownProps(包装された成分のprops)を取ることができる。それを使用してTreeNodesを区別することができます。あなたの場合、pathは良い選択です。

このような状態セレクタを作成し、それに応じてノードを返すことを考慮する。

あなたは、最初のReduxのドキュメントを通じて、特にこのseciontを読んで検討することをお勧めします:[コンピューティング派生データ]でhttp://redux.js.org/docs/recipes/ComputingDerivedData.html

関連する問題