简体   繁体   English

如何创建共享功能但具有独立状态的反应组件?

[英]How to create react components which share functions but have independent state?

I want to create two React component. 我想创建两个React组件。 They need to share common functions. 他们需要分享共同的功能。 These functions uses this.setState() , so I could not put them inside a helper file. 这些函数使用this.setState() ,所以我无法将它们放在辅助文件中。 I tried using composition . 我尝试过使用composition This enable me to share functions but they also share state. 这使我能够共享功能,但他们也共享状态。

I need something like 我需要类似的东西

//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.

You have a couple options here. 你有两个选择。

A store 一家商店

If these components are completely independent, you can use a store to keep and update the data that each component uses, and subscribe to the store. 如果这些组件完全独立,则可以使用存储来保留和更新每个组件使用的数据,并订阅该存储。 This is the Flux/Redux pattern. 这是Flux / Redux模式。

A component might look like this 组件可能看起来像这样

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>)
  }
}

The thing to note here is that the store doesn't have direct access to the component's state. 这里要注意的是商店没有直接访问组件的状态。 The component subscribes, and some other mechanism will publish data. 组件订阅,其他一些机制将发布数据。 The store will call the registered callback will this happens. 如果发生这种情况,商店将调用已注册的回调。 A very simple store might look like this 一个非常简单的商店可能看起来像这样

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))
  }
}

This allows anyone with access to the store to update any/all components that are subscribed to it. 这允许任何有权访问商店的人更新订阅它的任何/所有组件。

const CounterButton = () => (
  <button onClick={() => store.update('count', (store.data.count || 0) + 1)}>Increase Count</button>
)

Here is a very contrived codepen demonstrating this 这是一个非常人为的代码库,展示了这一点

Parent Component 父组件

If your components are both children of a shared component, then their parent can update them by updating their props , instead of updating their state. 如果您的组件都是共享组件的子组件,那么他们的父组件可以通过更新其props来更新它们,而不是更新它们的状态。 It can keep track of this using its own, internal state. 它可以使用自己的内部状态跟踪它。

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>
)

Here is an equally contrived codepen demonstrating this 这是一个同样做作的代码笔,展示了这一点

Something insane else 别的东西疯了

The above two are the recommended way to go. 以上两种是推荐的方式。 But this is JavaScript, and we have less rules than the Wild West. 但这是JavaScript,我们的规则比Wild West少。 If you really want to directly control the state of components from some shared function, there is nothing stopping you . 如果你真的想直接控制来自某个共享函数的组件状态,那么没有什么可以阻止你

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)

Here is a completely insane codepen demonstrating this. 这是一个完全疯狂的codepen来证明这一点。

Keeping the both Component1 & Component2 under a Parent component , and if you pass the parent component function to the child component then both Component1 & Component2 will have the Parent Component functions as a props . Component1Component2保持在Parent component ,如果将父组件函数传递给子组件,则Component1Component2都将使用Parent Component函数作为props so you get your common function like this way as react component works in a parent-child relationship . 因此,您可以通过这种方式获得common功能,因为反应组件在parent-child relationship起作用。 children's can get the data from their parent. 孩子们可以从他们的父母那里获得数据。 and this way all your child component have their own state too. 这样你的所有子组件也都有自己的状态。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM