Typically, when creating a reusable React component that we want to conditionally render, we'll either give it a prop to tell it whether or not to render itself:
function TheComponent(props) {
return(
props.isVisible?<div>...</div>:null
);
}
Or just render the whole component conditionally, from the outside:
function App() {
//...
return (
isVisible ? <TheComponent /> : null
);
}
Alternatively, if we want to make a component that we can show/hide from anywhere in our application - like a toast notification - we could wrap in a provider & make a custom hook to access its context; this would let us show/hide it from anywhere inside the provider, just by calling a function:
const App = () => (
<ToastProvider>
<OtherStuff />
</ToastProvider>
);
const OtherStuff = () => {
const { showToast } = useToast();
showToast();
return ...;
};
However, there's a really cool package, react-toastify, that I can't seem to wrap my head around how it's implemented. All you have to do is drop a <ToastContainer /> somewhere in your app, then from anywhere else, you can:
import { toast } from "react-toastify";
toast.info("this will show the component with a message");
Since this function can be called outside of a provider, I don't really understand how it's controlling the state of the component elsewhere in the tree. I've tried looking into its code, but as a React beginner, it's a bit over my head. I love the idea of a totally self-contained component that you can just stick somewhere in your app, and invoke by calling a function from anywhere. No Provider/wrapper or anything: just a function call, and out it pops.
Can someone help shed some light on how, fundamentally, a component like this could work? How can a function outside of a provider be controlling state inside another component?