Exporting React Component - javascript

I have started to learn ReactJS, I have a question about this case. const is used before declaration and it doesn't throw error. Why?
import React from "react";
export class item extends React.Component {
render() {
return <div style={customStyle}>test</div>;
}
}
const customStyle = { color: red };
export default item;

The reference to customStyle is inside a function, so it is resolved only when the function is called, which is after all the definitions have been processed.

Using means accessing. If you would construct a new item instance and call it's render method before the const customStyle line, then it would throw.
JS does not semantically enforce that a variable declared with let or const cannot be used before it's initialization, it is just a runtime error to do so.
The same behaviour can be seen if you access variables that don't exist at all:
function see() {
console.log(a); // not a semantical error, this is totally fine ...
}
// ...unless you try to execute it
see();

Related

React app - disparity between debugger and console log

I've had this issue pop up in one form or another over the years, and I finally figured out how to put it to words. Consider the following code:
import React, {Component} from "react";
import aFunction from "./Function";
export default class SomeComponent extends Component{
constructor(props){
super(props);
}
render(){
console.log(aFunction);
debugger;
return(
<div>some stuff</div>
)
}
}
The console.log() call will print information about aFunction, but if I type "aFunction" into the browser console I get a reference error. Why does this happen? Shouldn't console.log and the browser console via debugger have access to the same scope?
EDIT: I should clarify that I'm getting a reference error after allowing the "debugger" to occur before typing "aFunction". I'm not trying to call up block scoped variables after render() has completed.
It's an engine optimisation. Variables are invisible if they are not needed.
You can use a small hack to prevent it.
eval('debugger');
And when you use console.log you have it in your scope.
So, you can use another hack:
const temp = smthFromParentScope;
debugger;
It happens when you are in a nested function and there are no functions that have a reference to them.
function foo() {
const a = 1;
const b = 2;
function bar() {
console.log(a); // now we have a ref
}
function baz() {
debugger; // here we can see only 'a'
}
}

Why can I use a variable before declaring it in JavaScript / TypeScript?

To my understanding, after ES6 and the introduction of let and const, a variable declared with them must be declared before it's used. However, I have run into many examples where my code runs just fine when I declare the variables after its use. For example, this is the code from (a simplified version of) the TypeScript template of React Native:
import React from 'react';
import {StyleSheet, Text} from 'react-native';
const App = () => {
return (
<>
<Text style={styles.text}>Some text</Text>
</>
);
};
const styles = StyleSheet.create({
text: {
backgroundColor: 'blue',
},
});
export default App;
Here, styles are declared after they are used, and it even seems to be the idiomatic way to do it, but even ESLint highlights as no-use-before-define.
My question is: why does it still work?
You aren't using it before it is declared.
The variable isn't used until the function it is used inside is called.
Essentially what is happening is
const styles = StyleSheet.create({});
has been declared as a called function. So on declaration the function is run, the variable is assigned the object;
const App = () => {return()};
is declaring App will be a function, the constructor for this will be called when it is executed from the Main process and currently you are just exporting it from the module. So at the point of export Styles has been declared with the object returned, and App has been declared awaiting future execution.

Updating my imported variable's value in React.js

I am refractoring an app I've build using React.js. I am exporting a variable from the global scope of Spotify.js and importing it in two other files App.js and Button.js.
After calling a function from Spotify.js that sotres a new value to the variable, It's new value is exported to 'Button.js' but stays an empty string in 'App.js'.
Your help would be appriciated :)
export let userAccessToken = '';
export const Spotify = {
...
getUserAccessToken (){
//stores a new string to userAccessToken.
}
}
import {userAccessToken, Spotify} from '../../util/Spotify';
export class App extends React.Component {
//a conditional rendering happens depending on if(!userAccessToken)
}
import {userAccessToken, Spotify} from '../../util/Spotify'
export class Button extends React.Component {
componentDidMount() {
if (!userAccessToken) {
console.log(`Button's UAT before calling the fn: ${userAccessToken}`)
Spotify.getUserAccessToken();
console.log(`Button's UAT after calling the fn: ${userAccessToken}`);
}
}
...
}
This is not how you share data between react components.
Use react context or pass props between components
You could use react context to share data or simply pass it as props (if the components are closely related in the component tree)
The only thing I can recommend is to export the userAccessToken, something like this, but you can't change its value outside the module
export const Spotify = {
...
getUserAccessToken (){
//stores a new string to userAccessToken.
}
}
...
}
const accessToken = Spotify.getUserAccessToken();
export const userAccessToken = accessToken;
If you got to read this question I solved it.
Turns out I should have called my method Spotify.getUserAccessToken() from App.js using the react lifecycle method componentDidMount().
The export and import methods are like snapshots of the module and therefore when I exported the variable userAccessToke from Spotify.js before calling the my method I imported an empty string and it did not update in all files.
Thanks Jørgen and joseluismurillorios for your support and time spent answering :)

JS Class that return a function

