I am using a debounce function in my react native project. It gets triggered after user enters 3 characters but it is triggering after 2 sec instead of the delay i assigned to it.
constructor() {
this.init()
this.hitSearchApi = debounce(() => {
log('inside if is called debounce')
this.getStudentTableData(() => this.updateFetchingStatus(true))
this.updateSearchLoaderStatus(false)
this.updateFetchingStatus(false)
}, 100)
}
I had created my debounce function inside the store constructor like this.
#action
onChangeSearchText = (searchText) => {
if (get(searchText, 'length', 0) > 2) {
log('inside search text if condition')
this.updateSearchLoaderStatus(true)
this.hitSearchApi.cancel()
// this.updateSearchLoaderStatus(true)
log('before hit search api')
this.hitSearchApi()
// fetch student list on search basis
} else if (get(searchText, 'length') === 0) {
this.setStudentListData({})
this.updateFetchingStatus(true)
this.resetSearchData()
}
this.searchText = searchText
}
This is my onChange text triggered, which is getting called on textinput onChange event.
Please help me out in this. What am I doing wrong here?
Related
I need help to rewrite some arrow functions to regular functions but right now my brain is totally stucked, I have some example code here from a rock paper scissors game I got from kyle, how would it look if I was to ditch the arrow function please somebody?
selectionButtons.forEach(selectionButton => {
selectionButton.addEventListener('click', e => {
const selectionName = selectionButton.dataset.selection;
const selection = SELECTIONS.find(selection => selection.name === selectionName);
makeSelection(selection);
would it be as easy as?:
selectionButtons.forEach(selectionButton = function() {
or have I completely lost it?
The list of arguments goes inside the parenthesis.
You need an explicit return statement
function (selection) {
return selection.name === selectionName
}
This particular example doesn't use this but if it did it wouldn't be so simple to exchange a function expression for an arrow function (see this question).
// either:
selectionButtons.forEach(function (selectionButton) {
selectionButton.addEventListener('click', function (evt) {
// - what happens here should be prevented.
// - one really should avoid subscribing to each element
// its very own ad-hoc created handler function.
// - a shared reference of a single handler function
// is better in terms of resources and also of removing
// a listener again.
const selectionName = selectionButton.dataset.selection;
const selection = SELECTIONS.find(function (item) {
return item.name === selectionName;
});
makeSelection(selection);
});
});
// or:
function handleSelectionClick(evt) {
// access currently clicked selection button from event object.
const selectionButton = evt.currentTarget;
const selectionName = selectionButton.dataset.selection;
const selection = SELECTIONS.find(item =>
// an arrow function here is much more convenient
// than an anonymous function expression.
item.name === selectionName
);
makeSelection(selection);
}
function subscribeSelectionClickHandling(selectionButton) {
// shared reference of a one time implemented handler function.
selectionButton.addEventListener('click', handleSelectionClick);
}
selectionButtons.forEach(subscribeSelectionClickHandling);
I've obtained an anonymous function that takes an event object as input as well as another input like so:
// define a state toggle function
const toggleDrawer = (open) => (event) => {
// quit for certain key events
if (event.type === 'keydown' && (event.key === 'Tab' || event.key === 'Shift')) {
return;
} // if
// set the given toggle open state
setState(open);
};
I would like to incorporate this as a method in a class, but unsure how to rewrite inputs.
I could just store the variable as a property on the object, but I would like to write it like so:
/*
View-model of the Drawer view.
*/
class DrawerModel {
// class constructor
constructor() {
// initialise a drawer state
const [open, setOpen] = React.useState(false);
// store the state and set function on the object
this.open = open;
this.setOpen = setOpen;
} // constructor
// method to toggle the drawer
toggleDrawer(open) {
// quit for certain key events
// TODO: how to pass event in like with the anon fnc?
// const toggleDrawer = (open) => (event) => {...
//if (event.type === 'keydown' && (event.key === 'Tab' || event.key === 'Shift')) {
// return;
//} // if
// set the given toggle open state
setState(open);
} // toggleDrawer
} // class
The toggleDrawer function can be assigned as the callback for some UI component events.
I don't understand the anonymous function definition with multiple inputs "= (open) => (event) =>".
Could someone explain/link how that works?
How do I make that event data available with how I'm writing the class method?
It is currying function. It is function which returns function. With classic syntax (not arrow syntax as your example is) you can write it like this:
class DrawerModel {
toggleDrawer(open) {
return function(event) {
// do your magic here
}
}
}
I would like to set a timer for the action function. The rule is: when the selected text does not change for 3 seconds, we run the function action with the selected text.
I tried the following code in the playground https://microsoft.github.io/monaco-editor/playground.html, it did not work. When I changed the selected text very quickly, their actions were not cancelled.
Could anyone help?
const editor = monaco.editor.create(document.getElementById('container'), {
value: '1+2+3+4+5+6+7',
language: 'javascript'
});
function action(x) {
console.log("action", x)
}
let myTimeout
editor.onDidChangeCursorSelection((e) => {
clearTimeout(myTimeout)
console.log("cleared", myTimeout)
let selectedText = editor.getModel().getValueInRange(editor.getSelection())
if (selectedText != "") { // if we are already in this event, the selected text must change
myTimeout = setTimeout(action(selectedText), 3000);
console.log("set", myTimeout, selectedText)
}
})
Edit 1: My component is a class component, so I cannot use hook calls.
You can use lodash's debounce to achieve the effect you want. And use useCallback to make sure you get the same instance of function. I think an implementation like this might work:
import _ from 'lodash';
...
const debouncedAction = _.debounce(action, 3000).bind(this);
editor.onDidChangeCursorSelection((e) => {
let selectedText = editor.getModel().getValueInRange(editor.getSelection())
if (selectedText != "") { // if we are already in this event, the selected text must change
debouncedAction(selectedText);
}
})
I used this as a reference.
setTimeout takes function as input, while you have called it. I think the following code works well.
const editor = monaco.editor.create(document.getElementById('container'), {
value: '1+2+3+4+5+6+7',
language: 'javascript'
});
function action(x) {
console.log("action", x)
}
let myTimeout
editor.onDidChangeCursorSelection((e) => {
clearTimeout(myTimeout)
let selectedText = editor.getModel().getValueInRange(editor.getSelection())
if (selectedText != "") {
// "action" is called inside a function
myTimeout = setTimeout(() => action(selectedText), 3000);
}
})
I was trying to pause/play and change instruments in the code below by trying to call the function responsible in a useEffect Hook. The playKeyboard method uses a new instance every time it is called, but instead, I want that state to be stopped and merged completely.
useEffect(() => {
if (keyboard.length > 0)
playKeyboard(keyboard, stat.pause, stat.index, stat.selectSound);
}, [keyboard, stat]);
const onInstrumentChange = (event) => {
const newStat = { ...stat, selectSound: { value: event.target.value } };
setStat(newStat);
};
The function responsible for creating the sound is partially:
async function playKeyboard(keyboardArray, pause, index, selectSound) {
var __audioSynth = new AudioSynth();
__audioSynth.setVolume(0.08);
var __octave = 4; //sets position of middle C, normally the 4th octave
//to select the instrument to play
// let selectSound = {
// value: "1"
// //"0" //piano
// // "1" //organ
// // "2" //acoustic
// // "3" //edm
// };
// Generates audio for pressed note and returns that to be played
var fnPlayNote = function(note, octave, duration) {
var src = __audioSynth.generate(selectSound.value, note, octave, duration);
var container = new Audio(src);
container.addEventListener("ended", function() {
container = null;
});
container.addEventListener("loadeddata", function(e) {
e.target.play();
});
Is there a recommended way to stop the previously registered or called function.
FullCode in CodeSandbox is: here for the keyboard method and here for the react component that uses it
I guess what you are trying to achieve can be done using, useEffect with Cleanup,
in every useEffect you can return a function that will be called with the component exits,
useEffect(() => {
if (keyboard.length > 0){
playKeyboard(keyboard, stat.pause, stat.index, stat.selectSound);
return stopKeyboard(arguments); // Implement the sound stop functionality here
}
}, [keyboard, stat]);
I'm building an autocomplete feature. Everything works as expected except when I reach the end of the input. When I change the value of the input, programatically, the input doesn't scroll/focus on the cursor until I type something.
I tried doing something like this on componentDidUpdate and it worked, but besides being a bit "dirty" I don't want to use the onBlur because I'm closing the autocomplete popup on this event.
setTimeout(() => {
this.refInput.input.selectionStart = this.refInput.input.selectionEnd = this.state.value.length;
this.refInput.input.blur();
this.refInput.input.focus();
}, 1);
How can I achieve this, specially without a setTimeout? If I do it without the setTimeout it doesn't work.
I'd do it with a useEffect Hook
import React, { useEffect } from 'react'
//
//
useEffect(()=>{
this.refInput.input.selectionStart = this.refInput.input.selectionEnd = this.state.value.length;
this.refInput.input.blur();
this.refInput.input.focus();
},[this.state.value, this.refInput.input.selectionStart, this.refInput.input.selectionEnd])
I made it worked. Unfortunately it is not very pretty. I still need to use the blur and setTimeout events.
onBlur = () => {
setTimeout(() => {
if (this.refInput.input !== document.activeElement) {
console.log(this.refInput.input.selectionEnd);
this.setState({ helperVisible: false });
this.props.clearAutoComplete();
}
}, 1);
};
(...)
componentDidUpdate(prevProps, prevState, snapshot) {
const { value } = this.state;
if (prevState.value !== value) {
setTimeout(() => {
this.refInput.input.selectionStart = this.refInput.input.selectionEnd = this.state.value.length;
this.refInput.input.blur();
this.refInput.input.focus();
}, 0);
}
If anyone has any ideia how to improve this it would be great. Otherwise I'm marking this as the correct answer.
The below should grab the element. focus on it. then move the selection range to the end of the current value. This abides by the desire to avoid blur().
CAVEAT: sometimes it doesn't seem to properly fire in this snippet and in codepen..
(function () {
const el = document.getElementById('dataList'),
val = 'this is my value',
len = val.length;
el.focus();
el.value = val;
setTimeout(function () { el.setSelectionRange(len, len); }, 100);
})();
<input id="dataList">