Checking if posthog has been initialized - reactjs

Is there a legit way to check if Posthog has been initialised somewhere in the app?
My NextJS application structure is like that:
_app.tsx -> posthog init inside useEffect
MyComponent-> event capture
My event capture from MyComponent is being initialised before posthog init from _app.tsx and thats why I am not able to record that event. I am just missing those events.
Any hints would be appreciate.
I am also wondering if I place two init functions, one in _app.tsx and one inside MyComponent, would that be a problem?
I would use the same keys and everything. Would I end with two different instances of posthog?

Related

How to prevent refresh of list over API after drag & drop with beautiful DND?

I simulated my Context + DND problem in https://codesandbox.io/s/adoring-booth-33vqo . I have other components which will be added to this example and I will use a Context hook to share values across the page.
After the initial render, everything looks fine. The idea of the list is to change the order within itself and when ones changes the order with drag-drop, it throws an "Invalid Hook" error.
So the (first) real question is, what is triggering this error which is linked to the line
const { lang1Library, updateLang1Library } = useContext(LangContext)
;
Thanks in advance for your help.
Geo
It's not a good approach to provide a link for the whole project even if it is small. But I had a quick look and there's at least one thing you're doing wrong:
// DragEndFct.js
export default function DragEndFct(result, libName) {
const { lang1Library, updateLang1Library } = useContext(LangContext);
This is not React component, but it uses a hook - and it is wrong. Hooks have a special meaning in React and should be used properly (Rules of Hooks).
You can't use hooks inside regular functions and expect them to work. That is why you are getting that error.
So, there are many ways you can try to fix this. For instance, DragEndFct is a regular function, you can declare more arguments and pass stuff you get from context:
// you are using it in components right ?
function DragEndFct(result, libName, param3, param4) {}
// so you probably have access to the context there
// and can pass data from the context when you call it.
// something like this
onDragEnd={function (result) {
console.log();
DragEndFct(result, StaticVars.LANG1_LIBRARY_NAME, lang1Library, updateLang1Library);
}}
You could even make DragEndFct to be a React component - it can just return null (which means no UI will be rendered) but in that case you will have hooks and all other stuff there. It really depends on what you need and how you will use it.

React hook - Can I use common variable out of function(hook) or Is it anti-pattern?

I recently use react hook well. however sometime I wonder my coding style is okay.
let mDown = false;
let timerId = null;
function App() {
useEffect(() => {
mDown = true
....
}, [])
}
Like bottom code, I declare variable out of function. and I want to use common variable and access, change this value without using state.
Is it anti-pattern?
Thanks to read. :)
yes, of course. you can use the common variable in not only the hook function, but also any other methods of the App.
however the best practice is to make the global variables in other js files like constant.js, and import them in the above of the file.
import { mDown, timerId } from '../constant'
So let's think in terms of components. I mean, let's ignore for a while there barely will be more than one <App /> but think about component-centric approach in general.
Do you mean some data independent for each component's instance? Then you use useState(if changing this data should re-render component) or useRef(if updating this should never trigger re-rendering).
Or should that data be shared among all the components? Then, again it depends. Sometimes global variable is fine(real global variable, as a property on window object), sometimes better to put it into Context API or any state management layer(Mobx, Redux) instead.
Why don't have module-level variable as you aer going to? I see multiple reasons(again, maybe not big deal for exact case with <App />):
Module-level variable sticks to module instance. If we you ever end with multiple version of the same component in the same application, they will have own instances of such a variable. Think of <Dropdown /> component and some variable made to collapse all other instances once some is expanded. In case with module-level variable you may end some dropdown closes some instances - but not all - just if you got few versions of the same package used(like coming as 2nd level dependency)
No access, and no isolation - hard to unit-test.
And finally: what could be a profit here?

Global es6 module to store constants in react app - prevent garbage collection

