I've this App React component (TypeScript):
class App extends React.Component {
public state = {
text: ''
}
constructor(props: any) {
super(props);
this.state = { text: 'something' };
}
public handleClick = () => {
const date = `new ! : ${new Date().toString()}`;
// tslint:disable-next-line:no-console
console.log('click ! : ' + date);
this.setState({
text: date
});
};
public render() {
return (
<div className="App">
<button onClick={this.handleClick}>Button</button>
<p>{this.state.text}</p>
<Hello />
</div>
);
}
}
And this Hello component:
export class Hello extends React.Component {
#lazyInject("nameProvider")
private readonly nameProvider: IProvider<string>;
public render() {
return <h1>Hello {this.nameProvider.provide()}!</h1>;
}
}
Where the nameProvider is a simple provider which return based on a random number a string.
When clicking the button, the Date gets updated, however also the Hello component is re-rendered each time.
Is this expected? If yes, please explain.
And can this behaviour be changed?
Check full example project here...
You can make Hello component a PureComponent by extending React.PureComponent, so that it doesn't re-render on every parent render
export class Hello extends React.PureComponent {
#lazyInject("nameProvider")
private readonly nameProvider: IProvider<string>;
public render() {
return <h1>Hello {this.nameProvider.provide()}!</h1>;
}
}
Related
So I am building my first react project and stumbled upon following problem:
In my App.js (main application) I got a function and render my components:
class App extends Component {
constructor(props) {
super(props);
this.candidateCounter = 0;
this.setCandidateVote = this.setCandidateVote.bind(this);
}
...
setCounter (name) {
this.candidateCounter++;
console.log(this.candidateCounter);
}
render() {
...
<Candidates setCounter={this.setCounter} />
}
}
The child component Candidates.jsx has another function and thus calls another component:
export class Candidates extends React.Component {
constructor(props) {
super(props);
this.AppProps = props;
}
...
registerVote(name) {
...
this.AppProps.setCounter(name);
}
render() {
...
<MyButton id={this.state.candidates[i].name} register={this.registerVote} />
}
And the last component MyButton.jsx looks like this:
export class MyButton extends React.Component {
constructor(props) {
super();
this.ParentProps = props;
this.state = { active: false }
}
buttonActiveHandler = () => {
this.setState({
active: !this.state.active
});
if (this.state.active === false) {
this.ParentProps.register(this.ParentProps.id);
}
else {
...
}
}
render() {
return (
<Button content='Click here' toggle active={this.state.active} onClick={this.buttonActiveHandler} />
);
}
}
I have successfully debugged that all functions calls are working except when the grandchild MyButton has triggered the registerVote() function in my Candidates module. Logging in this method gets printed but it cannot call this.AppProps.setCounter() from the parent App. I receive the following error:
TypeError: Cannot read property 'setCounter' of undefined
I hope this wasn't too complicated explained, any help is appreciated :)
Simply bind the function in the constructor of the class as #qasimalbaqali stated in his comment.
constructor(props) {
super();
this.registerVote = this.registerVote.bind(this);
}
Let say I have this Parent
const Parent = () => <ChildComponent foo={<Button>clic</Button>} />
why would this code work
class ChildComponent extends React.Component {
render() {
return (
<div>
{this.props.foo}
</div>
)
}
}
but this code would not ?
class ChildComponent extends React.Component {
constructor(props) {
super(props)
const ParentButton = this.props.foo
}
render() {
return (
<div>
<ParentButton />
</div>
)
}
}
I need something like the second example in order to add some event to ParentButton.
I'd like to make this example work with class defined component
Update :
Based on answer I now have a partial solution
class ChildComponent extends React.Component {
constructor(props) {
super(props)
this.ParentButton = this.props.foo
}
render() {
return (
<div>
{this.ParentButton}
</div>
)
}
}
You're not assigning ParentButton to the ChildComponent.
What you currently have is a const floating in the constructor since const, let and var keywords are function/block scoped.
this. ParentButton = this.props.foo and succinctly <this. ParentButton > in your render function will get you what you're after.
Say you have a parent component:
// ParentComponent
class ParentComponent extends React.Component {
render() {
return(
<ChildComponent/>
)
}
}
From inside the child component, is there a way to access the class name of the parent component without passing this down as props?
// ChildComponent
class ChildComponent extends React.Component {
// ?????
getParentComponentName() {
return this.??? // Should return "ParentComponent"
}
render() {
return(
<div/>
)
}
}
I'd prefer to be able to access this without passing it down as props. Thank you!
You need to access ReactInternalFiber like
class Child extends React.Component {
constructor(props) {
super(props);
this.state = { name: '' }
}
getParentName = () =>{
this.setState({ name: this._reactInternalFiber._debugOwner.type.name })
}
render() {
return (
<div>
<h1>Name: {this.state.name}</h1>
<button onClick={this.getParentName}>Get Parent Name</button>
</div>
)
}
}
How can I show a component randomly on every page load (using React)?
For example, I have two components:
<ComponentOne /> and <ComponentTwo />
I would like to randomly show one of the components on each page load.
Should I do it in componentDidMount()?
class MyComponent extends React.Component {
loadRandomComponent() {
// return <ComponentOne /> || <ComponentTwo />
}
componentDidMount() {
this.loadRandomComponent();
}
}
See if that helps
class ComponentThree extends React.Component {
render() {
return <div>ComponentThree</div>;
}
}
class ComponentTwo extends React.Component {
render() {
return <div>ComponentTwo</div>;
}
}
class ComponentOne extends React.Component {
render() {
return <div>ComponentOne</div>;
}
}
class Hello extends React.Component {
randomize(myArray) {
return myArray[Math.floor(Math.random() * myArray.length)];
}
render() {
var arr = [<ComponentOne />, <ComponentTwo />, <ComponentThree />]
return <div>Hello {this.randomize(arr)}</div>;
}
}
I want to achieve navigation based on hash change in url.
for example for url index.html#HomePage the app will load HomePage component.
import { HomePage } from '../components/homepage'
import { AnotherPage } from '../components/anoterpage'
export class NavigationFrame extends React.Component<any, State> {
constructor(props) {
super(props);
this.state = { pageName: this.pageNameFromUrl() };
}
onHashTagChanged = () => {
this.setState({pageName: this.pageNameFromUrl()});
}
public render() {
var Page = this.state.pageName as any;
return <Page /> //this renders <homepage /> when this.state.pageName = "HomePage";
}
}
is there any way how to dynamically create component based on string?
class CustomComponent extends React.Component{
render(){
return (
var DynamicComponent = this.props.component;
return <DynamicComponent />;
)
}
}
import it into your file and use like below,
return (
<CustomComponent component={this.state.pageName} />
);