Before marking it as an duplicate read the question completely.
I have two component, say A and B. A extends React.Component and B extends A. Calling super inside the constructor of B will make all the things available under this of A to be available under B also.
The issue I'm facing is, I've a method which will updated the state of A. I'm calling this method from B. This still updates the state of B not A. Is this expected or am I doing anything wrong.
Working example
class A extends React.Component{
constructor(props) {
super(props)
this.updatedState = this.updatedState.bind(this) //bound to this parent
this.state = {
text: 'Hello from the other side!'
}
}
updatedState(){
this.setState({
text: 'I must have called a thousand times!'
})
}
render(){
return <h1>{this.state.text}</h1>
}
}
class B extends A{
constructor(){
super()
}
render(){
return <div>
<h1>{this.state.text}</h1>
<button onClick={this.updatedState}>Update state</button>
</div>
}
}
ReactDOM.render(
<div>
<A/>
<B/>
</div>,
document.getElementById('app')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
Another Example
This is not using the constructor or the super. I instantiate A using new and call the methods. The method is being called but the render is not triggered.
class A extends React.Component{
constructor(props) {
super(props)
this.updatedState = this.updatedState.bind(this) //bound to this parent
this.state = {
text: 'Hello from the other side!'
}
}
updatedState(){
console.log('called')
this.setState({
text: 'I must have called a thousand times!'
})
}
render(){
return <h1>{this.state.text}</h1>
}
}
class B extends A{
render(){
var parent = new A()
return <div>
<h1>{this.state.text}</h1>
<button onClick={parent.updatedState}>Update state</button>
</div>
}
}
ReactDOM.render(
<div>
<A/>
<B/>
</div>,
document.getElementById('app')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
Your second example does not work as it supposed to.
class B extends A{
render(){
var parent = new A()
return <div>
<h1>{this.state.text}</h1>
<button onClick={parent.updatedState}>Update state</button>
</div>
}
}
In the above there is a B object which extends A.
Assuming that this instance of B references adress 0x001 in memory.
var parent =new A() creates an A object and it references another address in memory for example 0x002. This reference is kept in memory which is reserved for instance of object B extends A. that's it. they have just Has - a realationship. But B extends A (B is A ) so they have is-a relationship.
http://www.w3resource.com/java-tutorial/inheritance-composition-relationship.php
Extending B with A doesn't link any new instance of B with a new instance of A. Furthermore, try composition instead of inheritance. There is no specific use case in inheritance that composition doesn't cover. Composition is more natural, more easier to reason, behavior is more explicit and also a lot safer.
Here's how I would do it with composition. I don't know what exactly your use case is, so pardon me if the following refactored example doesn't fit in with what you're trying to accomplish. But nevertheless, you should be able to achieve the same with composition instead of having to use inheritance.
class A extends React.Component {
render () {
return <h1>{this.props.displayText}</h1>
}
}
class B extends React.Component {
state = {
displayText: 'Hello from the other side!'
}
updateState () {
let displayText = 'I must have called a thousand times!';
this.setState({
displayText: displayText
}, () => this.props.onUpdateClick(displayText));
}
render () {
return <div>
<h1>{this.state.displayText}</h1>
<button onClick={this.updateState.bind(this)}>Update state</button>
</div>
}
}
class C extends React.Component {
state = {
displayTextA: 'Hello from the other side!'
}
changeA (value) {
this.setState({
displayTextA: value
});
}
render () {
return (
<div>
<A displayText={this.state.displayTextA} />
<B onUpdateClick={this.changeA.bind(this)} />
</div>
)
}
}
ReactDOM.render(
<div>
<C/>
</div>,
document.getElementById('app')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
Here are a few posts that you might find helpful:-
Composition vs Inheritance
Mixins Are Dead. Long Live Composition
Related
I know how it can be done with Functional Components. But when it comes to class components, I'm having few questions to be clarified.
I've a class here,
class MyTable extends Component {
constructor(props) {
super(props);
this.state = {
page:0,
rowsPerPage:10
}
}
handleChangePage(event) {
//Here I want to update only **page** keeping **rowsPerPage** intact
}
handleChangeRowsPerPage(event) {
//Here I want to update only **rowsPerPage** keeping **page** intact
}
render() {
return(
<SomeComponent
onChangePage={this.handleChangePage}
onChangeRowsPerPage={this.handleChangeRowsPerPage}
/>
)
}
}
export default Mytable;
So here what I want to know is,
If I want to update only page inside the state object, should I have to preserve rowsPerPage and update them both as
this.setState({page:<updatedValue>, rowsPerPage:<preservedValue>);
And Vice versa
What code goes inside handleChangePage and handleChangeRowsPerPage, if we can update independent properties inside a state object.
What's the best practice when we've several such states and we want to update each one independently?
You can update page and rowsPerPage independently as I did bellow. You have just to call this.setState and passing and object with the key of state you want to update
class MyTable extends React.Component {
constructor(props) {
super(props);
this.state = {
page:0,
rowsPerPage:10
}
this.handleChangePage = this.handleChangePage.bind(this);
this.handleChangeRowsPerPage = this.handleChangeRowsPerPage.bind(this);
}
handleChangePage(event) {
//Here I want to update only **page** keeping **rowsPerPage** intact
this.setState({page: event.target.value});
}
handleChangeRowsPerPage(event) {
//Here I want to update only **rowsPerPage** keeping **page** intact
this.setState({rowsPerPage: event.target.value});
}
render() {
return (
<div>
<div>
Page <input type="text" value={this.state.page} onChange={this.handleChangePage} />
</div>
<div>
rowsPerPage <input type="text" value={this.state.rowsPerPage} onChange={this.handleChangeRowsPerPage} /></div>
</div>
)
}
}
ReactDOM.render(<MyTable />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I do not know what is wrong with this code
I also did binding but still, it doesn't have any effect
<div id="root">
</div>
<script type="text/babel">
class Counter extends React.Component{
constructor(props){
super(props);
this.state={count:0};
this.clickHandler=this.clickHandler.bind(this);
};
clickHandler(){
this.setState((prevState,props)=> {count: prevState.count+5});
};
render(){
return <button onClick={this.clickHandler}> {this.state.count}</button>
};
};
var element=<Counter />
ReactDOM.render(element, document.getElementById('root'));
</script>
Are you getting any error? Your click handler must be like this.
clickHandler() {
this.setState((prevState,props)=> ({count: prevState.count+5}));
};
Check the ( added in front of the object and ) after it.
clickHandler() {
this.setState(
{
count: this.state.count + 5
}
);
}
I'm trying to get the listing of a component in the DOM. Something like
document.getElementsByTagName("ComponentName") but with a component name.
React Components aren't part of the DOM Model. As such, you cannot get a list of Components from the document object.
What you can do instead is to give the React Components you're interested in finding, a certain css class name, which you then can find in the DOM.
For example:
class MyComponent extends React.Component {
render(){
return (
<div className="myComponent">{this.props.children}</div>
);
}
}
class MyApp extends React.Component {
render(){
return (
<div>
<MyComponent>foo</MyComponent>
<MyComponent>bar</MyComponent>
</div>
);
}
}
ReactDOM.render(<MyApp />, document.getElementById("myApp"));
/* get components from their class name: */
var list = document.getElementsByClassName("myComponent");
for (var item of list) {
console.log(item)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="myApp"></div>
You can of course also use id and use document.getElementById() (if the id is unique) or name and use document.getElementsByName(), and other methods. I think class makes most sense.
I have a problem with the prop. Below is my code and I don't understand why when I'm rendering paragraph with {this.props.name}, it doesn't show the name from props. It may be a stupid question but I've just started my adventure with React so I need your help.
class CardGenerator extends React.Component{
render(){
return (
<div>
<Name/>
</div>
)
}
}
class Name extends React.Component{
render(){
return <p>{this.props.name}</p>
}
}
ReactDOM.render( <CardGenerator name='David'/>, document.getElementById('app'))
Because you are not passing the props to Name component. You are passing the prop name to CardGenerator component there it will be available by this.props.name. To access that inside Name component you need to pass the value to Name component again.
Use this:
class CardGenerator extends React.Component{
render(){
return (
<div>
<Name name={this.props.name}/>
</div>
)
}
}
class Name extends React.Component{
render(){
return <p>{this.props.name}</p>
}
}
ReactDOM.render( <CardGenerator name='David'/>, document.getElementById('app'))
Check the working example:
class CardGenerator extends React.Component{
render(){
return (
<div>
<Name name={this.props.name}/>
</div>
)
}
}
class Name extends React.Component{
render(){
return <p>{this.props.name}</p>
}
}
ReactDOM.render( <CardGenerator name='David'/>, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='app'/>
You are passing the name to the CardGenerator component, but then the CardGenerator component is not passing the name to the Name component.
I would like to call in the external script, or console React components of the method
I tried to do so
componentDidMount(){
window.mwap = this;
}
but no use
enter image description here
please help me
The return value of ReactDOM.render() is actually the mounted instance of the component:
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
inc() {
this.setState({count: this.state.count + 1});
}
render() {
return (
<div>
Count: {this.state.count}
</div>
)
}
}
const instance = ReactDOM.render(
<Counter />,
document.getElementById('app')
);
instance.inc();
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
If you need access to a deeply nested component, that's a bit more difficult, but this should get you started.