如何在 React Redux 中实现自包含组件?

     2023-02-23     147

关键词:

【中文标题】如何在 React Redux 中实现自包含组件?【英文标题】:How to implement a self contained component in react redux? 【发布时间】:2016-10-22 11:46:03 【问题描述】:

我正在基于react redux构建一个文件管理器webui(我的目的是通过这个项目掌握react和redux)

如您所知,文件管理器需要一个树浏览器。我想构建一个可以包含它自己并且每个都有自己状态的组件。如下:

TreeNode 也可以包含TreeNode 的子代。每个TreeNode 都保持其状态path, children_nodes, right .....children_nodes 是从服务器获取的,path 是由父代传递的。这就是我的想象。 结构如下:

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

但是麻烦来了,因为reduxconnect存储到树根,根下的所有节点接收到相同的状态...

例如,我有一个OPEN_NODE 动作,旨在触发getFileList fucntion 基于此节点的路径并将此节点的state.open 设置为true。(注意:getFileList fucntion 尚未实现,只需给出暂时的假数据) 屏幕截图:

点击每个元素,但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

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

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

完整代码见我的githubhttps://github.com/eromoe/simple-redux-boilerplate

我没有看到涵盖此类组件的示例,并且谷歌结果没有任何帮助。 有什么办法克服这个问题吗?

更新: 我看到了这个How to manage state in a tree component in reactjs

但解决方案是将整个树传递给状态,不能在文件管理器中使用。

【问题讨论】:

查看 Redux 中的computing derived data。 【参考方案1】:

你所有的TreeNode 与redux 的状态相同,因为你的mapStateToProps 都是相同的。

mapStateToProps 可以将ownProps(被包装组件的props)作为第二个参数。你可以用它来区分你的TreeNodes。在您的情况下,path 是一个不错的选择。

考虑编写像getChildrenNodes(state, path) 这样的状态选择器并相应地返回节点。

您可能需要考虑先阅读 redux 文档,尤其是本节:http://redux.js.org/docs/recipes/ComputingDerivedData.html

【讨论】:

【参考方案2】:

我正在使用 React 和 Redux 实现一个类似 Github 的应用程序。

目前,我只列出存储库并显示其文件以及浏览它们。

我不知道这是一种好的做法还是坏的做法,但这就是我实现 Tree 组件的方式。

在每个树组件中,我都有一个指向自身的链接。而且我在路线上传递了一些数据,所以当我渲染它时我能够得到下一棵树。

组件

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;

完整代码可以查看我的github仓库

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

【讨论】:

React-Native + Redux 将 ID 传递给组件

...:00【问题描述】:我是react-native的新手,最近在我的应用中实现了Redux。该应用程序用于在餐厅点餐:)这是我的餐厅详细信息屏幕的快照,其中包含代表不同菜单的卡片:<Viewstyle=alignItems:\'center\'&g 查看详情

如何在canvas中实现自定义路径动画(代码片段)

...塞尔曲线,因此,这个动画也许是下面这个样子的:那么如何才能在canvas中实现这种动画效果呢?其实很简单,对于路径的处理svg非常在行,因此在canvas中实现自定义路径动画,我们需要借助svg的力量。创建Path制作动画前,先... 查看详情

另一个组件如何在 react/redux 中监听另一个组件的动作?

】另一个组件如何在react/redux中监听另一个组件的动作?【英文标题】:Howdoesanothercomponentlistenfromanothercomponentactionsinreact/redux?【发布时间】:2018-05-1502:18:23【问题描述】:Letsay组件A需要知道另一个组件是否派发了一个action以及le... 查看详情

react-redux:在 API 调用后渲染组件

...,我都会调用API来获取合适的配方成分。但我无法弄清楚如何显示包含配方成分的组件。我也尝试了条件路由和条件渲染,但找不到 查看详情

如何在 React/Redux 中本地管理组件的状态

】如何在React/Redux中本地管理组件的状态【英文标题】:Howlocallymanagingcomponent\'sstateinReact/Redux【发布时间】:2017-04-2013:09:23【问题描述】:我正在做react并且我使用redux。我有点困惑。例如,我有两个按钮,每次单击其中的一个时... 查看详情

如何在 ASP.NET MVC 5 中实现自定义身份验证

】如何在ASP.NETMVC5中实现自定义身份验证【英文标题】:HowtoimplementcustomauthenticationinASP.NETMVC5【发布时间】:2015-10-1314:09:48【问题描述】:我正在开发一个ASP.NETMVC5应用程序。我有一个现有的数据库,我从中创建了我的ADO.NET实体... 查看详情

