react-native imported(?) function arguments is so weired - javascript

My react native project skeleton here
-app
--component
--LoginScreen.js
--container
--styles.js
-index.ios.js
-index.android.js
and styles.js....
...
export const colors = {
'green' : '#######'
....
}
export const test = () => {
console.log(arguments);
}
...
and LoginScreen.js
import { test } from '../styles';
export default class LoginScreen {
....
constructor () {
test();
}
....
}
so watch chrome debug console...
Arguments[5]
0:DedicatedWorkerGlobalScope
1:_require(moduleId)
2:Object
3:Object
4:null
callee:(global, require, module, exports)
length:5
Symbol(Symbol.iterator):values()
__proto__:Object
what is this?
imported function always return arguments[5]
I don't know why return that arguments.
I think that this related import? function.
Let me know please

Arrow functions do not bind their arguments. If you want to use variable number of arguments in React Native, you can use rest parameter syntax ... to get an array of arguments.
export const test = (...args) => {
console.log(args);
}
The arguments object should work with named function expressions:
export function test() {
console.log(arguments);
}

Related

Running a method when a module is called?

Consider this:
export default () => ({
init() {
alert('hello');
},
});
Which is called via:
import Test from './Test';
let test = Test();
test.init();
Is there a way to just have a method run without having to call it? For example, could I just do:
import Test from './Test';
let test = Test();
And have something default run?
-----EDIT
I wish to have a module that can be called like:
import Test from './Test';
let test = Test();
But the module should also have various methods in it. Basically - is there some sort of constructor?
export default () => {
console.log('this runs when `Test()` is called')
return {
init() {
console.log('this runs when `test.init()` is called')
}
}
}

Change ESM export bindings

I'm wondering how the exported bindings of an ES6 module work when destructuring. I'm exporting an object (thing) as a named export -- but also one of its properties (foo), too, which I'm later updating.
This update works when I import the object and reference its prop, but not when I directly import foo, as shown below. I'm guessing the export const... creates a new, immutable binding, but is there any way to retain its reference to the original object upon export?
// module: 'thing.js'
let thing = {
foo: (x) => console.log(x)
};
const init = () => {
thing.foo = (x) => console.log("updated");
};
export { init, thing };
export const { foo } = thing;
// index.js
import { foo, thing, init } from "./thing";
init();
foo("test"); // does not work
thing.foo("test"); // update is reflected, here
codesandbox
There is not issue with export/import
see this example:
let thing = {
foo: (x) => console.log(x)
};
const init = () => {
thing.foo = (x) => console.log("updated");
};
const foo = thing.foo;
init();
foo("test"); //test
thing.foo("test"); //updated
Variable foo and field thing.foo contains different functions after you rewrite thing.foo inside init function

How to export functions from a custom hook

The basic structure of my hook:
const useMyHook = () => {
const func1 = (): boolean => { ... }
const func2 = (type: "type1" | "type2"): boolean => { ... }
const func3 = (): boolean => { ... }
return {
func1, func2, func3
}
}
export default useMyHook
I'm currently using it like this, which works in dev, but breaks my build.
import useMyHook from "../hooks/useMyHook";
const { func1 } = useMyHook()
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
const isValid = func1();
if (isValid) {
// do more things
}
}
return (
<form>...</form>
)
When running yarn build, I am faced with this error:
Objects are not valid as a React child (found: object with keys {func1, func2, func3}). If you meant to render a collection of children, use an array instead.
My attempt at solving this was to export my custom hook functions in an array, as the error seemed to suggest.
return [
func1, func2, func3
]
And using it like this:
const [ func1 ] = useMyHook();
const isValid = func1();
TypeScript is not happy with this:
An argument for 'type' was not provided.
But this is confusing, because func1 does not accept a type argument as func2 does.
Questions
Is there some way I work around this build-time error and export the { } of functions? This feels like the cleanest approach.
If there is no way to achieve 1, how can I properly use the exported array of functions without my types being misread?

difference between export default { name } and named export { name }

