React组件接口与方法

时间:2017-06-06 19:12:40

标签: reactjs design-patterns interface

问:有没有办法提供一个接口来访问给定可重用组件的公共方法?

场景:想象一下,我正在建立一个Tabs组件。它位于父组件内,名为App

<App>
    <Tabs />
    <button id="previous">Previous</button>
    <button id="next">Next</button>
</App>

正如您所看到的,有两个按钮可以与Tabs组件进行交互,将其移动到上一个或下一个选项卡窗格。

我的实施包括将next()previous()方法保留在Tabs组件中:

export default class Tabs extends React.Component {
    next() {}
    previous() {}
}

问:如何将next()previous()方法绑定到App组件中的那些按钮?我可以编写Tabs组件公开的某种界面吗?什么是最佳干净方式?

编辑1 :...

编辑2 Tabs是一个“可重复使用”的组件。许多应用程序可以将其呈现在内

3 个答案:

答案 0 :(得分:2)

您可以在父组件

中获得ref到Tabs实例
class Root extends Component {

  render() {
   return (
    <App>
      <Tabs ref={ref => this.tabs = ref} />
      <button id="previous" onClick={() => this.tabs.prev()}>Previous</button>
      <button id="next" onClick={() => this.tabs.next()}>Next</button>
   </App>
   )
  }
}

或者更合理的方法是切换到一些集中的状态管理解决方案说Flux。看看Redux:)。

答案 1 :(得分:2)

正如其他人所说,按钮位于Tabs组件之外是没有意义的。

我看到您的代码示例的方式,您的App组件应该是您的Tabs组件,我认为您的Tabs组件代表某种TabsView

<强> app.js

import Tabs from './components/tabs';

<App>
  <Tabs/>
</App>

<强> tabs.js

class TabsView extends Component {
  constructor(props){
    super(props);
  }
  render(){
    return(
      <span>{this.props.currentTab}</span>
    );
  }
}

class Tabs extends Component {
  constructor(props){
    super(props);
    this.state = {
      currentTab: 0
    }
  }
  handleOnClickPrev(){
    this.setState({currentTab: currentTab--});
  }
  handleOnClickNext(){
    this.setState({currentTab: currentTab++});
  }

  render(){
    return(
      <div>
        <TabsView currentTab={this.state.currentTab}/>
        <button id="prev" onClick={handleOnClickPrev.bind(this)}>-</button>
        <button id="next" onClick={handleOnClickNext.bind(this)}>+</button>
      </div>
    );
  }
}

export default Tabs;

这样,组件的所有功能都存在于其中。 Tabs组件现在具有所需的所有信息。您使用的每个Tabs组件都有自己的状态和标签。如果您希望currentTab状态来自App,以便您可以在其他位置呈现相同的currentTab,则可以将其作为道具从App组件传递。

<强> app.js

<App>
  <Tabs currentTab={this.state.currentTab} handlePrev={} handleNext={}/>
</App>

<强> tabs.js

class Tabs extends Component {
  constructor(props){
    super(props);
  }

  render(){
    return(
      <div>
        <TabsView currentTab={this.props.currentTab}/>
        <button id="prev" onClick={this.props.handlePrev}>-</button>
        <button id="next" onClick={this.props.handleNext}>+</button>
      </div>
    );
  }
}

export default Tabs;

如果您希望在某些位置显示标签而不是其他位置的按钮,则可以使用TabsView组件使用传递给Tabs组件的相同支柱。

<强> app.js

<App>
  <Tabs currentTab={this.state.currentTab} handlePrev={} handleNext={}/>
  <TabsView currentTab={this.state.currentTab} />
</App>

如果您对组件的控件生活在与组件本身不同的位置,那么我会建议将相同的道具传递给TabsView和按钮。

<强> app.js

handlePrev() {
  this.setState({ currentTab: this.state.currentTab - 1 })
}
handleNext(){
  ...
}
render(){
  return (
    <App>
      <TabsView currentTab={this.state.currentTab} />
      <button id="prev" onClick={this.handlePrev.bind(this)}>-</button>
      <button id="next" onClick={this.handleNext.bind(this)}>+</button>
    </App>
  )
}

我认为此时引入Redux或任何其他状态库是不合理的。仅为您的标签组件管理全局状态是过度的。

答案 2 :(得分:1)

如果您的按钮作用于Tab组件的元素,则它们应位于此组件内。然后,您可以使用state的{​​{1}}支柱轻松更改组件的onPress

如果您仍希望将按钮保留在组件之外(即使我没有明确说明的原因),那么您应该考虑使用像Button这样的商店在整个组件中保持“全局”状态。