how can i stop the setInterval() timer i created, i have used clearInvterval but it's not working - setinterval

I'm finding it really difficult to stop my setInterval() using clearInterval() in my react app. My setInterval() was to dispatch my reducer from redux at an interval of 1 second. Below are my react and redux codes. Please, what could be the problem?
let countSession = useSelector((state)=>state.timer.minutes);
let countDown = useSelector((state)=>state.timer.seconds);
const initialSec = countDown=== 60 ? '0':countDown;
const seconds = initialSec < 10 ? '0' + initialSec: initialSec
const dispatch = useDispatch();
const a = ()=>{
setInterval(handleDispatch,1000);
}
const handleDispatch =()=>{
dispatch(countSeconds());
}
const b = ()=>{
clearInterval(handleDispatch)
}
return (
<Compo className="App">
<div className='label'>25 + 5 Clock</div>
<TimerApp/>
<br/>
<Compo className='timerBox' >
<div className='count'>Session</div>
<div className='count'>{countSession}:{seconds}</div>
</Compo>
<div className='playPause' id='playPause' onClick={()=>{a()}}>
<RiPlayFill/>
<MdPause/>
</div>
<button onClick={()=>{b()}}>Stop</button>
</Compo>
);
}
Redux
countSeconds:(state)=>{
state.seconds -=1;
if(state.seconds < 0){
state.minutes -=1;
state.seconds = 59;
}
}

Related

setInterval() and setTimeout() do nothing on heroku

My Node.js app works as intended and runs without errors on VSCode. However, setInterval() and setTimeout() do nothing once my app runs on heroku. I knew this because I wrote console.log() everywhere and looked at the heroku log of my app. None of the console.log() statements inside a setInterval() or setTimeout() were executed.
Surprisingly, all other functions of this app worked on heroku.
Here is the segment of code.
var refreshIntervalId = setInterval(() => {
config = require("./config.json");
// console.log("index line 44: entered loop");
if (config["reminder#" + fixedCount] == undefined) return clearInterval(refreshIntervalId);
config["reminder#" + fixedCount]["time"] -= 5 * 60 * 1000;
if (config["reminder#" + fixedCount]["time"] > 0) updateJson();
}, (5 * 60 * 1000));
setTimeout(() => {
const color = "#" + hexCodes[~~(Math.random() * hexCodes.length)], userID = config["reminder#" + fixedCount]["user"];
const userObject = client.users.cache.get(userID);
let sendReminder = new Discord.MessageEmbed()
.setTitle(`Reminder to ${userObject.username.split("#")[0]}`)
.setColor(color)
.setDescription(config["reminder#" + fixedCount]["content"]);
userObject.send({embeds: [sendReminder]}).catch(err => { });
delete config["reminder#" + fixedCount];
updateJson();
}, config["reminder#" + fixedCount]["time"]);
Any idea why this happened?

Unit test for Svelte on:click event

Can anybody point me into right direction?
I'm expecting mock function to be called after click event was fired.
What I've got is:
Expected number of calls: 1
Received number of calls: 0
This are my components along with test file:
EventTestingWrapper.svelte
<script>
export let testComponent
export let clickHandler
</script>
<div data-testid="testing-wrapper">
<svelte:component this={testComponent} on:click={clickHandler} />
</div>
Modal.svelte
<div
class="modal-background"
data-testid="modal-background"
on:click|self={close}
>
lorem
</div>
Modal.test.js
test('trying out test wrapper',()=>{
const clickHandler = jest.fn();
const { getByTestId } = render(EventTestingWrapper, {testComponent: Modal, clickHandler})
const modalBackground = getByTestId('modal-background')
const clickEvent = createEvent.click(modalBackground)
fireEvent(modalBackground, clickEvent);
expect(modalBackground).toBeInTheDocument()
expect(clickHandler).toHaveBeenCalledTimes(1)
})
I don't know exactly if this is what you want, but to pass on:click type event listeners to #testing-library/svelte rendered components you must use the component.$on syntax.
For example:
describe('Button', () => {
it('should render correctly', async () => {
const results = render(Button)
const onClick = jest.fn()
results.component.$on('click', onClick)
const button = results.container.querySelector('button')
expect(button).not.toBeNull()
// Using await when firing events is unique to the svelte testing library because
// we have to wait for the next `tick` so that Svelte flushes all pending state changes.
await fireEvent.click(button as HTMLElement)
expect(results.container).toBeInTheDocument()
expect(onClick.mock.calls.length).toEqual(1)
})
})
This link in the testing-library docs seemed to be quite useful https://sveltesociety.dev/recipes/testing-and-debugging/unit-testing-svelte-component/
This question is about jest but for people coming here in the future looking for a vitest solution, try this:
import Component from '$lib/MyComponent.svelte'
import { expect, test, vi } from 'vitest'
test(`invokes callback functions`, async () => {
const keyup = vi.fn()
const click = vi.fn()
const instance = new Component({
target: document.body,
props: { foo: `bar` },
})
// register callbacks (same as passing them as `on:<event>` props to component
instance.$on(`keyup`, keyup)
instance.$on(`click`, click)
const node = document.querySelector(`.some-css-selector`)
if (!node) throw new Error(`DOM node not found`)
node.dispatchEvent(new KeyboardEvent(`keyup`, { key: `Enter` }))
expect(keyup).toHaveBeenCalledTimes(1)
node.dispatchEvent(new MouseEvent(`click`))
expect(click).toHaveBeenCalledTimes(1)
})

