I'm coming up against 'window is undefined' errors while using React and Gatsby, so I want to conditionally pass a default value to my function parameter:
function useEventListener(element = window) {
I only want the function to be able to run if 'window' exists, and wrapping the contents of useEventListener inside an if statement isn't enough to avoid the error.
I was wondering if there is some way of doing it something like:
const windowDefined = () => typeof window !== "undefined";
function useEventListener(windowDefined ? element = window : element) {
can't you do the same inside the function, check it the parameter passed is undefined or not and return empty if it is?
function useEventListener( element) {
if(element){
return something
}
else{
return null
}
}
or wrap the whole function itself in a if condition and by default parameter it means it will work only if you don't pass a value,
please give more context for the question and usecase also
You could use a guard clause for this. If you just want the function to be prevented from running if window exists, the code would look like this:
function useEventListener() {
if (!window) return null
//function code here
}
Related
I'm using the useEffect hook, and in some cases I do not need to return anything. What is the best way to handle this situation?
// fooRef is a reference to a textfield (belonging to the same component). Sometimes the fooRef is not there,because of redirections) that's why I need to check if it exists
useEffect(() => fooRef.current && fooRef.current.focus() , [fooRef])
When using it like this, React complains with the following error message:
An effect function must not return anything besides a function, which is used for clean-up. You returned null. If your effect does not require clean up, return undefined (or nothing).
Would the best option be to return undefined or an empty function?
I think you intended to write
useEffect(() => {if (fooRef.current) fooRef.current.focus() } , [fooRef])
Your current implementation is returning the the boolean result of executing fooRef.current && fooRef.current.focus() rather than just executing the focus function if fooRef.current is true.
You can use void:
useEffect(() => void rooRef.current && fooRef.current.focus(), [fooRef])
See Kent C. Dodds video about it: Using void to make arrow functions return nothing
When you write above syntax in arrow function, you are explicitly informing to return fooRef.current.focus(), so do something like below
useEffect(() => { if(fooRef.current) fooRef.current.focus() } , [fooRef])
I am utterly confused by this peice of code, that does not seem to work in any way.
Simply, it's this:
// in app.js
import {layoutItemButtonClick} from '/blablaWrappeur.js'
document.addEventListener('DOMContentLoaded', function () {
var element = document.querySelector('.qq-element') //this is a html element obj
$('.layout-item-button').click(layoutItemButtonClick)
})
//in blablaWrappeur.js
export const layoutItemButtonClick = function () {
const selectedLayout = this.dataset.layout.split("")
doQqthing(element) // element is not defined
}
function doQqthing(element) {
alert(element) /// not defined
}
I need to pass the element and the this context of the clicked button to the layoutItemButtonClick function and then inside that, to the doQqthing function.
However, it does not work like this.
1) If I let the code like this and click the button nothing happens.
2) Now, if I change the click function to this (adding paranthese to the function call:
$('.layout-item-button').click(function () {
layoutItemButtonClick()
})
I get a dataset is not defined error.
3) If I change it to this:
$('.layout-item-button').click(layoutItemButtonClick())
I get the same error.
4) For this:
$('.layout-item-button').click(layoutItemButtonClick)
I get an element is not defined error.
I know that if I call the function inside a function, this would be the current element, and if inside the click parentheses like in 3) and 4), it would be the local scope this. So, how do I pass both the element and the this from the click into my function.
And why/how does using parenthesis make a difference when calling a function defined as a constant?
Thanks in advance.
And why/how does using parenthesis make a difference when calling a function defined as a constant?
layoutItemButtonClick is like any other variable access. It resolves to the value of the variable, which is a function object.
layoutItemButtonClick() otoh calls the function and resolves to its return value.
Therefore,
$('.layout-item-button').click(layoutItemButtonClick())
passes the return value of layoutItemButtonClick (which is undefined) to .click whereas
$('.layout-item-button').click(layoutItemButtonClick())
passes the function object itself to .click.
I get an element is not defined error.
And rightly so because element is not defined in the scope accessible to layoutItemButtonClick. It is only defined inside DOMContentLoaded event handler.
You'd have to pass element as argument to layoutItemButtonClick. So the function should be declared as
export const layoutItemButtonClick = function(element) { ... }
Now we need to call layoutItemButtonClick such that this refers to the clicked element and we pass element as argument. We can do this using .call:
$('.layout-item-button').click(function() {
layoutItemButtonClick.call(this, element);
});
However, there is no need for using this inside layoutItemButtonClick. We can just make the element that triggered the event an explicit argument:
export const layoutItemButtonClick = function(trigger, element) {
const selectedLayout = trigger.dataset.layout.split("")
doQqthing(element);
};
and call it as
$('.layout-item-button').click(function() {
layoutItemButtonClick(this, element);
});
In the View I have this condition:
<h3 *ngIf="show">{{users.result}}</h3>
In the TypeScript logic I have:
show=false; <----as a property
And the the following function:
timeOut(seconds: number, value:boolean) {
value = true;
setTimeout(
function() {
value = false;
}.bind(this),
seconds
);
}
But when I call it, like this:
console.log(this.timeOut(3000, this.show));
the property `this.show´ gets undefined, but the seconds passed as argument work. I'm missing something and I can't figure out what... Can anyone give a help?
As i see:
First of all you console logging function call without result.
When you pass the boolean value into the function params it's being copied, so when you change the value inside the function, it doesn't affect the outside variable/field.
This is very specialized use case, so you do not need to extract it to different function.
My suggestion - just put setTimeout call with arrow function into some component's method like ngAfterViewInit or in event handler method:
ngAfterViewInit() {
setTimeout(() => this.show = true, 3000)
}
Hope that helps.
Generally speaking, in C# i have a method like this;
public virtual IPagedList<Manufacturer> GetAllManufacturers(string manufacturerName = "",
int pageIndex = 0,
int pageSize = int.MaxValue,
bool showHidden = false)
{
//rest of the code
}
and when i need to specify the parameter order /override/call manually, i do this;
//manually saying, pageIndex should be as parameter 1 and showHidden should be true and order no 2
GetAllManufacturers(pageIndex:10, showHidden:true);
Similarly in JavaScript, i have the following function;
var CommonManager = function () {
var
displayWizard = function (wizardName, formName, leaveStepCallBack) {
leaveAStepCallback('test');
function leaveAStepCallback(obj) {
if (typeof (leaveStepCallBack) == "function") {
//yaheeeeeee callback is there
return leaveStepCallBack();
}
//oh no callback, handle the defaults
return validateSteps(); // return false to stay on step and true to continue navigation
}
};
return {
displayWizard: displayWizard
};
}();
and if i want to handle the callback i do call it like this;
CommonManager.displayWizard($('#wizard'), $('#attributeForm'), function() {
//i handled it, don't need to call default function
});
if i don't want to handle the callback, i do like this;
CommonManager.displayWizard($('#wizard'), $('#attributeForm'), undefined);
Note that, i have several optional parameters but i skipped it here. In my orginal case, i am passing undefined, undefined, undefined
So my questions are;
1) - How do i make it adjusted to i can call it like this;
//Notice the order of the parameter
CommonManager.displayWizard(attributeForm : $('#attributeForm'), wizard: $('#wizard'));
2) - if 1 isn't possible then How do i skipped passing this undefined as calling the Orignal Callback and call it like this
CommonManager.displayWizard($('#wizard'), $('#attributeForm'));
i could use the above code directly but i have the last parameter which need to be passed as well like this;
CommonManager.displayWizard(wizard, attributeForm, undefined,undefined, true);
3) - Lastly i wanna know, if i am following the right way of doing or handling this optional parameters
Please, let me know if the question doesn't make sense.
How do i make it adjusted
You can make your function take a parameter object, like this:
CommonManager.displayWizard({ attributeForm : $('#attributeForm'), wizard: $('#wizard') });
You could combine both approaches. For instance, in jQuery these lines are equivalent:
$(this).css("color", "red");
$(this).css({ color: "red" });
This is because the css function checks if its first parameter is an object and acts accordingly.
if 1 isn't possible then How do i skipped passing
You already can use the following:
CommonManager.displayWizard($('#wizard'), $('#attributeForm') /* no undefined here */);
If you skip a parameter at the end of the argument list, the default value passed to the function will be undefined.
Lastly i wanna know, if i am following the right way of doing or handling this optional parameters
If I know I may want to expand on a function's parameters in the future and some of them are/will be optional, I often create the function so that it accepts a single parameter: an object containing all the values I need to pass to the function.
This way, I can add parameters with default values, and still have calls that skip some values without breaking anything.
I am attempting to use the method invocation pattern in Javascript. I declare a function as an object member.
According to Javascript: The Good Parts, this should result in the this pointer referencing the enclosing object. When I've tried this before, this has been the case.
In the sample of code below, the this pointer reference by the single console.log statement is pointing to the function, not the object. I've double-checked my code and I honestly don't know what's going on.
I could use another pair of eyes on this. Is there something really obvious that I'm missing here, or am I expecting the wrong behavior? Thank you.
EDIT: I had a mistake in my code that I posted (it's been in flux); the keyword inside the anonymous function should be that, not this. Fixed.
DOUBLE EDIT: I've added the rest of my code within the module. I'm trying to write a commonJS module (in accordance with the gameJS library that I'm using) and although I'm not sure where that would be the problem, I'm wondering if it is. Does this change anything?
var gamejs = require('gamejs');
var system = require('app/system');
var input = {
eval_keys: function () {
console.log(this); // This should be the outer object, but shows the function!
var that = this;
gamejs.event.get().forEach(function (event) {
if (event.type === gamejs.event.KEY_DOWN) {
for (var key in that.keyconfig) {
if (that.keyconfig.hasOwnProperty(key)) {
if (event.key === gamejs.event[key]) {
that.keyconfig.key = true;
}
}
}
system.log("KEYDOWN", event.key);
}
if (event.type === gamejs.event.KEY_UP) {
for (var key in that.keyconfig) {
if (that.keyconfig.hasOwnProperty(key)) {
if (event.key === gamejs.event[key]) {
that.keyconfig.key = false;
}
}
}
system.log("KEYUP", event.key);
}
return keyconfig;
});
},
eval_mouse: function () {
/* in progress
else if (event.type === gamejs.event.MOUSE_MOTION) {
// if mouse is over display surface
if (display.rect.collidePoint(event.pos)) {
system.log("mousemove", testcoords);
testcoords = event.pos;
}
}
*/
},
keyconfig: {
K_UP: false,
K_LEFT: false,
K_RIGHT: false,
K_DOWN: false
}
};
exports.eval_keys = input.eval_keys;
Output from Chrome's dev console:
Object {eval_keys: function}
eval_keys: function () {
arguments: null
caller: null
length: 0
name: ""
prototype: Object
__proto__: function Empty() {}
<function scope>
__proto__: Object
It looks like it does work to me, by calling input.eval_keys() after the object is declared.
Also the output you show in the console looks to me to be the output you want -- i.e., the outer object Object {eval_keys: function} containing the method.
The problem seems more to be that you should be seeing the other methods you declared in there, like this:
Object {eval_keys: function, eval_mouse: function, keyconfig: Object}
eval_keys: function () {
eval_mouse: function () {
keyconfig: Object
__proto__: Object
So, as far as I can tell, your question should be "why aren't these other methods showing up within my object in the console?" But I don't what else you are doing with the code that might account for that nor how and when you're invoking the relevant method.
Hope this helps.
It would work if you didn't use an anonymous function with that forEach loop, the this keyword has a different value inside there. You can pass it in a the second parameter:
gamejs.event.get().forEach(function (event) {
// this now refers to the outer this
}, this);
Alternatively you can use your that variable which refers to the outer this value as well.
Well, I figured out what was causing the this pointer to only show an object with one function - it was this line:
exports.eval_keys = input.eval_keys;
On a whim, I decided to add exports.keyconfig = input.keyconfig and it appeared in the console as part of the object.
It looks like the exports keyword does something with the this pointer when it's referenced, even if the this pointer is inside the module in question. I'm not exactly sure how that worked, but it did.
I'm running into more problems, but at the moment, the immediate issue has been resolved. I'll have to do some more reading on this.