React Native - import javascript file into another javascript file as text - javascript

I've got a MyFirstPage.js file which is something like this:
renderCards() {
let icon = this.state.icon;
....
....
....
}
Which i write to render my cards inside my main render function! The point is, because it's getting too long (about 350 lines), i want to create another file and import this renderCards() AS TEXT so i can i have it in the MyFirstPage.js main render!
Please note that let icon = this.state.icon; which refer to the MyFirstPage.js state - so i have to import it AS TEXT.
I tried:
export default {
renderCards() {
....
....
....
}
}
but not working!
Any idea?
Thanks in advance!

You can define code in a string and execute it in Javascript. We can use eval() to evaluate a String as a piece of code. This approach has a security, reliability, and performance concerns because eval can essentially inject code into your script, and that code is simply determined by what String is passed to it. That said, most Babel transpiling presets use strict mode, and this limits eval to some extent by ultimately not allowing it to instantiate new variables in the surrounding scope. What it can still do, is define a function and evaluate that function and assign it to a variable in the external scope like so:
var a = 5
var b = 10
var c = eval('function abc() { return a + b }; abc;')
assert(c() === 15)
With this ability in hand, we can wrap your entire 'renderCards' function definition in a String (by way of template literal):
export default `renderCards() {
let icon = this.state.icon;
....
....
....
}; renderCards;`
Import this string (import renderCardsImport from {relative path to file} in the react component MyFirstPage.js, and in the constructor you need to do a few things:
constructor(props){
super(props)
this.state = {
icon: // whatever this is
}
let renderCards = eval(renderCardsImport)
// so you have access to the parent class object this
this.renderCards = renderCards.bind(this)
}
And now you should be able to call renderCards() in the render() method or anyplace else in the component. Phewww. That was a doozy, but learned so much about eval, strict mode, etc. Hope it helps.
EDIT: You can also use the Function constructor it appears, as in var myFunct = Function('body of function with a return statement') but you will need to remember to bind it to this as well. If you use Function, you avoid performance and security hit of eval. Strict mode takes away most of the reliability problems.

Related

Variable not defined when used outside of Vue <template>

I am exporting a value from a JS file and using it in my Vue. I display the value like in my template, but I would like to also use this value elsewhere, outside of the template.
Here is a simplified version of my setup and what I would like to achieve:
In my myJS.js (in actual app this file is used to call my API):
const appService = {
getPosts() {
return 123456;
}
}
export default appService
and then I have a VUE component that looks like this:
<template>
{{ info }}
</template>
alert(info);
import appService from '../myJS'
export default {
name: 'myvue',
props: {
msg: String
},
data () {
return {
info: {}
}
}
async created () {
this.info = await appService.getPosts();
}
}
The value is displayed in the template, but the alert(info) triggers a 'info is undefined' error.
How can I use this value in normal JavaScript outside of my template?
Hope that makes sense.
Thanks in advance!
There's basically two ways:
Assign the value to a variable, inside the file, but outside the component definition. So in your example you would say let info; and in your created() hook you would go this.info = info = await appService.getPosts().
Assign the component itself to a variable before you export it:
const myComponent = { component definition... }
// Access with myComponent.info
export default myComponent;
However! You will see that myComponent.info is initially undefined. And unlike in the template, the value of info will not reactively update when the asynchronous call resolves. Reactivity magic only works in the template and in the code of the actual component, e.g. in computed and watch properties. How to handle the specifics of asynchronous loading elegantly really depends on the specifics of how you want to use this variable.
Finally: the reason you don't just get access to the variable throughout the .vue file is because under the hood, the template compiles to a function which is executed in the context of the component. For convenience, all of the fields of the component are then made available as variables without the usual this prefix. In fact, in your template, info is treated as a shorthand for this.info. (Notice that you can substitute this.info for info in the template and it will still work.) This privilege doesn't apply to any other code in the file; that stuff is just vanilla js code.

How can I make an ES6 named export for parts of an object without exporting the whole object?

Here's a JavaScript object I'm working with:
const tree = {
birdhouse: {
inspectNest: () => 'eggs'
},
...
}
I want the world to have access to the inspectNest function tucked into the middle there, but for hand-wavy reasons I do not want to give my consumers the entire tree object. I was hoping I could do something like this as a named export:
export { tree.birdhouse.inspectNest as inspectNest };
However, including the dot notation to access those properties seems to be invalid syntax.
I suspect a destructuring statement like const { birdhouse: { inspectNest }} = tree; right before exporting may work, but there's another hitch - other parts of my program may redefine birdhouse or inspectNest as the app runs. When that happens, I don't know if the changed item will continue to be exported with the new value.
Any advice, or is destructuring the best approach?
(P.S. I know export const inspectNest = tree.birdhouse.inspectNest; will do the trick, but in my real app I'd need many of these assignment exports. If at all possible, I want to use the named export object to keep things syntactically cleaner.)

Why is arrow syntax preferred over function declaration for functional React components?

I always see examples of functional React components defined with arrow function syntax:
const foo = () => (...);
export default foo;
Rather than the more traditional function declaration syntax:
export default function foo() {
return ...;
}
Is there a reason to prefer the former over the latter?
I would say that this is a bit opinionated choice really. There are at least several reasons why I (personally) see arrow function use for a purely functional component as pretty bad practice. Here are those:
Syntax abuse. When we define function component we don't need to pre-bind its context to a specific scope. The context (this) is going to be undefined anyway in the module namespace. The use of arrow functions is dictated here by pure aesthetics reasons like conciseness. But arrow functions as language feature has a very specific purpose for existence in the first place, and this is not coolness and conciseness.
Error stack trace. Exceptions thrown in arrow function will be less descriptive because arrow function is anonymous by definition. This is not the huge problem probably since React project will most likely be configured with proper source maps support, but still stack trace will be a bit more clear if named function is used. As noted in comments this is not really an issue of the functional component, as the name will be the name of the variable basically.
Less convenient logging. Consider this very typical pure function component style:
const Header = ({ name, branding }) => (
<header>
...
</header>
)
In the function above it's impossible to throw in quick debugger statement or console.log. You will have to temporarily convert it to something like this
const Header = function ({ name, branding }) {
console.log(name)
return (
<header>
...
</header>
)
}
This might be pretty annoying especially for bigger pure functional components.
That being said this is a very popular choice for many teams, also by default preferred by ESLint, so if you don't see the problem with it, then it is probably okay.
Actually, there is no difference between them, I make a little project on the CodeSandBox and make two simple components, one of them is the Arrow component by using the arrow function:
import React from 'react';
const MyArrowComponent = () => (
<main>
<h2>Arrow</h2>
</main>
);
export default MyArrowComponent;
And the other is the Declaration component by using function declaration:
import React from "react";
function MyFunctionComponent() {
return (
<main>
<h2>Declaration</h2>
</main>
);
}
export default MyFunctionComponent;
Then I run the yarn build command and got the bundle like below:
(window.webpackJsonp = window.webpackJsonp || []).push([[0], {
14: function (e, n, t) {
"use strict";
t.r(n);
var a = t(0), r = t.n(a), l = t(2),
c = t.n(l), u = t(3), i = t(4), o = t(6), m = t(5), E = t(7);
var p = function () {
return r.a.createElement("main", null, r.a.createElement("h2", null, "Declaration"))
}, s = function () {
return r.a.createElement("main", null, r.a.createElement("h2", null, "Arrow"))
}, d = function (e) {
function n() {
return (
Object(u.a)(this, n),
Object(o.a)(this, Object(m.a)(n).apply(this, arguments))
}
return Object(E.a)(n, e), Object(i.a)(n, [{
key: "render", value: function () {
return r.a.createElement(
'div',
null,
r.a.createElement('div', null, 'Hi'),
r.a.createElement(p, null),
r.a.createElement(s, null)
);
}
}]), n
}(r.a.Component);
c.a.render(r.a.createElement(d, null), document.getElementById("root"))
}, 8: function (e, n, t) {
e.exports = t(14)
}
}, [[8, 1, 2]]]);
Pay attention to the definition of the Arrow and the Declaration component:
var p = function () {
return r.a.createElement("main", null, r.a.createElement("h2", null, "Declaration"))
}, s = function () {
return r.a.createElement("main", null, r.a.createElement("h2", null, "Arrow"))
}
Both of them are defined in the same way, so definitely there is no difference between them and it is fully opinion based on developers' attitude to code readability and clean code, based on ESLint 5.x in our team, we choose the arrow function to define the functional components.
Function declaration and arrow functions are different in their essence, but in the scope of your question, it's basically a code style preference. I personally prefer Function declaration as I find it easier to spot the meaning of that line of code.
If you will use Arrow functions or Function declarations, try to also think in terms of what makes more sense in the context. To make the code clean and easier to read it isn't only about the amount of code you write but what that code express.
I tend to use Arrow Functions for callbacks, for example, [].map(() => {})
Using Arrow function is way better than using a regular function not only because the syntax is clean and you will be able to write less code with the arrow function but also because of :
Scope safety: when arrow functions are used consistently, everything is guaranteed to use the same thisObject as the root. If even a single standard function callback is mixed in with a bunch of arrow functions there's a chance the scope will become messed up.
Compactness: Arrow functions are easier to read and write.
Clarity: When almost everything is an arrow function, any regular function immediately sticks out for defining the scope. A developer can always look up the next-higher function statement to see what this object is.
For more details, you can take a look at these questions
When should I use Arrow functions in ECMAScript 6?
A few other points not mentioned in other answers:
With arrow function components, when using React dev tools in Chrome/Firefox, those components come up as Anonymous making debugging harder. These Anonymous components are also throughout dev tools including performance flame trees. Functional components display their name in dev tools.
A standard function declaration can be defined on a single line. You don't need to define the export default later in a file. This also makes it easier when you want to add/remove the default keyword.
export default async function MyComponent() {
...
}

Augmenting Object in React

I am working on a project where I have to attach a few utility functions to Javascript Object object as follows:
function isEmpty(a, b) {...}
Object.prototype.isEmpty = isEmpty;
Now the problem i am facing is, since I am working with react, I am guessing the above code is also attaching the isEmpty function to the constructed Components. And this works fine as long as I don't use the native html tags i.e. div, span inside my components which is not possible. I get the following warning
Warning: Unknown prop `isEmpty` on <div> tag.
Remove these props from the element. For details, see
https://facebook.github.io/react/warnings/unknown-prop.html
when I use the native html tags. Is there any way to augment the Object object without getting this error in react?
The problem is that an object extension like this is enumerable. You need to use defineProperty
BTW: this is still a bad idea
When you write jsx tags in react it gets transpiled to objects (React elements).
So
<div id="test">
</div>
is transformed into following object -
var divElement = React.createElement("div", { id: "test" });
Now since you are attaching
function sum(a, b) {...}
Object.prototype.sum = sum;
It gets attached to every objects present.
May be you should consider providing a Util.js which will contain all utility methods and do not attach to Object prototype. Because It can cause undesired side effects.
You can import Util.js where ever you need and use those methods.
e.g. -
module.exports = {
sum(a, b) {...}
};
Problem
All JSX elements are first created as objects (WitVault explains how JSX is transpiled to plain JS that can run in the browser). React takes those objects and their properties that React supports and maps them to DOM elements. If there are properties that React does not know about, it will show a warning because it's likely a case of either "you don't know what you are doing" or "you made a typo", and therefore you won't get the behavior that you expect.
Since you edited the prototype of Object, all objects, also those created by React, get the property sum, and for primitive html elements React does not know how to map a sum property.
As Juan Mendes pointed out, extending native objects is bad practice. If you extend Object.prototype in a React project you really cant avoid the problem you are experiencing.
Solution 1: Export/Import util function
Since React comes with browserify you can instead import utility methods. This has two advantages:
You don't need to extend native objects
You clearly express where the methods used come from, be cause they have an import statement in the file where it's used.
In ES6
// util/objectSum.js
export default function objectSum(object) { ... };
// anotherFile.js
import objectSum from 'utils/objectSum.js'; // assuming utils/ is directly under the root path of your project (root path can be configured in webpack.config if you use webpack)
const object = ?; // the object you want to sum
const sum = objectSum(object);
In ES5
// util/objectSum.js
module.exports = function(object) { ... };
// anotherFile.js
var objectSum = require('utils/objectSum.js'); // assuming utils/ is directly under the root path of your project (root path can be configured in webpack.config if you use webpack)
const object = ?; // the object you want to sum
const sum = objectSum(object);
Solution 2: Using ES6 classes
In ES6 you can also create a class with the sum method. Here's an example:
class NumberList {
constructor(arrayOfNumbers) {
this.numbers = arrayOfNumbers;
this.sum = this.sum.bind(this);
}
sum() {
return this.numbers.reduce((sum, next) => sum + next, 0);
}
}
const numberList = new NumberList([1, 2, 3]);
numberList.sum(); // -> 6

React.js: modify render() method for all components?

For debugging reasons I'd like to add following line into general render() method, so it would be executed in all components.
console.log('render' + this.constructor.displayName, this.state);
I assume you want to do this without changing any of the existing code. I played around with this and found a way to do so if you're using something like webpack or browserify to build your application and you're using React v0.13.
It's important to note that this uses private methods, reaching into React's internals, and could break at any time. That said, it might be useful for your debugging purposes.
[Update to the Update]
If you use Babel, I highly recommend checking out the React Transform plugin. This will let you do all sorts of nifty stuff to React, including wrapping (or overwriting!) render methods.
[Update]
I've found a way to do this without hacking into React.addons.Perf; the key was the module name of ReactCompositeComponent and the function name of _renderValidatedComponent—just wrap that method to inject your custom behavior.
Note you'll need to place this code before you require("react").
var ReactCompositeComponent = require("react/lib/ReactCompositeComponent");
var oldRenderValidatedComponent = ReactCompositeComponent.Mixin._renderValidatedComponent;
ReactCompositeComponent.Mixin._renderValidatedComponent = function() {
var name = this.getName();
if (name && !name.match(/^ReactDOM/)) {
console.log("render: ", this.getName(), {props: this._instance.props, state: this._instance.state});
}
return oldRenderValidatedComponent.apply(this, arguments);
}
You'll then end up with a very similar result as the old answer, below. I've added better logging of props and state, and filter out any of the built in ReactDOM* components.
[Old Answer]
I've overridden the default measure function of the performance tools, which React calls through its codebase to measure performance when using React.addons.Perf. By doing so, we're able to get the information that the default measurement strategy would normally get. Note that this breaks the normal behavior React.addons.Perf.
Add this code to the entry-point of your application (after you require React):
var ReactInjection = require("react/lib/ReactInjection");
var ReactDefaultPerf = require("react/lib/ReactDefaultPerf");
ReactDefaultPerf.start();
ReactInjection.Perf.injectMeasure(function measure(moduleName, fnName, fn) {
return function() {
if (moduleName === 'ReactCompositeComponent' && fnName === '_renderValidatedComponent') {
var name = this.getName();
if (name) {
console.log("render: ", name);
}
}
return fn.apply(this, arguments);
}
});
And you'll get the following in your console logs:
ReactElements with no names (that is, components that make up regular HTML elements like span and div) are not shown. One notable set of exceptions is button and other input elements, as React provides composite components that wrap those to help manage state. They show up as ReactDOMButton and ReactDOMInput.
React supports Mixins for such cross-cutting concerns:
https://facebook.github.io/react/docs/reusable-components.html#mixins
However, it's not permitted to define a render method in a mixin. The restrictions on each of the React lifecycle methods are in the following source:
https://github.com/facebook/react/blob/0c6bee049efb63585fb88c995de788cefc18b789/src/core/ReactCompositeComponent.js#L189
If you could assign this behaviour to one of the other steps in the component lifecycle, mixins might work for you.

Categories