Lightning Web Component: recordId unavailable from inside constructor - salesforce

The following code prints "undefined from constructor" but gets the correct recordId when used by the button click from handleClick(). Would anyone know what I'm missing? Thank you in advance.
import { LightningElement, api } from 'lwc';
export default class Tester extends LightningElement {
#api recordId;
constructor(){
super();
console.log(this.recordId + ' from constructor');
}
handleClick(){
console.log(this.recordId + ' from click handler')
}
}

The parent properties such as recordId are not passed until after the constructor is called and the component is attached to the dom. See the code below.
For more information about lifecycle methods go here:
https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.reference_lifecycle_hooks
import { LightningElement, api } from 'lwc';
export default class Tester extends LightningElement {
#api recordId;
constructor(){
super();
}
connectedCallback(){
console.log(this.recordId + ' from connectedCallback')
}
handleClick(){
console.log(this.recordId + ' from click handler')
}
}

A workaround, just delay the connectedCallback some ms.
import { LightningElement, api } from 'lwc';
export default class Tester extends LightningElement{
#api recordId;
connectedCallback(){
setTimeout(() => {
alert(this.recordId);
}, 5);
}
}

Related

Class variables in REACT

Does class variables in a class need to be a part of the stateObject? I tried below with no luck. Here there is samples with simple variables so I am kind of surprice below does not work (alert says undefined)?
https://www.w3schools.com/react/react_es6.asp
https://codesandbox.io/s/jovial-glade-lfv4f?fontsize=14&hidenavigation=1&theme=dark
import React, { Component } from "react";
class Test extends Component {
constructor(props) {
super(props);
this.variable = "works";
}
clicked() {
alert(this.variable);
}
render() {
return <div onClick={this.clicked}>CLICK ME</div>;
}
}
export default Test;
You need to use bind() call to make it work.
constructor(props) {
super(props);
this.variable = "works";
this.clicked = this.clicked.bind(this);
}
for more information on this checkout Handling events in React
Why you have to bind here? so this is because you are using ES6 syntax for your components, and in ES6 class methods are not bound to classes by default, and to be able to use this keyword inside your methods and make it refer to the class instance you have bind your method to the class like in this answer.
import React, { Component } from "react";
class Test extends Component {
constructor(props) {
super(props);
this.variable = "works";
}
clicked = () => {
alert(this.variable);
}
render() {
return <div onClick={this.clicked}>CLICK ME</div>;
}
}
export default Test;
You can choose not to bind but you need to be adding fat-arrow function syntax in order to make it work.

Do I have to use a constructor when importing an external module I made in React?

I made a module in react.
So, I imported the module. And then, the function of the external module was called using the constructor.
import { connect } from './api';
...
class App extends Component {
constructor(props) {
super(props);
connect(message => {
console.log(message);
});
}
render(){
...
}
}
But I would like to express class fields syntax without using a constructor.
import { connect } from './api';
...
class App extends Component {
connect(message => {
console.log(message);
});
render(){
...
}
}
The results of the above code, 'connect' function is not executed because 'connect' is not declared.
Can't I get an function of external module without a constructor?
Here is your connect.js:
export const connect = message => {
console.log(message);
};
Here is your component:
import React from 'react';
import { connect } from './connect';
class App extends React.Component {
componentDidMount() {
connect('connected');
}
render() {
return (
<div>
<h1>Some Text...</h1>
</div>
);
}
}
export default App;
Should be fairly clear... If you have a question ask...

how do I declare additional property for React class component?

I rewrite my React Project with TypeScript. now I know how to declare property interface and state interface for a Class Component, simple like this:
export interface ComponentProps {
propName: string
}
interface ComponentState {
stateName: number
}
class myComponent extends React.Component<ComponentProps, ComponentState> {
...
}
but error accur when I do something in componentDidMount() lifecycle:
componentDidMount() {
this.customProperty = 26; // here I could save an id returned by setInterval to cancel it in the componentWillUnmount() for example.
}
[ts] Property 'customProperty' does not exist on type 'MyComponent'. [2339]
What can I do to declare additional property correctly, not just simple silence the error.
I've learned the basic of typescript.
import React, { Component } from 'react';
export interface CheckoutProps {
total: number;
customer: string;
}
interface State {
isChecking: boolean;
}
class Checkout extends Component<CheckoutProps, State> {
state = {
isChecking: false
};
componentDidMount() {
this.customProperty = 'sean';
}
render() {
return <div>hello</div>;
}
}
export default Checkout;
Class level properties can be defined after the class declartion,
They can be initialized either at the time of declartion or in constructor.
Change your Class To :-
class Checkout extends Component<CheckoutProps, State> {
customProperty:string=''; //Here,you can define your class level properties
state = {
isChecking: false
};
componentDidMount() {
this.customProperty = 'sean';
}
render() {
return <div>hello</div>;
}
}
Hope this helps,
Cheers !!
You can declare it within the class:
class myComponent extends React.Component<ComponentProps, ComponentState> {
private customProperty: string = '';
componentDidMount() {
this.customProperty = 'sean';
}
}

React TS: Despite passing method through wrapper, child still can't access getPage()

I'm trying to build a fetch method that can be shared to a bunch of Reader components through a higher order component. I believe I've built the HOC right, but I'm not 100% sure.
import React, { Component } from 'react';
import base from "./firebase";
export default (ChildComponent) => {
class GetPage extends Component<{},any> {
constructor(props: any) {
super(props);
this.state = {
text: "Hii"
};
}
public getPage(page: string) {
base
.fetch(page, { context: this, })
.then(data => this.setState({ text: data }));
console.log(this.state.text)
}
public render() {
return <ChildComponent getPage={this.getPage} text={...this.state.text} {...this.props}/>;
}
}
return GetPage;
};
You can see that I'm importing the HOC on the second line , but despite this, the 'Reader' component is throwing an error that 'getPage' is no where to be found.
import * as React from "react";
import GetPage from "./fetch";
class Reader extends React.Component<{},any>{
public componentWillMount() {
this.getPage('1A1');
}
public render() {
return <div{...getPage('1A1')}>{...this.state.text}</div>;
}
}
export default (GetPage(Reader));
Inside your Reader component instead of accessing this.getpage try with this.props.getpage
and I don't understand why you are doing with following:
<div{...getPage('1A1')}>

Meteor React Komposer: Execute Component Constructor AFTER ready subscription

I have a React Component Post:
export class Post extends React.Component {
constructor(props) {
this.state = this.props;
}
...
}
, which I compose with
import { composeWithTracker } from 'react-komposer';
import { composeWithTracker } from 'react-komposer';
import Post from '../components/post.jsx';
function composer(props, onData) {
const subscription = Meteor.subscribe('post', props.postId);
if (subscription.ready()) {
const data = {
ready: true,
posts: Posts.findOne(props.postId).fetch()
}
onData(null, data);
} else {
onData(null, {ready: false});
}
}
export default composeWithTracker(composer)(Post);
. As given in the Post Component I want to put some properties in the state of the component, but the constructor will be executed before I get the data from the composer!
How do I wait until the data is send and then put my props into the state?
Isn't this what the React Kompose should do? BTW I am using Version 1.~ to get composeWithTracker.
You could use componentWillReceiveProps to get new properties and set as component state. This function will run whenever there are new properties passed to component:
export class Post extends React.Component {
// ...
componentWillReceiveProps(nextProps) {
this.setState({
...nextProps,
});
}
// ...
}

Resources