我想创建两个React组件。他们需要共享共同的职能。这些函数使用this.setState(),因此我无法将它们放在帮助文件中。我尝试使用composition。这使我可以共享功能,但它们也可以共享状态。

我需要类似的东西

//file 1
var Component1 = React.createClass({
    getInitialState() {
        return {
            //return some common + new states
        }
});

//file 2
var Component2 = React.createClass({
    getInitialState() {
        return {
            //return some common + new states
        }
});

// file 3
// This file needs to have some functions, which can do:
this.setState(); //on state of Component1 and Component2.

最佳答案

您在这里有几个选择。

一家商店

如果这些组件是完全独立的,则可以使用存储来保留和更新每个组件使用的数据,并订阅该存储。这是助焊剂/氧化还原模式。

组件可能看起来像这样

class Component1 extends React.Component {
  constructor(...props) {
    super(...props)
    this.update = this.update.bind(this)
    this.state = { count: 0 }
  }

  update (storeData) {
    this.setState(storeData)
  }

  componentDidMount () {
    store.subscribe(this.update)
  }

  componentDidUnmount () {
    store.unsubscribe(this.update)
  }

  render () {
    return (<span>You have clicked {this.state.count} times</span>)
  }
}

这里要注意的是,存储没有直接访问组件状态的权限。该组件将进行订阅,并且其他一些机制将发布数据。如果发生这种情况,商店将调用注册的回调。一个非常的简单商店可能看起来像这样
const store = {
  subscriptions: new Set(),
  data: {},
  subscribe: function (callback) {
    this.subscriptions.add(callback)
  },
  unsubscribe: function (callback) {
    this.subscriptions.delete(callback)
  },
  update: function (key, value) {
    this.data[key] = value
    this.subscriptions.forEach(cb => cb(this.data))
  }
}

这样,任何有权访问商店的人都可以更新预订的任何/所有组件。
const CounterButton = () => (
  <button onClick={() => store.update('count', (store.data.count || 0) + 1)}>Increase Count</button>
)

这是一个非常contrived codepen的演示

父组件

如果您的组件都是共享组件的子代,则它们的父代可以通过更新其props来更新它们,而不必更新其状态。它可以使用自己的内部状态对此进行跟踪。
class ParentComponent extends React.Component {
  constructor(...props) {
    super(...props)
    this.state = { clicks: 0 }
  }

  render () {
    return (
      <div>
        <button onClick={() => this.setState({ clicks: this.state.clicks + 1})}>Increase Count</button>
        <Component1 clicks={this.state.clicks} />
        <Component2 clicks={this.state.clicks} />
      </div>
    )
  }
}
const Component1 = ({clicks}) => (
  <span>You have clicked {clicks} times</span>
)

const Component2 = (props) => (
  <span>You have pressed {props.clicks} times</span>
)

这是一个equally contrived codepen证明了这一点

疯狂的其他东西

推荐使用上述两种方法。但这是JavaScript,并且我们的规则比荒野西部更少。如果您真的想直接通过某些共享功能控制组件的状态,则没有什么可以阻止您
var sharedComponents = new Set()

function incrementComponents () {
  sharedComponents.forEach(c => c.setState({clicks: c.state.clicks + 1}))
}

class Component1 extends React.Component {
  constructor(...props) {
    super(...props)
    this.state = { clicks: 0 }
    sharedComponents.add(this)
  }

  render () {
    return (<span>You have clicked {this.state.clicks} times</span>)
  }
}

setInterval(incrementComponents, 1000)

这是一个completely insane codepen证明了这一点。

关于javascript - 如何创建共享功能但具有独立状态的React组件?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39219482/

10-11 04:16
查看更多