Can svelte use composable functions? - javascript

I am coming from vue and used to composable functions. I am trying to figure out the way to do this in svelte
So I make a js file and import store and then was trying to make a function that I could call on multiple components and act individually
swipe.js file
import { writable, derived, get } from 'svelte/store';
function createSwipe() {
const dyFromStart = writable(0)
function moveEvent(eventType, val){
console.log('moveEvent', eventType, val, get(dyFromStart))
dyFromStart.update(n => n + 1);
}
const dxScore = derived(dyFromStart, $dyFromStart => $dyFromStart + 3)
const dyScore = derived(dyFromStart, $dyFromStart => Math.round($dyFromStart + 100));
return {
moveEvent,
dxScore,
dyScore,
};
}
export const swipe = createSwipe();
then in .svelte component import function in script and decompose into subparts
<script>
import { swipe } from "$lib/swipe";
let { moveEvent, dxScore, dyScore } = swipe
</script>
<p>{$dxScore}{$dyScore}</p>
<button on:click="() => moveEvent">button</button>
Well eventually I want to turn into a swipe component hence name but trying to get fundamentals down. So I want to be able to have unique store for each component and for this if I use multiple of this .svelte component the state is shared amongst all.
And not just like three idk modal.svelte components I want to use swipe for a bunch of diff components maybe a photoViewer.svelte right just generic swipe function and use same code for all.
or would I just have to keep the state like const dyFromStart = writable(0) be just let dyFromStart = 0 in each .svelte component and pass it into a pure js function that returns results and update local .svelte variables
Adding this as the non store more pure js things I was trying but couldn't get to be reactive so accepting the answer below on store method that worked and sounds like is the correct approach
export function createSwipe() {
let dyFromStart = 0
function moveEvent(eventType, val){
console.log('moveEvent', eventType, val, dyFromStart, dxScore(), dyScore())
dyFromStart++
}
function dxScore(){ return dyFromStart + 3 }
// const dzScore = derived(dyFromStart, $dyFromStart => $dyFromStart + 3)
const dyScore = () => Math.round(dyFromStart + 100)
return {
moveEvent,
dxScore,
dyScore,
dyFromStart
};
export function createSwipe() {
let dyFromStart = 0
let dxScore = dyFromStart + 3
let dyScore = Math.round(dyFromStart + 100)
function moveEvent(eventType, val){
console.log('moveEvent', eventType, val, dyFromStart, dxScore, dyScore)
dyFromStart++
dxScore = dyFromStart + 3
dyScore = Math.round(dyFromStart + 100)
}
return {
moveEvent,
dxScore,
dyScore,
dyFromStart
};
I suppose that works fine just not reactive with $ and need to call to update a diff local var if doing that
this would seem most sveltey to me or something like it as far as composable function type style not store type
export function createSwipe() {
let dyFromStart = 0
function moveEvent(eventType, val){
console.log('moveEvent', eventType, val)
dyFromStart++
}
$: dxScore = dyFromStart + 3
$: dyScore = Math.round($dyFromStart + 100)
return {
moveEvent,
dxScore,
dyScore,
};
}

I don't understand the question fully, so I try to reiterate first what I think you want:
You want to use your swipe function in multiple places
Each usage of that swipe function should be independent of all others
If that's correct, then the answer is simple: Don't do export const swipe = createSwipe(). Delete that part and instead export the create function to use directly within your components. That way you create a new independent instance each time:
<script>
import { createSwipe } from "$lib/swipe";
let { moveEvent, dxScore, dyScore } = createSwipe()
</script>
<p>{$dxScore}{$dyScore}</p>
<button on:click="() => moveEvent">button</button>

Related

Javascript Functions as constants

I have inheritted some code and I've very rarely used JS. In the code, athere are losts of functions which are defined into contstants. I'm trying to debug an issue using a browser, and I am struggling to call any of the functions from the commandline
can anyone let me know how I would do this please. Example below (not actual code)
const updateDisplay = function () {
if (0x0 === seq[hl_0b('0x8', '3D61')]) {
return;
}
if (0x1 === seq[hl_0b('0x16', 'Sg%G')]) {
get('display')['innerText'] = '';
}
const a = 0x32 * (seq[hl_0b('0x7', '7U46')] - 0x1 - get(hl_0b('0x22', 'uOD4'))[hl_0b('0x24', 'Mu]C')]['length']);
setTimeout(function (b) {
get(hl_0b('0x2b', 'Q0y5'))[hl_0b('0x10', 'Zu59')] += seq[b];
buttonFlash(null, hl_0b('0x5', 'lRst') + seq[b]);
}, a, seq[hl_0b('0x1e', '2f%K')] - 0x1);
};
Updated to include actual code
to create a constant function you need to call it with const instead of constant. After that you can create your function as
const toto = function(){
/*DO SOMETHING*/
}
This function can be write as an arrow function to as
const toto = () => {/*DO SOMETHING*/}
Anyway, this is links for documentations if you want
https://developer.mozilla.org/en-US/docs/Glossary/Function
https://www.w3schools.com/js/js_const.asp

will export function() be called multiple times in javascript?

I wonder if this
const getData = () => {
const data = 1; // simplified complicated operations
return data;
};
export default getData();
is any performance difference than this:
const getData = () => {
const data = 1;
return data;
};
const toexport = getData(); // cache to a variable before exporting
export default toexport;
The question boils down to how export actually works. I read many articles and I can manage to make it work, but I haven't understood what it does under the hood (couldn't find an article about my question).
What if an export is imported from difference import, will the getData() be called once or being called for each import?
function getData() {
console.log('getData');
return 1;
}
// will `export default getData();` be like this
const importSomeWhere = getData();
const importSomeWhereElse = getData();
// or this?
const exportCached = getData();
const importSomeWhere2 = exportCached;
const importSomeWhereElse2 = exportCached;
It will be evaluated only once. Here's example from What Happens When a Module Is Imported Twice?
In increment.js, we declare a variable called counter
let counter = 0;
counter++;
export default counter;
In consumer.js we import 2 times, but the counter is evaluated once for the first import
import counter1 from './increment';
import counter2 from './increment';
counter1; // => 1
counter2; // => 1

How to encapsulate state with an update method and a mithril component

I want to render state that is updated every request animation frame.
I want to encapsulate state with an update method and corresponding component:
But that fails because it's not correct usage of mithril components.
import * as Vnode from 'mithril/render/vnode';
import * as h from 'mithril/hyperscript';
export default function Play() {
// background is another encapsulation like Play
let background = new Background(this);
let data;
this.init = d => {
data = d;
background.init();
};
this.update = delta => {
background.update(delta);
};
this.component = ({
view() {
return h('div.' + data,
[Vnode(background.component)]
);
});
}
Render code:
import mrender from 'mithril/render';
import * as Vnode from 'mithril/render/vnode';
export default function MRender(mountPoint) {
this.render = (component) => {
mrender(mountPoint, Vnode(component));
};
}
Usage:
let mrender = new MRender(element);
let play = new Play();
function step() {
play.update();
mrender.render(Vnode(play.component));
requestAnimationFrame(step);
};
step();
I want state mutations and render code to be in the same place, because state is concerned with view animations.
If I understand correctly you want to be able to manage the internal state of the component while it's being updated by requestAnimationFrame? The following might get you on the right track:
const m = require('mithril');
//Use a closure to manage internal state of component
const play = initialVnode => {
const {
timestamp
} = initialVnode.attrs;
const start = timestamp;
return {
view: vnode => m('ul',[
m('li',`Start: ${start}`),
m('li',`Current timestamp: ${vnode.attrs.timestamp}`),
])
}
};
let reqID;
const step = timestamp => {
if( timestamp ){ //Start animating when timestamp is defined
m.render(document.body, m(play,{
timestamp,
}));
}
reqID = requestAnimationFrame(step);
if( reqID === 60 ){ //Add condition to stop animating
cancelAnimationFrame(reqID);
}
};
step();
I hope that helps.

How to get the "returns" of functions that are arguments in a function using ...spread?

I'm developing a simple Javascript Client API for my unit tests, as I'm studying TDD and learning better by doing things.
I'm following a model where they will only be a CHECK by test, I have my TEST function, which is where all the tests of a given file will be, and each test will be called by TEST_F with only one CHECK function each, thus not needing a description for each TEST_F, since with just a CHECK, it is simple and easy to understand with just a good "nameTest".
The problem I'm having is to use the Javascript spread, I actually know well how to solve my problem without it, but I would like to understand if it could help me simplify things here. The TEST function, as I said, might get several TEST_F functions as arguments, so I thought I'd do something like const TEST = (... f) => {};, but I'm not sure how to use each "f" argument since each TEST_F function returns me an object, which I want to use to accuse the TEST_Fs that fail. I will try to explain what I try to do with the code below that we know will not work, but only to understand where I am trying to get:
/* --------------------------------------------------------------- */
/* ------------------- Test API ---------------------------------- */
/* --------------------------------------------------------------- */
const TEST = (fileName, ...f) => {
const passing = [];
const failing = [];
console.log('Running unit tests in '+fileName+':');
const tStart = performance.now();
const result = ...f(); // I know it's not possible, but you understand what I'm trying to do?
result.resultTest==='passed'?passing.push(result):failing.push(result);
const tEnd = performance.now();
const duration = tEnd - tStart;
const lenPassing = passing.length;
const lenFailing = failing.length;
console.log('Passing: '+lenPassing+' ('+duration+'ms)');
console.log('Failing: '+lenFailing);
if(lenFailing > 0){
let stg = '';
for(let i = 0; i < lenFailing; i++){
stg += (i + ') ' + failing[i].nameTest + ' (' + failing[i].durationTest + ')' + '\n');
}
console.log(stg);
}
};
const TEST_F = (nameTest, f) => {
const tStart = performance.now();
const resultTest = f();
const tEnd = performance.now();
const durationTest = tEnd - tStart;
return { nameTest: nameTest, durationTest: durationTest, resultTest: resultTest };
};
const CHECK_EQUAL = (value, expected) => {
return ((value === expected)?'passed':'failed');
};
export {
TEST,
TEST_F,
CHECK_EQUAL
};
Up 1:
How would I solve my problem without using the spread? creating a TEST object that contains an array of TEST_F and then would create a function to run the tests, something like EXECUTE_TEST, but what I want to avoid is having to call a function always in my test files, I want something simple like:
TEST("main.js",
TEST_F("test1", () => {
return CHECK_EQUAL(3, 3);
}),
TEST_F("test2", () => {
return CHECK_EQUAL(7, 3);
})
);
which I was able to solve with the #TJ Crowder answer:
for(let fn of f) {
const result = fn;
result.resultTest==='passed'?passing.push(result):failing.push(result);
}
If your goal is to call each function in the f array and get the results from them into the passing or failing arrays, I'd probably use a simple for-of:
for (const fn of f) {
const result = fn();
result.resultTest==='passed'?passing.push(result):failing.push(result);
}
or forEach or similar, any of the array looping mechanisms would do the job.

How do I manage context when exposing object methods in JS modules?

Okay, I realize this can be considered subjective, but I'm trying to better understand how to consider scope when writing modules that only expose what's needed publicly. I have a string utility that I've written as an object literal below:
const substrings = {
query: {},
text: "",
results: [],
exists: function (index) {
const exists = index >= 0
return exists
},
check: function () {
const q = this.query
const start = q.openIndex
const stop = q.closeIndex
if (q.hasOpen && !q.hasClose) {
console.log("Missing closing delimiter.")
}
if (!q.hasOpen && q.hasClose) {
console.log("Missing opening delimiter.")
}
if (q.hasOpen && q.hasClose && start > stop) {
console.log("Closing delimiter found before opening.")
}
if (!q.hasOpen && !q.hasClose && this.results.length == 0) {
console.log("No results found.")
}
const order = start < stop
const check = q.hasOpen && q.hasClose && order
return check
},
update: function () {
const q = this.query
const text = this.text
q.before = this.text.indexOf(q.open)
q.start = q.before + q.open.length
this.text = text.slice(q.start, text.length)
q.stop = this.text.indexOf(q.close)
q.after = q.stop + q.close.length
q.openIndex = q.before
q.closeIndex = q.before + q.stop
q.hasOpen = this.exists(q.openIndex)
q.hasClose = this.exists(q.stop)
const newPosition = q.start + q.after
q.position = q.position + newPosition
this.query = q
},
substrings: function () {
const q = this.query
const current = this.text.slice(0, q.stop)
const fullLength = this.text.length
this.text = this.text.slice(q.after, fullLength)
this.results.push(current)
this.update()
if (this.check()) {
this.substrings()
}
},
init: function (open, close, text) {
this.results = []
this.query = {
open,
close,
position: 0,
}
this.text = text
this.update()
},
getSubstrings: function (open, close, text) {
this.init(open, close, text)
if (this.check()) {
this.substrings()
return this.results
}
},
getSubstring: function (open, close, text) {
this.init(open, close, text)
if (this.check()) {
return this.text.slice(0, this.query.stop)
}
}
}
I want to use it as a Node module and expose the getSubstring and getSubstrings methods, but if I were to do:
module.exports = {
all: substrings.getSubstrings,
one: substrings.getSubstring
}
I would get an error due to the usage of this. I realize that if I replace this with the object var name substrings to reference it directly, it works. I could also refactor it to be one big function or smaller functions and just export the 2 I need.
I am trying to go about learning things the right way and am struggling with how I should be thinking about context. I understand how this changes here, but I feel like I'm not fully wrapping my head around how I should consider context when structuring my code.
Is there a more elegant solution to expose methods with code like this that wasn't written to separate private and public methods?
A simple solution would be to bind the exported functions to the proper calling context inside the exports object:
module.exports = {
all: substrings.getSubstrings.bind(substrings),
one: substrings.getSubstring.bind(substrings)
}
Personally, I prefer using the revealing module pattern over object literals for situations like this. With the revealing module pattern, create an IIFE that returns the desired functions, referring to local variables instead of properties on this. For example:
const { getSubstrings, getSubstring } = (() => {
let query = {}
let text = ''
let results = []
function exists(index) {
return index >= 0
}
function check() {
const q = query;
// ...
}
...
function getSubstrings(open, close, text) {
}
...
return { getSubstrings, getSubstring };
})();
module.exports = {
all: getSubstrings,
one: getSubstring
}
This is somewhat opinion-based, but code can be easier to read when there aren't any this references to worry about.

Categories

Resources