I have a JS Fiddle with the below code.
I have a dynamic component setup, which does work. If I do var Component = Switch or set Component to some other React component, it works. But I want to be able to have it switch when I click on it.
So I set up an onClick event. Yet its not firing. I get no log statements or any change. Any ideas why?
var Other = React.createClass({
render: function () {
return <h2>Test this craziness</h2>;
}
});
var Switch = React.createClass({
render: function () {
return <h2>A different one to switch with</h2>;
}
});
var Hello = React.createClass({
getInitialState: function() {
return {on: true};
},
handleClick: function() {
console.log('handleclick');
this.setState({on: ! this.state.on});
},
render: function() {
console.log(this.state);
var Component = this.state.on ? this.props.component.name : Switch;
return <Component onClick={this.handleClick} />;
}
});
ReactDOM.render(
<Hello component={{name: Other}} />,
document.getElementById('container')
);
Easy! When onClick is put directly on a Component, like you have done, it is NOT set as the onClick function. It is instead placed in this.props.onClick. You still need to add the onClick to your actual DOM Elements. See the attached JSFiddle!
You need to add the onClick attribute to an actual HTML element, i.e.
var Other = React.createClass({
render: function () {
return <h2 onClick={this.props.onClick}>Test this craziness</h2>;
}
});
Related
I can call ReactDOM.render only after the element with id react-container has loaded, therefore I must have it in the document.ready, but doing it like I did in the snippet, just returns undefined and does not update its value after the overlay object is properly set in the document.ready function.
code:
var Overlay = React.createClass({
getInitialState: function() {
return { show: false };
},
render: function() {
if (!this.state.show) {
return null;
}
return(
<div>Hello</div>
);
}
});
var overlay;
$( document ).ready(function() {
overlay = ReactDOM.render(
<Overlay />,
$('#react-container')[0]
);
});
module.exports = overlay;
Moving the ReacDOM.render function outside this file is problematic, because I am not transforming (.jsx -> .js) the file where I want to use it.
In this tutorial he uses an onClick function with bind.
<Card onClick={that.deletePerson.bind(null, person)} name={person.name}></Card>
When I remove the bind like this
<Card onClick={that.deletePerson(person)} name={person.name}></Card>
I get an error
Uncaught Error: Invariant Violation: setState(...): Cannot update
during an existing state transition (such as within render). Render
methods should be a pure function of props and state.
I know what bind does, but why is it needed here? Is the onClick not calling the function directly?
(code is in this JSbin: https://jsbin.com/gutiwu/1/edit)
He's using the bind so that the deletePerson method gets the correct person argument.
Because the Card component doesn't get a full Person object, this allows him to identify which person's card was actually clicked.
In your example, where you removed the bind onClick={that.deletePerson(person)} is actually evaluating the function that.deletePerson(person) and setting that as onClick. The deletePerson method changes the Component's state, which is what the error message is saying. (You can't change state during a render).
A better solution might be to pass the id into Card, and pass it back up to the app component on a delete click.
var Card = React.createClass({
handleClick: function() {
this.props.onClick(this.props.id)
}
render: function () {
return (
<div>
<h2>{this.props.name}</h2>
<img src={this.props.avatar} alt=""/>
<div></div>
<button onClick={this.handleClick}>Delete Me</button>
</div>
)
}
})
var App = React.createClass({
deletePerson: function (id) {
//Delete person using id
},
render: function () {
var that = this;
return (
<div>
{this.state.people.map(function (person) {
return (
<Card onClick={that.deletePerson} name={person.name} avatar={person.avatar} id={person.id}></Card>
)
}, this)}
</div>
)
}
})
I want to write a simple mixin for a tooltip. I already know how to bind my mixin to DOM events:
componentDidMount: function() {
var el = this.getDOMNode();
el.addEventListener('mouseenter', this.mouseenter, false);
el.addEventListener('mouseleave', this.mouseleave, false);
},
...but I'd like to bind to the React events instead, to take advantage of its consistent event system. How do I do it?
I think you probably want to do this in the render method of the mixing component, by passing in the mixin's mouseenter and mouseleave handlers as props. I think one option might look like this:
var MouseMixin = {
getMouseProps: function() {
return {
onMouseEnter: this.mouseenter,
onMouseLeave: this.mouseleave
}
},
mouseenter: function() {
console.warn('mouseenter', arguments)
},
mouseleave: function() {
console.warn('mouseleave', arguments)
}
};
Then, in addition to mixing this in, you'd need to apply the behavior. In JSX in React 0.12, you can use the ... spread operator to help with this:
var Example = React.createClass({
mixins: [MouseMixin],
render: function() {
return (
<div { ...this.getMouseProps() }>
Hello world
</div>
)
}
});
See a working fiddle here.
Here is the piece of code from the react-grid-layout documentation
var ReactGridLayout = require('react-grid-layout');
//...
render: function() {
var layout = getOrGenerateLayout();
return (
<ReactGridLayout className="layout" layout={layout}
cols={12} rowHeight={30}>
<div key={1}>1</div>
</ReactGridLayout>
)
}
With this I want to extract the div element in an React component. So I've added this piece of code :
var SimpleDiv = React.createClass({
render() {
return (<div>1</div>);
}
});
And so the first part becomes :
var ReactGridLayout = require('react-grid-layout');
//...
render: function() {
var layout = getOrGenerateLayout();
return (
<ReactGridLayout className="layout" layout={layout}
cols={12} rowHeight={30}>
<SimpleDiv key={1}>1</SimpleDiv>
</ReactGridLayout>
)
}
And the problem is that it's not working, the div element is present but no class name transformation occurs.
Am I missing something ?
The problem is that you are wrapping the div element in your custom component so when the ReactGridLayout component tries to set properties on its children it'll be setting them on the SimpleDiv component. You might be able to make it work by passing along the props like:
var SimpleDiv = React.createClass({
render() {
return (<div {...this.props}>1</div>);
}
});
or explicitly:
var SimpleDiv = React.createClass({
render() {
return (<div style={this.props.style} className={this.props.className}>1</div>);
}
});
But I'm not too familiar with ReactGridLayout so if that doesn't work you may have to ping them and ask if it's possible.
If you don't mind an extra 'div' element, you could use:
render: function() {
var layout = getOrGenerateLayout();
return (
<ReactGridLayout className="layout" layout={layout}
cols={12} rowHeight={30}>
<div key={1}><SimpleDiv>1</SimpleDiv></div>
</ReactGridLayout>
)
}
I'm trying to unmount a React.js node with this._rootNodeID
handleClick: function() {
React.unmountComponentAtNode(this._rootNodeID)
}
But it returns false.
The handleClick is fired when I click on an element, and should unmount the root-node. Documentation on unmountComponentAtNode here
I've tried this as well:
React.unmountComponentAtNode($('*[data-reactid="'+this._rootNodeID+'"]')[0])
That selector works with jQuery.hide(), but not with unmounting it, while the documentation states it should be a DOMElement, like you would use for React.renderComponent
After a few more tests it turns out it works on some elements/selectors.
It somehow works with the selector: document.getElementById('maindiv'), where maindiv is an element not generated with React.js, and just plain html. Then it returns true.
But as soon as I try and select a different ElementById that is generated with React.js it returns false. And it wont work with document.body either, though they all essentially return the same thing if I console.log them (getElementsByClassName('bla')[0] also doesn't work)
There should be a simple way to select the node via this, without having to resort to jQuery or other selectors, I know it's in there somewhere..
Unmount components from the same DOM element that you mount them in. So if you did something like:
ReactDOM.render(<SampleComponent />, document.getElementById('container'));
Then you would unmount it with:
ReactDOM.unmountComponentAtNode(document.getElementById('container'));
Here is a simple JSFiddle where we mount the component and then unmount it after 3 seconds.
This worked for me. You may want to take extra precautions if findDOMNode returns null.
ReactDOM.unmountComponentAtNode(ReactDOM.findDOMNode(this).parentNode);
The example I use:
unmount: function() {
var node = this.getDOMNode();
React.unmountComponentAtNode(node);
$(node).remove();
},
handleClick: function() {
this.unmount();
}
You don't need to unmount the component the simple solution it's change the state and render a empty div
const AlertMessages = React.createClass({
getInitialState() {
return {
alertVisible: true
};
},
handleAlertDismiss() {
this.setState({alertVisible: false});
},
render() {
if (this.state.alertVisible) {
return (
<Alert bsStyle="danger" onDismiss={this.handleAlertDismiss}>
<h4>Oh snap! You got an error!</h4>
</Alert>
);
}
return <div></div>
}
});
As mentioned in the GitHub issue you filed, if you want access to a component's DOM node, you can use this.getDOMNode(). However a component can not unmount itself. See Michael's answer for the correct way to do it.
First , i am new to reactjs ,too . Of course we can control the Component all by switch the state , but as I try and test , i get that , the React.unmountComponentAtNode(parentNode) can only unmount the component which is rendered by React.render(<SubComponent>,parentNode). So <SubComponent> to be removed must be appened by React.render() method , so I write the code
<script type="text/jsx">
var SubComponent = React.createClass({
render:function(){
return (
<div><h1>SubComponent to be unmouned</h1></div>
);
},
componentWillMount:function(){
console.log("componentWillMount");
},
componentDidMount:function(){
console.log("componentDidMount");
},
componentWillUnmount:function(){
console.log("componentWillUnmount");
}
});
var App = React.createClass({
unmountSubComponent:function(){
var node = React.findDOMNode(this.subCom);
var container = node.parentNode;
React.unmountComponentAtNode(container);
container.parentNode.removeChild(container)
},
componentDidMount:function(){
var el = React.findDOMNode(this)
var container = el.querySelector('.container');
this.subCom = React.render(<SubComponent/> , container);
},
render:function(){
return (
<div className="app">
<div className="container"></div>
<button onClick={this.unmountSubComponent}>Unmount</button>
</div>
)
}
});
React.render(<App/> , document.body);
</script>
Run the sample code in jsFiddle , and have a try .
Note: in the sample code React.findDOMNode is replaced by getDOMNode as the reactjs version problem .