So i love this React thingy, and we have this so called 'stateless' functions to help us build a 'dumb' component. Now i want to create a class that produce a stateless function. Why you may ask, well i love the idea of inheritance and wanting to 'extend' my stateless function basic capability, said i want to add a helper function as a statics that binds to the function itself.
I ended up with this code
class Stateless {
constructor() {
return this.render.bind(this)
}
nanny() {
// do something
}
render(props) {
// yeay! a stateless function!
// plus i can access nanny by using this.nanny()
}
}
And when i extend it, i can see that the inheritance is working well.
BUT, if then i initialize the class:
const stateless = new Stateless()
Why can't i access stateless.nanny even tho inside the render function i can see that this.nanny is accessible? Where does the nanny lives? Does it binded to the render function?
EG:
class Stateless {
constructor() {
return this.render.bind(this)
}
nanny() {
console.log('foo')
return true
}
render(props) {
console.log(this.nanny()) // -> returns 'foo'
return 'JSX'
// this should return a JSX
}
}
const stateless = new Stateless() // -> stateless IS a function
stateless()
// 'foo'
// true
// JSX
stateless.nanny
// undefined
While clearly inside render when i called this, there is nanny there. But when i
refer it outside, the nanny is gone. I thought nanny should be a static property of the stateless, right?
If you are returning object from constructor - new will return that object instead of the instance of the class being constructed (more info).
Therefore line
const stateless = new Stateless()
will assign to stateless variable result of this.render.bind(this) - that is reference to method (function) of Stateless class, that is not an instance of Stateless. Therefore stateless.nanny makes no sense - as function render does not have such property defined. On the other hand calling bound render function directly - produce the expected result.
All in all - i strongly do not recommend you to return anything from constructor (unless you are dealing with some really weird requirements like controlling number of instances and such). It makes code hard to understand and maintain.
Your example should work if you remove this.render.bind(this) from your constructor.
It should also work, if you just remove return from the constructor:
constructor() {
this.render.bind(this)
}
However, you might actually be looking to create a higher order component that can enhance the component that it wraps.
Your higher order component is a function that returns a class that renders the component that it passed to it:
import React from 'react'
function HigherOrderComponent(WrappedComponent) {
return class Enhancer extends React.Component {
constructor(props) {
super(props)
}
exampleFunc() {
// Code here
}
render() {
return <WrappedComponent exampleprop={ this.exampleFunc } />
}
}
}
export default HigherOrderComponent
Then you can import HigherOrderComponent into your stateless dumb component file and wrap the export:
import React from 'react'
import HigherOrderComponent from './HigherOrderComponent'
const DumbComponent = (props) => {
// Return JSX
// You can use props.exampleprop
}
export default HigherOrderComponent(DumbComponent)
Here are some articles that you can read on higher order components:
https://facebook.github.io/react/docs/higher-order-components.html
https://medium.com/#franleplant/react-higher-order-components-in-depth-cf9032ee6c3e

React - binding `this` to an imported function

In my React app, I have a handful of functions that I'd like to be able to access across a few similar components... however, I want to bind this to the shared functions so that they can do things like update the component state, etc... however, it seems that importing the functions and then trying to bind this in the 'typical' React manner does not work.
Here's an illustration of what I'd like to accomplish - in this case, clicking the rendered button would call the function from the imported shared function file and update the component state:
//shared_functions.js
const sharedFunctions = {
testFunction = () => {
this.setState({functionWasRun: true})
}
}
//MyComponent.jsx
import React, { Component } from 'react';
import sharedFunctions from '../static/scripts/shared_functions.js';
let { testFunction } = sharedFunctions;
class MyComponent extends Component {
constructor(props){
super(props);
this.testFunction = this.testFunction.bind(this)
this.state = {
functionWasRun: false
}
}
render(){
return(
<div>
<button onClick={this.testFunction}>Click</button>
</div>
)
}
}
Trying to run this code as is will return an error like:
Uncaught (in promise) TypeError: Cannot read property 'bind' of undefined
and I get what that's all about... but what I'd like to know is: is it possible to bind this to an imported function?
I'm starting to get a lot of similar-looking functions popping up throughout my app and I'd love to simplify things by abstracting them into a shared script, but I'm not sure how to achieve the typical this binding that's needed to achieve state-setting.
The following line is not trying to bind the imported testFunction but rather a method testFunction of <MyComponent>
To bind the imported function, refer to it directly, as follows:
this.testFunction = testFunction.bind(this);
// Notice how: ^--- there is no longer a this here
NB: You're example tries to use bind on an arrow function You cannot bind a new context to an arrow function. The this context of an arrow function will always be set to the location
were it is defined. You can get around this by declaring
testFunction using a regular function declaration:
const sharedFunctions = {
function testFunction(){
this.setState({functionWasRun: true})
}
}
I used it in the following way:
In constructor:
this.handleChange = handleChange.bind(this);
In the imported file (be careful, no arrow):
export const handleChange = function handleChange(event)
{
const { name, value } = event.target;
this.setState({
[name]: object
});
};
import ToastTimeout from 'toastTimout'
ToastTimeout.bind(this)('message to popup')
I was able to get the context of this in a simple service with a setTimeout function that changed the variable on this context
sorry for the sudo code

Categories

Resources