ReactJS - 维护Parent和Child之间的通用模型

时间:2016-11-23 18:26:39

标签: reactjs model-view-controller model state

我的组件视图如下所示。 DataList有多个DataItems,每个DataItem都有一个Header和Body,Header又有一个Expandable部分,带有一个按钮,用于切换相应DataItem的Body的可见性。

DataItem,Header,Expandable,Body是独立的组件,每当点击可扩展按钮时,我都可以通过/解除可扩展的'状态一直到Header& DataItem将一个css类添加到DataItem以显示/隐藏Body部分。

因此,与Expandable一起,即使Header和DataItem也应该可以扩展'状态是多余的,并在组件之间产生紧密耦合。

有没有办法保持公共状态(在MVC中称为Model),可以在ReactJS中的组件中重复使用?

DataList
|
|-DataItem-1
|    |
|    |-Header
|    |   |
|    |   |-Expandable
|    |
|    |-Body
|     
|-DataItem-2
|    |
     |-Header
     |   |
     |   |-Expandable
     |
     |-Body 

2 个答案:

答案 0 :(得分:1)

实际上,您不需要向DataItem添加css类来显示/隐藏Body部分。您可以使用React's Conditional Rendering实现此目的。

如何避免冗余状态?

<强> DataItem.js

import Expandable from './Header';
import Body from './Body';

class DataItem extends React.Component {
    constructor(props) {
        super(props);
        this.state = { showBody: false };
    }

    onExpandableClick = () => {
        this.setState({ showBody: !this.state.showBody });
    }

    render() {
        return (
            <div>
                <Header onExpandableClick={this.onExpandableClick} {...otherHeaderProps} />
                { this.state.showBody && <Body {...bodyProps} />}
                {/* other elements */}
            </div>
        )
    }
}

<强> Header.js

import Expandable from './Expandable';

class Header extends React.Component {
    render() {
        return (
            <div>
                <Expandable onClick={this.props.onExpandableClick} />
                {/* other elements */}
            </div>
        )
    }
}

<强> Expandable.js

class Expandable extends React.Component {
    render() {
        return (
            <div onClick={this.props.onClick}>
                {/* other elements */}
            </div>
        )
    }
}

公共状态(全局存储),MVC中的模型

我们有许多解决方案(状态管理库)来处理我们应用的全局状态。

  • Flux(伟大的老人)
  • Reflux(我不认识他)
  • Redux(我最喜欢的)
  • MobX(新的强大的)
  • ...

谈到我最喜欢的Redux,它将整个应用程序的状态保存在单个不可变状态树(对象)中,不能直接更改。当某些内容发生变化时,会创建一个新对象(使用操作和缩减器)。

Redux因其简单,体积小(仅2 KB)和出色的文档而非常受欢迎。正如Redux的作者所说,

  

&#34; Redux API表面很小。如果删除开发人员警告,   评论和理智检查,它的99行。没有棘手的异步   要调试的代码。&#34;

查找全面的文档here

答案 1 :(得分:0)

永远不要在多个组件状态下复制相同的状态项。这将导致问题,因为它们总是需要手动保持同步。

在这种情况下,我会将展开的属性定义为DataItem本身的属性,而不是正文的属性。这允许您将信息保持在DataItem的状态,并在需要时将其传递下去。不要将信息保留在标题中,而是将回调传递到允许其切换属性的Header组件中。

这可以类似于下面的代码段实现。运行代码段以查看其实际效果!

class App extends React.Component {
  constructor(props) {
    super(props)
    
    this.toggleExpand = this.toggleExpand.bind(this)
    
    this.state = {
      expanded: true
    }
  }
  
  toggleExpand() {
    this.setState({
      expanded: !this.state.expanded
    })
  }
  
  render() {
    return (
      <div>
        <Header toggleExpand={this.toggleExpand} />
        <Body expanded={this.state.expanded} />
      </div>
    )
  }
}

const Header = props => (
  <div id='header'>
    <button onClick={props.toggleExpand}>
      Toggle Expand
    </button>
  </div>
)

const Body = props => (
  props.expanded ?
    <div id='body'>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
    </div>
  : null
)

ReactDOM.render(
  <App />,
  document.getElementById('app')
)
#header, #body {
  border: 1px solid black;
  padding: 5px;
  margin: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id='app'></div>