Javascript 如何在react redux中实现自包含组件?
我正在基于react-redux构建一个文件管理器webui(我的目的是通过这个项目掌握react和redux) 正如您所知,文件管理器需要一个树资源管理器。我想构建一个组件,该组件可以包含它自己,并且每个组件都有自己的状态。如下图所示:Javascript 如何在react redux中实现自包含组件?,javascript,reactjs,components,redux,react-redux,Javascript,Reactjs,Components,Redux,React Redux,我正在基于react-redux构建一个文件管理器webui(我的目的是通过这个项目掌握react和redux) 正如您所知,文件管理器需要一个树资源管理器。我想构建一个组件,该组件可以包含它自己,并且每个组件都有自己的状态。如下图所示: TreeNode也可以包含TreeNode的子节点。每个TreeNode保持其状态{path,children\u nodes,right….},子节点从服务器获取,路径由父节点传递。这就是我的想象。 类似结构: App: TreeNode --TreeNod
TreeNode
也可以包含TreeNode
的子节点。每个TreeNode
保持其状态{path,children\u nodes,right….}
,子节点
从服务器获取,路径
由父节点传递。这就是我的想象。
类似结构:
App:
TreeNode
--TreeNode
----TreeNode
----TreeNode
TreeNode
TreeNode
--TreeNode
TreeNode
--TreeNode
----TreeNode
----TreeNode
但麻烦来了,因为redux
connect
存储到树根,根下的所有节点都接收相同的状态
例如,我有一个OPEN\u节点
操作,它被设计为触发getFileList函数
基于此节点的路径并设置此节点的状态。OPEN
为true
(注意:getFileList函数
尚未实现,现在只需提供假数据)
屏幕截图:
单击每个元素,但状态是相等的
我的代码:
容器/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);
减速器/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;
}
}
有关完整的代码,请参阅MyGitHub
我没有看到一个例子涵盖这样的组件,谷歌结果没有任何帮助。
有什么办法克服这个问题吗
更新:
我看到了
但解决方案是将整个树传递到状态,不能在文件管理器中使用。我正在使用React和Redux实现一个类似Github的应用程序 目前,我只列出存储库并显示其文件以及浏览它们 我不知道这是一个好的还是坏的做法,但这就是我如何实现我的树组件 在每个树组件中,我都有一个指向自身的链接。我在路径上传递了一些数据,这样我就能在渲染下一棵树时得到它 组件
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 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上查看我的存储库
所有
TreeNode
的redux状态相同,因为它们的MapStateTrops
都相同
mapstatetops
可以将ownProps
(包装组件的props
)作为第二个参数。您可以使用它来区分树节点
。在您的情况下,path
是一个很好的选择
考虑编写这样的状态选择器getChildrenNodes(state,path)
,并相应地返回节点
<>你可能想先阅读ReDox文档,特别是这个SeiNo: 在ReDux中查看。
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));
});
}
}
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;
}