I am trying to deprecate a module with many named exports like so:
const Foo = () => 'foo';
const Bar = () => 'bar';
export { Foo };
export { Bar };
which is fine when consuming via:
import { Foo, Bar } from './something';
My thoughts about enabling deprecation warnings was to use a default export of type object with a property getter override for each key that prints the deprecation and then returns the module.
The shape then becomes something like:
const something = {};
Object.defineProperty(something, 'Foo', {
get(){
console.warn('Foo is deprecated soon');
return Foo;
}
});
// etc
export default something;
My thinking had been that the destructuring import would figure it out so
import { Foo, Bar } from './something';
... would continue to work as before. Instead, webpack complains that something does not have a named export Foo or Bar
using this, however, works:
const { Foo, Bar } = require('./something');
I can also have import something from './something'; const { Foo, Bar } = something and that works but it defeats the purpose if I have to refactor every import that exists.
So the question really is about how import { Foo, Bar } from './something'; works compared to the require() - I'd have thought that if the default export is an object, it would figure it out and destructure, but no joy.
Is there an easy way to do this 'proxying' without changing how the exports are being consumed elsewhere?
I think i made it work. Bare in mind that this is a workaround.
Given that you said that the library is being "re-exported" from a single file you could add an additional "layer" to the "re-export" where we turn the "re-exportation" file into a JS file and write our own associated typing file for it.
Working repl: https://repl.it/#Olian04/CelebratedKlutzyQuotes
Code snippets:
// index.ts
// consuming the library
import { Foo } from './demo';
console.log(Foo());
// library.ts
// the library it self
const Foo = () => 'foo';
export { Foo }
// demo.js
// the workaround implementation
const depricatedLibrary = require('./library');
const something = new Proxy(depricatedLibrary, {
get(obj, key) {
if (typeof key === 'string') {
console.warn(key + ' is deprecated soon');
}
return obj[key];
}
});
module.exports = something;
// demo.d.ts
// the workaround types
export * from './library';

Mocking exported exports in Jest

I am having a problem whereby if I export * from submodule (using ES6 module syntax and babel) I am unable to mock the submodules functions using Jest from the entry point. I wondered if anyone out there could help...
For example given this structure:
+ __tests__
| |- index.js
+ greeter
| |- index.js
| |- submodule.js
|- index.js
And this code:
index.js
import { sayHello } from "./greeter";
export const greet = (name) => sayHello(name);
greeter/index.js
export * from "./submodule.js";
greeter/submodule.js
export const sayHello = (name) => console.log(`Hello, ${name}`);
__tests__/index.js
import { greet } from "../index";
import * as greeter from "../greeter";
describe("greet", () => {
it("Should delegate the call to greeter.sayHello", () => {
const name = "John";
greet(name);
});
});
This all works fine and when the test runs it passes. Hello, John is printed to the console as expected. The advantage that make this worth it to me is that index.js is completely unaware of the structure of the greeter module, so i can restructure and refactor that code without worrying about my consumers.
The Rub comes when I try and mock out greeter.sayHello...
__tests__/index.js
import { greet } from "../index.js";
import * as greeter from "../greeter";
greeter.sayHello = jest.fn();
describe("greet", () => {
it("Should delegate the call to greeter.sayHello", () => {
const name = "John";
greet(name);
expect(greeter.sayHello).toHaveBeenCalledWith(name);
});
});
Now instead of the test passing as expected - I get an error:
Test suite failed to run
TypeError: Cannot set property sayHello of [object Object] which only has a getter
...(stack trace)
Changing the greeter import in __tests__/index.js to:
import * as greeter from "../greeter/submodule";
Makes the test pass but puts the coupling back in my test code.
Is there another way?
In order to mock a imported method on the file you want to test you need make sure the mock ran before you import your file(index.js), like this:
// import { greet } from "../index.js"; =====> Import on each test case(it)
// import * as greeter from "../greeter"; =====> Mock on each test case(it)
// greeter.sayHello = jest.fn(); =====> Would be not good to do this, it will mess with the entire import and this jest.fn will be share across your tests making it gives you false positives.
describe("greet", () => {
it("Should delegate the call to greeter.sayHello", () => {
const name = "John";
jest.mock('../greeter', () => ({ sayHello: jest.fn() })); // here you mock the import, remember it needs to be before you require your index.js
const greet = require('../index.js').greet; // require after the mock
greet(name);
expect(greeter.sayHello).toHaveBeenCalledWith(name);
});
});

Categories