How is this inheritance working in JavaScript? - javascript

Watching a React course, he wanted to extract a Component into a more reusable component, My question/confusion is about this line below:
this.doSubmit(); that how does it even not error? because doSubmit() is in the CHILD class. It is not defined in the parent class. So shouldn't it error?
class Form extends Component {
handleSubmit = (e) => {
e.preventDefault();
// bunch of code then next line is my question:
this.doSubmit();
};
}
class LoginForm extends Form {
doSubmit = () => {
// call server
console.log("submitted");
};
}

Since you mentioned this is a course, I suspect there might be something more. But based on what you provided, this will not work: exactly as you said, the method is in child class.
I created a sample and you will see the error when call handleSubmit(): https://codesandbox.io/s/thirsty-buck-zpgll?file=/src/App.js

Related

Can I wait on connectedCallback finsh work in tests?

I am trying to test some code and I know it will work as expected, but I do not know how can I write tests in that case because my attribute is set always after test have finish?
In general, I have created an abstract WebComponent class which needs to be inherited by my custom web-components instead of HTMLElement. This whole abstract class have some common logic for all my web-components for example setting props if user passed any by constructor.
I have created a simple example to show what I want to achieve. In the example below I am creating a HelloWorld component this component has one observedAttributes which is heading-content (value which will be dispalyed inside <h1></h1> of HelloWorld component template). If users sets heading-content via constructor, then I am saving this value inside this.propsContent. Then after connectedCallback is triggered I am setting this props setContentFromProps which triggers attributeChangedCallback and this callback does the rest.
Is it possible to somehow wait until these actions end?
Example
HelloWorld component:
const template = `<h1 id="hello-world-content"></h1>`;
export class HelloWorld extends HTMLElement {
static TAG = 'hello-world';
static observedAttributes = ['heading-content'];
constructor(props) {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = template;
this.headingContent = null;
this.propsContent = props;
this.helloHeading = this.shadowRoot.querySelector('#hello-world-content');
}
connectedCallback() {
this.setContentFromProps();
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'heading-content') {
this.helloHeading.textContent = newValue;
this.headingContent = newValue;
}
}
setContentFromProps() {
this.setAttribute('heading-content', this.propsContent);
}
}
customElements.define(HelloWorld.TAG, HelloWorld);
HelloWorld unit tests:
import 'jest';
import { HelloWorld } from './HelloWorld';
describe(HelloWorld.name, () => {
test('should set heading content to given value', () => {
const helloWorld = new HelloWorld('dupa');
expect(helloWorld.headingContent).toBe('dupa');
});
});
Test result:
expect(received).toBe(expected) // Object.is equality
Expected: "dupa"
Received: null
Not without adding code; there is no allAttributesChangesDone callback. And its not possible to write unless you know upfront What needs to be changed.
I see, so it is impossible. Anyway thank you for your answer
If you wait till the Event Loop is done; you can be fairly sure all updates are done... unless there is async code doing updates...
"What the heck is the Event Loop:" https://youtube.com/watch?v=8aGhZQkoFbQ&vl=en
That's true but If I wait when EventLoop will become free than my tests can take much more time. Actually, now after I thought more about that my test is 'not working' (in my opinion a few hours ago) I can say I was mistaken and the test works correctly, and I should take care of the case when someone is trying to access the attribute before it is initialized.

ReactJS call parent method over two layers typescript