How to mock/simulate a child component event for jest tests in svelte?

I want to run an isolate test on my svelte parent component (e.g. OrderSearch). Therefore the behavior of the child component (e.g. SearchForm) should be "simulated". The child component throws a search event that is bound in the parent component to initiateSearch.
SearchForm.svelte (Child component - NOT subject of testing - triggering of "submit" should be simulated)
<script>
const dispatchEvent = createEventDispatcher()
const submit = () => {
dispatchEvent('search', {firstName: '42'})
}
</script>
<div on:click="submit">Submit</div>
OrderSearch.svelte (Parent Component - Subject of testing)
<script>
let results = []
const initiateSearch = (e) => {
console.log('initiate search with', e)
// search is started and returns results
results = [{orderId: 'bar'}]
}
</script>
<SearchForm on:search="initiateSearch"></SearchForm>
{#each results as order}
<div data-testid="order">{order.id}</div>
{/each}
My not working approach so far when testing the OrderSearch.svelte in an isolated way:
OrderSearchTest.js
const {getAllByTestId, component} = render(Component)
expect(getAllByTestId('order')).toHaveLength(0)
await component.getSubComponent('SearchForm').dispatchEvent('search', {detail: {orderId: 'jonine'}}
expect(getAllByTestId('order')).toHaveLength(1)
Don't mock the child's event. You don't need to test that the on:<event> directive works, I would assume that Svelte has corresponding tests to ensure that it does. You need to test only that your component responds in the way that it should when the code that is executed on a particular event occurs. So trigger the event using fireEvent and mock or spy on a function, or function(s) called in the event handler.
Here's an example with appropriate changes made to your component:
OrderSearch.svelte
<script>
import http from "path/to/some/http/util"
let results = []
const initiateSearch = async (e) => {
// search is started and returns results
results = await http.fetchSearchResults(e.detail)
}
</script>
<SearchForm on:search="initiateSearch"></SearchForm>
{#each results as order}
<div data-testid="order">{order.id}</div>
{/each}
Then the corresponding test could look like:
import mockHttp from "path/to/some/http/util"
jest.mock("path/to/some/http/util")
...
it("calls search endpoint and renders results after fetch resolves", async () => {
mockHttp.fetchSearchResults.mockResolvedValue([{orderId: 'bar'}])
const { queryByText, getAllByTestId } = render(Component)
const submit = queryByText("Submit")
expect(getAllByTestId('order')).toHaveLength(0)
await fireEvent.click(submit)
expect(getAllByTestId('order')).toHaveLength(1)
})

how to properly handle firebase realtime database listeners with useEffect?

const Messages = (props) => {
const [messages, setMessages] = useState([]);
const { currentChannel, currentUser } = props;
const messagesRef = firebase.database().ref("messages");
useEffect(() => {
if (currentChannel && currentUser) {
const channel = currentChannel.currentChannel;
let loadedMessages = [];
messagesRef.child(channel.id).on("child_added", (snap) => {
loadedMessages.push(snap.val());
});
setMessages(loadedMessages);
}
return () => messagesRef.off();
}, [currentChannel, currentUser, messagesRef]);
const displayMessages = (messages) =>
messages.length > 0 &&
messages.map((message) => (
<Message key={message.timestamp} message={message} user={currentUser} />
));
return (
<>
<MessagesHeader />
<Segment>
<Comment.Group className="messages">
{displayMessages(messages)}
</Comment.Group>
</Segment>
<MessageForm
messagesRef={messagesRef}
currentChannel={currentChannel}
currentUser={currentUser}
/>
</>
);
};
Warning: Maximum update depth exceeded. This can happen when a
component calls setState inside useEffect, but useEffect either
doesn't have a dependency array, or one of the dependencies changes on
every render.
How to prevent this infinite loop?
Every time you render, you're creating a new messagesRef object. It may be dealing with the same spot in the database, but it's a new object. Since messageRef changed, your effect will rerun and that effect will call setMessages with a brand new array each time. Since you set state, the component rerenders, and the loop repeats.
Most of the time, i would recommend having the database ref only exist inside your useEffect, and then removing it from the dependency array. However, it looks like you need to pass the ref as a prop to MessageForm, so that won't work here. Instead, you need to make sure that you only create the database ref once. useMemo is one way to do this:
const messagesRef = useMemo(() => {
return firebase.database().ref("messages");
}, []);

How to find out if reading dir is completed

everyone
I am working on some sort of image view application using node-webkit. I made a function to read dir inside the given location and search for the image files(*.jpg and *.png). Code I used is as follows:
app.js
var fs = require("fs");
var gui = require('nw.gui');
var win = gui.Window.get();
var directory;
var db = require('diskdb');
var path = require('path')
db = db.connect("lib/collections", ['temp']);
function chooseFile(name) {
var chooser = $(name);
scr = 0;
chooser.change(function(evt) {
directory = $(this).val();
var asdf;
console.clear();
readDir(directory);
$(this).val('').hide();
});
}
function readDir(directory){
c = 0;
console.log("reading "+directory);
if(fs.statSync(directory).isDirectory() == true){
fs.readdir(directory,function(err,files){
if (err){
console.log(err);
return;
}
var ext;
files.forEach(function(file){
console.log("Got what: "+file);
var fulls = directory+"\\"+file;
if(file.indexOf(".") != 0){
if(path.extname(fulls) == ""){
console.log("Got a directory: "+file);
if(fs.statSync(fulls).isDirectory() == true){
readDir(fulls);
}
}
else{
console.log("Got a file: "+file);
if(checkExtension(file, 'jpg,png')){
scr++;
c = saveTemp(fulls,scr,file);
}
}
}
});
if(c == 1){
loadgun();
}
});
}
}
function loadgun(){
if(db.temp.count()!=0){
for(i=1;i<=db.temp.count();i++){
var asd = db.temp.findOne({'id':i});
var theTempScript = $("#tmpl-imgholder").html();
var theTemp = Handlebars.compile(theTempScript);
$("#ContentWrapper").append(theTemp({"fulls":asd.file, "id":asd.id, "title":asd.title}));
}
}
}
saveTemp = function(file,id, title) {
var savedUser = db.temp.save({
file:file,
id:id,
title:title
});
return 1;
};
function checkExtension(str, ext) {
extArray = ext.split(',');
for(i=0; i < extArray.length; i++) {
if(str.toLowerCase().split('.').pop() == extArray[i]) {
return true;
}
}
return false;
};
$(document).ready(function(){
if(db.temp.count() != 0){
loadgun();
}
else{
$('#blah').css('display','block');
chooseFile('#blah');
}
});
index.html
<html>
.
.
.
<body>
<input type="file" nwdirectory id="blah" style="display:none"/>
<script src="js/jquery.min.js"></script>
<script src="js/app.js"></script>
<script src="js/handlebars.js"></script>
<script id="tmpl-imgholder" type="x-handlebars-template">
<div class="image-container grid__item" data-id="{{id}}" data-src="{{fulls}}">
<div class="cover" style="background:url({{fulls}})" title="{{title}}"></div>
<div class="info">
<div class="title">{{title}}</div>
</div>
<div class="clear"></div>
</div>
</script>
</body>
</html>
Here i tried to load data using loadgun function. Its hangs the node webkit window. If I could know when the readDir function terminates then i could do load the required datas.
If there is another way please do say.
Thanks in advance.
the problem with readDir is that is asynchronous function , that is why you have to provide a callback. you can however use fs.readdirSync(path) which is synchronous , and then the code flows synchronously. a psoducode may look like this :
function readDirAsynch(dir){
var files = fs.readdirSync(dir);
for (var i in files){
if (files[i] isDir){
readDirAsynch(files[i]);
} else if (myCondition){
//do somehting
}
}
}
needless to say , you know that the function is done when the next line after the function call is being executed
Quick answer:
You can use the synchrohous method fs.readdirSync(path) and everything should work just fine for you. You don't need to keep reading. https://nodejs.org/api/fs.html#fs_fs_readdirsync_path
My personal suggestion:
Since node is single threaded I would recommend you to keep using the asynchronous version but adding a callback to your method.
This means that your "readDir" method is going to be asynchronous too. You only need to add a callback parameter to your method. E.g.
readDir(dir, fnCallback) {
...
fs.readdir(directory, function(err,files){
... doing cool stuff ...
fnCallback();
});
}
If you want to read more about writing asynchronous code maybe this guide can help you.
http://callbackhell.com/
Also if you want to go further in the wonderful asynchronous world you can take a look to 'Promises' https://www.npmjs.com/package/node-promise, 'Future' https://www.npmjs.com/package/async-future, 'Async' https://www.npmjs.com/package/async and have more fun than you have ever imagined before.

Resources