I would like to store some variables inside a module (export) to be used as constants though out my react app. I would like to avoid context because there is no need for components to re-render and also I need those constants to be used outside my react components.
Where should I do it (where to import it), in order to prevent garbage collection?
One idea I have is to import and re-export it on top of my root component.
EDIT:
To be more precise, there will be a component that will set the constant once (mutate the variable), so that other components or files can access it.
So, what you will need is some sort of setter/getter pattern. Though I mostly don't recommend it unless you know what you are doing, because React won't re-render if the variable changes and because of that you need to be sure the variable is set before it is used.
You should have something like the example below in order for it to work the way you want. You can find an example of it working on this Codesandbox.
export let MY_VARIABLE = "";
export const setMyVariable = value => (MY_VARIABLE = value);
PS: I've added some console.log to the code in order for you to see how the import/get/set behaves.
After digging more into this I found that es6 module spec states:
When import your module it gets loaded => parsed => evaluated and cached (singleton). It also says that when you import modules its value is passed by reference (aka assignment). I didn't find anything mentioning when or how es6 modules are unloaded from that cache.
So that means, when you import a module once, it is there for as long as the program is running, and all modules access its values directly.
reference
https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/
https://medium.com/#mivanichok/understanding-es6-modules-in-depth-article-b49612926e39
You can create an config.js inside src folder and write the your constant variable like
//config.js
module.exports = {
CONST_VAR : 'const value',
}
import config.js in your component and use it

Is it necessary to call `unmountComponentAtNode` if the component's container is removed?

I render a React component SettingsTab within a wrapper called TeamView. Its API looks something like
class TeamView {
constructor() {
this.el = document.createElement('div');
}
render() {
ReactDOM.render(<SettingsTab/>, this.el);
return this;
}
remove() {
this.el.remove();
}
}
used something like
// to present the team view
const teamView = new TeamView();
document.body.appendChild(teamView.render().el);
// to remove the team view
teamView.remove();
And what I'm wondering is, should TeamView#remove call ReactDOM. unmountComponentAtNode(this.el) before calling this.el.remove()?
The examples I can find around the web make it seem like unmountComponentAtNode only needs to be called if the container is going to remain in the DOM; and the new portals example just removes the container, without calling unmountComponentAtNode.
But, I'm not sure if that's special because it's using a portal, and this post makes it kind of seem like it's always good practice to call unmountComponentAtNode.
Yes, it is important to call unmountComponentAtNode() because if you don't do this, none of the components below in the tree will know they have been unmounted.
User-defined components often do something in componentDidMount that creates a reference to the tree from the global environment. For example, you may add a window event handler (which isn't managed by React), a Redux store subscription, a setInterval call, etc. All of this is fine and normal as long as these bindings are removed in componentWillUnmount.
However, if you just remove the root from the DOM but never call unmountComponentAtNode, React will have no idea the components in that tree need to be unmounted. Since their componentWillUnmount never fires, those subscriptions stay, and prevent the whole tree from getting garbage collected.
So for all practical purposes you should always unmount the root if you're going to remove that container node. Otherwise you'll most likely get a memory leakā€”if not now, then later when some of your components (potentially deep in the tree, maybe even from third-party libraries) add subscriptions in their componentDidMount.
Even though you called this.el.remove(), you should still call the unmountComponentAtNode(this.el) because unmountComponentAtNode will clean up its event handlers and state, but the remove method will not.
For example, Eventhough you have clicked to remove the div, you can still call it's click event handlers:
var tap = document.querySelector('.tap');
var other = document.querySelector('.other');
tap.addEventListener('click', function(e) {
console.log(tap.getAttribute('data-name') + ' has been clicked');
tap.remove();
});
other.addEventListener('click', function(e) {
tap.click();
});
<div class="tap" data-name="tap">First Click me to remove me</div>
<div class="other">Then Click me </div>
I asked this question in the #react-internals Discord channel and received the following response:
So, this tallies with what #jiangangxiong says above: as long as we
don't keep our own references to component DOM elements
nor attach event handlers outside of React
and only need to support modern browsers
we should only need to remove the container to have the component's event handlers and state garbage collected, no need to call unmountComponentAtNode.

Possible to limit list of params when using React Router?

Using React with React-Router in a project and am wondering if it's possible to limit the possibilities for param names, like so:
www.mydomain.com/books/:id
and allowing 'Catcher in the Rye' and 'To Kill A Mockingbird' to be passed through, like so:
www.mydomain.com/books/catcher-in-the-rye
www.mydomain.com/books/to-kill-a-mocking-bird
I want to say that only a specific set of books can be used in place of :id (just so someone can't type in www.mydomain.com/books/whatever-they-want and have an empty React component render).
I do currently have a '*' route that catches anything not mentioned, but because params are dynamically generated based on whatever is passed, that won't help in this case.
Is this possible? Thanks.
You need to handle this logic in the component. Depending on if this is an already mounted component or not you will need to put the logic in the appropriate function (componentDidMount, componentWillReceiveProps)
if(!(this.props.params.id in myAcceptableParameters)){
redirect to a 404 here
}

Resources