Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multiple nested Contexts #115

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

jesstelford
Copy link
Contributor

@jesstelford jesstelford commented Jun 12, 2020

NOTE: PR best viewed with whitespace changes hidden

From the updated docs:

Displaying individual toasts differently is done using nested <ToastProvider>s.

For example, the docs page displays both "notification" style & "snack bar" style toasts simultaneously on the same page.

Nested Providers must be given a unique name prop, which is then also passed to the <ToastConsumer> component or useToasts() hook.

import { ToastProvider, ToastConsumer } from 'react-toast-notifications';
const App = () => (
  <ToastProvider>
    <ToastProvider name="snack">
      <ToastConsumer>
        {({ add }) => <button onClick={() => add('A toast')}>Add Toast</button>}
      </ToastConsumer>
      <ToastConsumer name="snack">
        {({ add }) => <button onClick={() => add('A snack')}>Add Snack</button>}
      </ToastConsumer>
    </ToastProvider>
  </ToastProvider>
);

@@ -151,7 +166,7 @@ export class ToastProvider extends Component<Props, State> {
this.setState(state => {
const old = state.toasts;
const i = old.findIndex(t => t.id === id);
const updatedToast = { ...old[i], ...options };
const updatedToast = { ...old[i], ...omit(options, 'id') };
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These id changes fix some flow errors I was getting.

super(props);

contexts[props.name] = contexts[props.name] || React.createContext();
const context = contexts[props.name];
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only create a new context if there isn't already one for that name.

Then we continue using the created context within this component for its lifetime.

<Consumer>{context => children(context)}</Consumer>
);
export const ToastConsumer = ({
name = DEFAULT_CONTEXT_NAME,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each of the 3 ways of consuming toast context (<ToastConsumer>, withToastManager(), and useToasts()) now all accept an optional name prop.

That name is used to lookup a context created by a provider.

If the named context isn't known, then an error is thrown. Otherwise, that named context is the one used for the life of the component.

In this way, any deeply nested consumers can connect to any parent provider no matter how many they are as long as they have unique names.

@@ -25,5 +26,5 @@ export type Placement =
| 'top-center'
| 'top-right';

export type ToastType = Options & { appearance: AppearanceTypes, content: Node, id: Id };
export type ToastType = { content: Node, id: Id } & Options;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fixes a flow issue I was having where it thought id was optional on internal state.

@jesstelford
Copy link
Contributor Author

I've published the changes in this PR as @jesstelford/[email protected] to try it out:

yarn add @jesstelford/[email protected]

@soosap
Copy link

soosap commented Nov 10, 2020

I have tested the PR by @jesstelford! It works like a charm thank you. Please merge!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants