React: Singleton React Component

Created on 27 Nov 2015  ·  5Comments  ·  Source: facebook/react

Hey guys!
So in this application I'm writing there's a component called "help section". It's basically a box that shows some predefined texts about the component the user's messing with.

I want to be able to tell my "help section" component which component to show help for. As of now, I'm using Flux with some actions and a store. This isn't too bad and works quite nicely, however it's quite a large setup, with 2 files defined specifically for this cause. There are also a number of other issues that I've experienced such as "help section" actions dispatching because of other actions (which raises a "Cannot dispatch in the middle of a dispatch" error).

However, if I could define "help section" as a singleton, I could just import helpSection from './HelpSection and be done with it, since I'll get the instance of "help section". All I have to do is expose a method on helpSection that sets the properties I want to change and call it.

I know it breaks React's unidirectional data flow, with a component changing another component, but maybe it's worth it sometimes. The way I think about it, it's sort of a combination of a store, some actions and a component into one object. A lot of components will only get instantiated once at run time so maybe it'll be quite useful in some cases.

I couldn't find any reference to this on the web other than in this JSfiddle, which seems to work nicely (It's a bit unclear IMO). Is this a good way to do it?

I'm quite a novice in JavaScript and React so I might be missing some obvious points, hopefully not.
What do you think about this?
Thanks for reading.

(P.S. Sorry for any ambiguousness, English is not my native language... :smile:)

Question

Most helpful comment

Hello @all,

I would like to revive this conversation by adding another point of view. Wir [email protected] it is possible to Mount components into certain points of the DOM by using Portals. For this use case I am building different components like modals or notifications that should be rendered into a certain other component that is mount in my App.jsx like this.

App.jsx

[...]
render() {
  return (<SingletonOverlay></SingletonOverlay>)
}
[...]

Notification.jsx

import React from 'react';
import ReactDOM from 'react-dom';
import NotificationComponent from './Notification.js';
import SingletonOverlay from '../general/Overlay.js';

export default class Notification extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      element: null
    };
  }

  componentDidMount() {
    this.setState({ element: ReactDOM.findDOMNode(SingletonOverlay) });
  }

  render() {
    return this.state.element
      ? ReactDOM.createPortal(
        <NotificationComponent>That is a notification</NotificationComponent>,
        this.state.element,
      )
      : null;
  }
}

The other option would be to find the domNode with document.findElementById or similar functions and pass them to ReactDOM.findDOMNode, which makes me feel very unpleasent as I am forced to leave the "React-Cosmos".

Therefore I would love to be able to search for Instances of a certain Component that I pass to the function, instead of passing the instance itself, for the above mentioned feature. Im also interested in other approaches on how to solve this problem.

@jimfb would this be worth a feature proposal?

All 5 comments

This looks like a usage question, rather than a bug in the React core. Usage questions are better answered on sites like StackOverflow, as we try to use github issues for tracking bugs in the React core. For this reason, I'm going to close out this issue, but feel free to continue the conversation here or move it to StackOverflow.

With regards to your question, my personal recommendation is that you avoid singletons.
http://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons

Thanks for the reply.
Is there already a way to create React components as singletons that I'm not aware of? (I do not trust the JSfiddle until it's evaluated by one of you seniors). If there is, please share it with me, as I couldn't find anything about it in the docs.

From the "Communicate between components" doc page:

For communication between two components that don't have a parent-child relationship, you can set up your own global event system.
...
Flux pattern is one of the possible ways to arrange this.

As you can see, singletons aren't mentioned. In the StackOverflow link you gave, a lot of people actually said that using singletons is useful in some cases. From the second answer:

Singletons solve one (and only one) problem.
Resource Contention.
If you have some resource that
(1) can only have a single instance, and
(2) you need to manage that single instance,
you need a singleton.

This sounds like my use-case (and quite a few more in the React world).

I believe this is still relevant as an issue on GitHub as it seems like a relevant way to use components, and I think the docs should contain a reference to it.

React component instances have internal state that is needed to know where inside a tree that instance is. You can't have the same instance rendered in multiple places. Therefore the idea of singleton instances doesn't make sense in the React world.

What is shown in that fiddle is not really what I would call a singleton mostly because of the single instance argument - it's more like a module with it's own state. Then when an instance is rendered, it uses the enclosed (but really "global") state. It's cheating and storing a reference to the mounted instance in its global state and forcing an update on the mounted instance. Now there's nothing actually stopping you from rendering more of these, which would result in the first one not being updated. You could easily do something similar and support rendering more than 1.

As for us making a reference to this in our docs, we won't do that. There are lots of patterns that could be achieved with React but we're not going to talk about all of them.

Thanks for taking the time to reply, James.
Firstly, I completely understand your points and appreciate the fact that you've taken a look into the JSfiddle. Let me just make a final statement.

  1. What I meant as a "singleton" is an instance of a React component that renders only once throughout the app. That was my starting point. Therefore, the problem you mentioned about the first one not being updated if rendering more than 1 is not so relevant.
  2. I know "contaminating" the global namespace is frowned upon, but as any coding-approach, it has it's place and it's usages. Using Flux for this sort of thing is problematic for a variety of reasons (I struggled with it for a good day or so) and even now the solution I came up with is not so good (The component "chooses" between the props or the store). Using a singleton the way I described can make this a lot easier. I think the benefits outweigh the cons.
  3. You know, with regard to the docs. I've been using React for about 2 months and it's no secret the docs are lacking severely at some points. For me, learning to use React was hard and confusing.
    The docs currently contain 3 sentences about communication between components that do not have a "family" relationship. I understand the variety of patterns available for this sort of thing is obvious to you, but I've only encountered Flux so far.
    Beginners rely heavily on the docs, and maybe listing the possible patterns available to solve all sorts of problems is the exact thing that you should do. We can learn patterns in-depth by ourselves, learning what tool is right for the task is the hard part.

I want to make the things that were hard for me easier. I think it'll be a matter of a few lines and could help beginners in the future.

I always end up writing huge comments.. Thanks for sticking up with me and reading. :smile:

Hello @all,

I would like to revive this conversation by adding another point of view. Wir [email protected] it is possible to Mount components into certain points of the DOM by using Portals. For this use case I am building different components like modals or notifications that should be rendered into a certain other component that is mount in my App.jsx like this.

App.jsx

[...]
render() {
  return (<SingletonOverlay></SingletonOverlay>)
}
[...]

Notification.jsx

import React from 'react';
import ReactDOM from 'react-dom';
import NotificationComponent from './Notification.js';
import SingletonOverlay from '../general/Overlay.js';

export default class Notification extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      element: null
    };
  }

  componentDidMount() {
    this.setState({ element: ReactDOM.findDOMNode(SingletonOverlay) });
  }

  render() {
    return this.state.element
      ? ReactDOM.createPortal(
        <NotificationComponent>That is a notification</NotificationComponent>,
        this.state.element,
      )
      : null;
  }
}

The other option would be to find the domNode with document.findElementById or similar functions and pass them to ReactDOM.findDOMNode, which makes me feel very unpleasent as I am forced to leave the "React-Cosmos".

Therefore I would love to be able to search for Instances of a certain Component that I pass to the function, instead of passing the instance itself, for the above mentioned feature. Im also interested in other approaches on how to solve this problem.

@jimfb would this be worth a feature proposal?

Was this page helpful?
0 / 5 - 0 ratings