I got a problem to call a parents method over two layers.
It either does nothing or says, that it is not a function. So here is my Child-Component:
class Child extends React.Component {
render() { //return some awesome HTML, that at some point calls doStuff }
doStuff() {
//do some stuff
this.props.parentState.notifyParent();
}
}
My parent component now got some conditional stuff going on, so it looks like this:
class Parent extends React.Component {
constructor(props : any) {
super(props);
this.state = {
//setSomeProps
updateParent: this.updateParent
};
}
determineUsedComponent(props: any) {
//some conditions
return <Child parentState={props}/>
}
updateParent() {
console.log("Update parent");
}
render() {
return (<this.determineUsedComponent props={this.state}/>)
}
}
I also tried giving the function as single object to the child. Do stuff looks the following then:
doStuff() {
props.notifyParent()
}
while the Parent component then has the determineUsedComponent method with following signature:
determineUsedComponent(props: Any, updateParent: Function) {}
and it gets called:
<this.determineUsedComponent props={this.state} updateParent={this.updateParent}/>
If I then try inside the determineUsedComponent method to insert it like an attribute:
return <Child parentUpdate={this.parentUpdate}/>
It again throws the exception "this.props.notifyParent() not a function".
Instead if I write it like this:
return <Child parentUpdate={()=>this.parentUpdate}/>
There is no error, instead just nothing happens. (Also no log.)
I am very clueless and now tried every possible option of how to write the function and give it to child, but some gave errors (above two) and most didn´t do anything at all.
Any ideas?
Maybe good to mention: Child component is written in pure JS, while Parent is written in Typescript.
Did you try
return <Child parentUpdate={()=>this.parentUpdate()}/>
I didn´t manage to implement it with two layers.
However I found another solution:
You can move the conditional rendering from the "determineComponent"-method directly into the render()-method and then input the parent-function directly (syntax as DarioRega wrote it above). Then it works.

Changing class state from an imported function in ReactJS

I am trying to change the state of a class from an imported named component so I only need to write the code once. Is this even possible?
I have 3 files ( Login, ForgotPassword, Register ). On ALL of these files I am listening for an "onChange" event on the input fields that all do the same thing as show below:
onChange method:
onChange = (e) => {
this.setState(() => ({ errors: {} }));
let fields = this.state.fields;
fields[e.target.name] = e.target.value;
this.setState(() => {
return {
fields
}
});
};
I'd really like to import this as a named method along with some others that are working already:
import { onFocus, onBlur, onChange } from './Utils/Input';
The issue is (as seen above in the onChange code), that I need to update the class state from this method.
Is this at all possible? I am very new to React, so I might be going about this in the completely wrong way.
Thank you in advance!
When trying to update the state of a component you are always updating the state regarding to a particular this.
You are trying to write on* functions which are independent of the instances you are working with. So it makes no sense to use "this" inside those.
You could pass the instance of the Class to the on-function like this:
https://codesandbox.io/s/focused-cache-zzfvp
Use the method by binding the context to it from inside the class like this
onChange.bind(this)

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

Trouble accessing props in callback function of Google Login using react-google-login

I'm using react-google-login in my react-redux project and having trouble accessing the props for the component in which this login button exists. I used react-facebook-login in a similar way and it works fine - however, console.log(this) in the loginGoogle() function prints 'undefined' whereas it printed the Javascript object representing the whole Login component in my similar loginFacebook() method. Any ideas as to how I can access this.props in loginGoogle()?
In my Login component:
//all needed import statements
class Login extends Component {
loginGoogle(response) {
console.log(response);
this.props.loginGoogleRequest(response.profileObj.email, response.accessToken, response.tokenObj.expires_in)
}
render() {
<GoogleLogin
clientId="{client id here}"
onSuccess={this.loginGoogle}
className="custom-google-btn"
/>
}
function mapDispatchToProps(dispatch) {
return {
loginGoogleRequest: (email, accessToken, expiresIn) => {
//some code that isn't being reached
}
}
}
export default connect(mapDispatchToProps)(Login);
I trimmed a lot of the fat out of this class in order to make it more readable - please let me know if it would help if I included more code in any way.
Try change loginGoogle definition to Arrow function:
loginGoogle(response) { => loginGoogle = (response) => {
An arrow function does not create its own "this", the this value of the enclosing execution context is used.
Or you may bind loginGoogle method, refer to this answer:
Why JSX props should not use arrow functions

Categories

Resources