如何使用 redux 模式在 react native 中刷新组件?

】如何使用redux模式在reactnative中刷新组件?【英文标题】:Howtorefreshcomponentinreactnativeusingreduxpattern?【发布时间】:2018-06-1810:19:13【问题描述】:我正在使用Redux模式,我在状态管理方面遇到了问题。条件:当我使用actonTypes.SUBMIT... 查看详情

如何在 react/redux 应用程序中开玩笑地访问组件的子组件

】如何在react/redux应用程序中开玩笑地访问组件的子组件【英文标题】:Howtoaccesschildofacomponentinjestinareact/reduxapp【发布时间】:2017-12-0814:53:05【问题描述】:我喜欢在Redux应用程序中测试Connect内的组件:this.component=TestUtils.renderInt... 查看详情

如何在 keras 中实现自定义指标?

】如何在keras中实现自定义指标?【英文标题】:howtoimplementcustommetricinkeras?【发布时间】:2016-10-0601:13:54【问题描述】:我得到这个错误:sum()得到了一个意外的关键字参数\'out\'当我运行这段代码时:importpandasaspd,numpyasnpimportkera... 查看详情

如何使用 redux 让根组件在 react-native 中重新渲染(开源项目)

】如何使用redux让根组件在react-native中重新渲染(开源项目)【英文标题】:Howtogetrootcomponenttore-renderinreact-nativewithredux(Opensourceproject)【发布时间】:2018-09-1311:52:47【问题描述】:在使用redux时,如何让React-Native(Expo.io)中的根组件... 查看详情

如何在类组件中使用 react-redux useSelector?

】如何在类组件中使用react-reduxuseSelector?【英文标题】:HowcanIusereact-reduxuseSelectorinclasscomponent?【发布时间】:2019-11-2919:54:39【问题描述】:我是react新手,正在尝试学习redux。我想访问类内的商店,但它给了我一个错误,我不能... 查看详情

找不到 react-redux 上下文值;请确保组件包含在 <Provider> 中,即使它已经包含在提供者中

】找不到react-redux上下文值;请确保组件包含在<Provider>中,即使它已经包含在提供者中【英文标题】:Couldnotfindreact-reduxcontextvalue;pleaseensurethecomponentiswrappedina<Provider>evenifalreadywrappedinaprovider【发布时间】:2021-07-0411:57:43... 查看详情

如何在 iPhone 中实现自定义相机功能? [关闭]

】如何在iPhone中实现自定义相机功能?[关闭]【英文标题】:HowtoimplementcustomcamerafunctionalityiniPhone?[closed]【发布时间】:2011-08-1605:07:13【问题描述】:我想开发一种功能,以便在iPhone应用程序中实现自定义相机功能,所以请给我... 查看详情

如何在 Alamofire 中实现自签名证书?

】如何在Alamofire中实现自签名证书?【英文标题】:HowtoimplementselfsignedcertificatesinAlamofire?【发布时间】:2015-03-0500:56:19【问题描述】:我编写了一个基于swift的应用程序,带有自签名证书服务器通信。作为一个网络库,我想使用A... 查看详情

如何在黄瓜中实现自定义监听器?

】如何在黄瓜中实现自定义监听器?【英文标题】:Howtoimplementcustomlistenersincucumber?【发布时间】:2021-12-2214:55:47【问题描述】:如何在cucumber中实现客户监听?哪个可以记录到控制台/报告失败方法的发生?使用黄瓜4.0注意:钩... 查看详情

如何在 react redux 中添加受保护的路由

】如何在reactredux中添加受保护的路由【英文标题】:Howtoaddprotectedroutesinreactredux【发布时间】:2021-05-1805:23:10【问题描述】:我创建了一个登录组件,其中包含所有逻辑内容。登录reducer是:constopenState=loggedIn:null,user:nullexportdefaul... 查看详情

React:如何从 Redux/Flux 操作访问组件引用?

】React:如何从Redux/Flux操作访问组件引用?【英文标题】:React:HowtoaccesscomponentrefsfromRedux/Fluxactions?【发布时间】:2017-08-0509:54:54【问题描述】:当实现像Redux或MobX这样的状态容器时,你的状态和事件通常被移动到一个单独的类... 查看详情

如何在 Spark SQL(PySpark) 中实现自增

】如何在SparkSQL(PySpark)中实现自增【英文标题】:HowtoimplementautoincrementinsparkSQL(PySpark)【发布时间】:2016-10-2504:20:43【问题描述】:我需要在我的sparksql表中实现一个自动增量列,我该怎么做。请指导我。我正在使用pyspark2.0谢谢卡... 查看详情