UnstableFractal
UnstableFractal

Reputation: 1422

React.js "global" component that can be created multiple times

I can't get my head wrapped around this.

The problem: let's say there's an app and there can be some sort of notifications/dialogs/etc that i want to create from my code.

I can have "global" component and manage it, but it would limit me to only one notification at a time, this will not fit.

render() {
  <App>
    // Some components...
    <Notification />
  </App>
}

Or i can manage multiple notifications by the component Notification itself. But state management will not be clear.

The other problem if i have some sort of user confirmation from that component (if it's a confirmation dialog instead of simple notification) this will not be very convinient to handle with this solution.

The other solution is to render a component manually. Something like:

notify(props) {
  const wrapper = document.body.appendChild(document.createElement('div'))
  const component = ReactDOM.render(React.createElement(Notification, props), wrapper)
  //...
  // return Promise or component itself
}

So i would call as:

notify({message: '...'})
  .then(...)

or:

notify({message: '...', onConfirm: ...})

This solution seems hacky, i would like to let React handle rendering, and i have an additional needless div. Also, if React API changes, my code breaks.

What is the best practice for this scenario? Maybe i'm missing something completely different?

Upvotes: 0

Views: 509

Answers (1)

Cameron Downer
Cameron Downer

Reputation: 2048

You could use React Context for this.

You create a React context at a high level in your application and then associate a values to it. This should allow components to create / interact with notifications.

export const NotificationContext = React.createContext({
  notifications: [],
  createNotification: () => {}
});

class App extends Component {
  constructor() {
    super();

    this.state = {
      notifications: []
    };

    this.createNotification = this.createNotification.bind(this);
  }

  createNotification(body) {
    this.setState(prevState => ({
      notifications: [body, ...prevState.notifications]
    }));
  }

  render() {
    const { notifications } = this.state;

    const contextValue = {
      notifications,
      createNotification: this.createNotification
    };
    return (
      <NotificationContext.Provider value={contextValue}>
        <NotificationButton />
        {notifications.map(notification => (
          <Notification body={notification} />
        ))}
      </NotificationContext.Provider>
    );
  }
}

The notifications are stored in an array to allow multiple at a time. Currently, this implementation will never delete them but this functionality can be added.

To create a notification, you will use the corresponding context consumer from within the App. I have added a simple implementation here for demonstration purposes.

import { NotificationContext } from "./App.jsx";

const NotificationButton = () => (
  <NotificationContext.Consumer>
    {({ notifications, createNotification }) => (
      <button onClick={() => createNotification(notifications.length)}>
        Add Notification
      </button>
    )}
  </NotificationContext.Consumer>
);

You can view the working example here.

Upvotes: 2

Related Questions