Global State
Global state on the frontend is any value which is useful to access from anywhere in your UI. Commonly this is things like the logged in user, the locale they have set and their role. You could just set javascript variables straight in to your window, except when you do that your UI will not know it needs to redraw when the value changes, and secondly, they don't support emails being rendered on the server where there is effectively multiple global scopes simultaneously.
So, global scope in SocialStack sits on top of React contexts. In short a "provider" sets the value which is then available to all of the child components, and can be obtained using a "consumer". React knows to trigger a redraw if you provide a new value. As it's often useful to have global state simply available to everything, SocialStack will check all modules for an export called Provider. If your .js file exports something called Provider, it will be treated as a root level provider and will get instanced right at the top of the React component tree allowing it to be automatically available to everything in a simple convenient way. A sample of this including the other bits of React context boilerplate is available below.
Common global state - User etc
UI/Session is the component you'll want to import if you would like to consume common global state such as the logged in user. Because of how common it is, whenever you generate a UI component the code comes with a commented out example of how to get hold of the logged in user (if there is one - it can of course be null). The content of this entirely comes from a JSON stringified version of the serverside context, so if you extend the context on the server then your extensions will be available in UI/Session state as well. Here's how to use the state - firstly if you're using React hooks:
import { useSession } from 'UI/Session';
export default function MyComponent(props){
var {session, setSession} = useSession();
// session.user, session.locale and anything else present in serverside Context.
// use setSession to update it - this is typically only when the serverside Context changes
// such as logging in or changing locale. setSession will internally diff for you, so you can set only one field if you want.
// setSession({user: {...}});
}
And if you're using component based React:
import {SessionConsumer} from 'UI/Session';
export default class MyComponent extends React.Component {
constructor(props){
super(props);
}
render(){
return <SessionConsumer>{(session, setSession) => {
// session.user, session.locale and anything else present in serverside Context.
// use setSession to update it - this is typically only when the serverside Context changes
// such as logging in or changing locale. setSession will internally diff for you, so you can set only one field if you want.
// setSession({user: {...}});
}}</SessionConsumer>
}
}
Custom Providers
If you find yourself needing a custom global state slice, it's a good idea to make it as a provider rather than using session/ setSession above. This is primarily to keep UI/Session easy to clear out when someone logs out, but also for performance - lots of smaller slices of state with more specialised consumers will always run better than effectively lots of components redrawing whenever anything in one massive state object changes. Here's a template for creating a provider:
// todo! I typically copy from something like Toast.js in UI/Functions/Toast
// https://github.com/socialstack-core/modules/blob/master/UI/Functions/Toast/Toast.js