Currently constructing an App in reactjs and hit a strange issue. JSX code is below (sorry it's a bit verbose):
var NavigationTab = React.createClass({
onClick: function() {
console.log('NT' + this.props.tab.index);
this.props.onTabClick(this.props.tab.index);
},
render: function(index){
return (
<li>
<a href="#" onClick={this.onClick} className='navigation-tab'> {this.props.tab.title} </a>
</li>
)
}
});
var NavigationPanel = React.createClass({
getInitialState: function() {
return {
};
},
onTabClick: function(tab) {
//console.log(i) ;
this.setState({active : tab});
this.props.showTab(tab);
},
render: function() {
var self = this;
var tabs = this.props.tabs.map(function(item, index){
item.index = index;
return <NavigationTab tab={item} onTabClick={self.onTabClick} />;
});
return (
<div id='navigation-panel' className='col-xs-2'>
<ul className='nav nav-pills nav-stacked'>
{tabs}
</ul>
</div>
);
}
});
var App = React.createClass({
getInitialState: function() {
return {
tabs: [
{title: 'test', ref: 'test', content: <div> test </div>},
{title: 'Dasboard', ref: 'dashboard', content: <div> home </div>},
{title: 'Settings', ref: 'settings', content: <div> settings </div>},
{title: 'Logout', ref: 'logout', content: <div> logout </div>}
],
activeTab: 0};
},
showTab : function(index) {
console.log('AP ' + index);
this.setState({activeTab : index});
},
render: function() {
console.log('AP ' + this.state.activeTab);
console.log('AP ' + this.state.tabs[this.state.activeTab].title);
return (
<div id="container">
<NavigationPanel showTab={this.showTab} tabs={this.state.tabs} />
<div id="content-body">
{this.state.tabs[this.state.activeTab].content} /* [1] */
</div>
</div>
);
}
});
What happens is after changing tabs, the first tab 'test' will no longer display.
If I change the line at /* [1] */ to {this.state.tabs[this.state.activeTab].ref} it works as expected.
Here is a fiddle
In older versions of React, you couldn't reuse component descriptors and needed to recreate them when rendering them multiple times. Your code works fine with React 0.11.
Related
I'm pretty new to React (coming from Angular 1), and have been playing around with it somewhat. I have a test script that loops through a multidimensional object, and binds it to the dom.
I then add a new item to the object wrapped in a setTimeout. Is calling the ReactDOM.render below that the best way to rerender the React component?
var items = [
{ name: 'Matt', link: 'https://google.com' },
{ name: 'Adam', link: 'https://bing.com' },
{ name: 'Luke', link: 'https://yahoo.com' },
{ name: 'John', link: 'https://apple.com' }
];
var RepeatModule = React.createClass({
getInitialState: function() {
return { items: [] }
},
render: function() {
var listItems = this.props.items.map(function(item) {
return (
<li key={item.name}>
<a className='button' href={item.link}>{item.name}</a>
</li>
);
});
return (
<div className='menu'>
<h3>The List</h3>
<ul>
{listItems}
</ul>
</div>
);
}
});
ReactDOM.render(<RepeatModule items={items} />, document.getElementById('react-content'));
setTimeout(function() {
var newline = { name: 'Added item', link: 'https://amazon.com' };
items.push(newline);
ReactDOM.render(<RepeatModule items={items} />, document.getElementById('react-content'));
}, 2000);
Much appreciated :)
React docs advise to place async calls in the componentDidMount method.
Load Initial Data via AJAX Fetch data in componentDidMount. When the
response arrives, store the data in state, triggering a render to
update your UI.
https://facebook.github.io/react/tips/initial-ajax.html
Here is a demo: http://codepen.io/PiotrBerebecki/pen/KgZGao
const App = React.createClass({
getInitialState: function() {
return {
items: [
{ name: 'Matt', link: 'https://google.com' },
{ name: 'Adam', link: 'https://bing.com' },
{ name: 'Luke', link: 'https://yahoo.com' },
{ name: 'John', link: 'https://apple.com' }
]
};
},
componentDidMount: function () {
setTimeout(() => {
this.setState({
items: [
...this.state.items,
{ name: 'Added item', link: 'https://amazon.com' }
]
});
}, 2000);
},
render: function() {
var listItems = this.state.items.map(function(item) {
return (
<RepeatModule key={item.name} href={item.link} itemName={item.name} />
);
});
return (
<div>
<h3>The List</h3>
{listItems}
</div>
);
}
});
const RepeatModule = React.createClass({
render: function() {
return (
<div className='menu'>
<ul>
<li>
<a className='button' href={this.props.href}>{this.props.itemName}</a>
</li>
</ul>
</div>
);
}
});
ReactDOM.render(
<App />,
document.getElementById('app')
);
Wrap the RepeatModule within a parent component. Items should be part of the state. Have a button to add new item. On click of the new item, pass the item details to the parent component. The parent component should update the state.
Your code won't work because you are pushing item to items. You should slice it before pushing it. React checks for props / state change using the === operator.
setTimeout(function() {
var newline = { name: 'Added item', link: 'https://amazon.com' };
var newItems = items.slice();
newItems.push(newline);
ReactDOM.render(<RepeatModule items={newItems} />, document.getElementById('react-content'));
}, 2000);
You could use the react state
working demo: http://codepen.io/anon/pen/WGyamK
var RepeatModule = React.createClass({
getInitialState: function() {
return { items: [
{ name: 'Matt', link: 'https://google.com' },
{ name: 'Adam', link: 'https://bing.com' },
{ name: 'Luke', link: 'https://yahoo.com' },
{ name: 'John', link: 'https://apple.com' }
] }
},
componentDidMount() {
var _this = this
setTimeout(function() {
var newline = { name: 'Added item', link: 'https://amazon.com' };
_this.setState({items: _this.state.items.concat(newline)});
}, 2000);
},
render: function() {
var listItems = this.state.items.map(function(item) {
return (
<li key={item.name}>
<a className='button' href={item.link}>{item.name}</a>
</li>
);
});
return (
<div className='menu'>
<h3>The List</h3>
<ul>
{listItems}
</ul>
</div>
);
}
});
ReactDOM.render(<RepeatModule />, document.getElementById('react-content'));
That being said, you should use some library trigerring the rerender for you. You are coming from Angular, so firstly you need to know that React is not a whole framework like angular, but just the "V in MVC".
I use react in combination with redux. Check out https://github.com/reactjs/redux for more.
There are some good boilerplate codes out there to get started quickly. I like this https://github.com/davezuko/react-redux-starter-kit
Hope you find this useful.
I am very new to React and am just getting my feet wet. I'm having a hard time understand why this isn't re-rending the List. Here is my code:
app.jsx
var Hello = React.createClass({
getInitialState: function() {
return {
links: ['test ']
}
},
render: function() {
return <div className = "row">
<Submission linkStore = {this.state.links}/>
<List links = {this.state.links} />
</div>
}
});
var element = React.createElement(Hello, {});
ReactDOM.render(element, document.querySelector('.container'));
In my submission.jsx I have this function to push info into the links array
handleSubmitClick: function() {
this.props.linkStore.push(this.props.text)
this.setState({text: ''})
console.log(this.props.linkStore)
}
My list.jsx looks like this
module.exports = React.createClass({
getInitialState: function() {
return {
links: this.props.links
}
},
render: function() {
return <div>
{this.props.links}
</div>
}
});
Everything works as intended and I can get the test to show appropriately.
I am aware that this isn't going to show up as an actual list and that I should create a list component to show the items in list form. I'm just trying to run tests along the way to see how everything works.
Use parent state instead of child props.
try this
app.jsx
var Hello = React.createClass({
getInitialState: function() {
return {
links: ['test ']
}
},
handleListSubmitClick: function(params) {
this.setState({links:params});
},
render: function() {
return <div className = "row">
<Submission linkStore = {this.state.links} handleListSubmitClick={this.handleListSubmitClick}/>
<List links = {this.state.links} />
</div>
}
});
submission.jsx
handleSubmitClick: function() {
var linkStore = this.props.linkStore;
linkStore.push(this.props.text)
this.setState({text: ''})
this.props.handleListSubmitClick(linkStore);
}
but I don't understand this.props.text. input's value using this.refs.ref
list.jsx
module.exports = React.createClass({
getInitialState: function() {
return {
links: this.props.links
}
},
render: function() {
return <div>
{this.props.links}
</div>
}
});
I have an application that, in IE9, does not seem to render properly on state change. Pretty much it is just a product grid that when you click on an object, it should pop open a modal box with some product information and the ability to add the item to your shopping cart. Right now, the grid renders, and when an object gets clicked only the modal overlay gets shown but the modal content is never loaded. This works in all other browsers. In addition, this works when IE9 dev console is open.
Here's pretty much how we are doing this:
var Modal = React.createClass({
propTypes: {
modalOpen: React.PropTypes.bool.isRequired,
children: React.PropTypes.element.isRequired,
onClose: React.PropTypes.func
},
render: function() {
if (this.props.modalOpen) {
return (
<div>
<div className="modal-overlay" onClick={this.props.onClose} />
<div className="modal-content">
{this.props.children}
</div>
</div>
)
}
else {
return (<div />)
}
}
});
var ProductModal = React.createClass({
propTypes: {
modalOpen: React.PropTypes.bool.isRequired,
onClose: React.PropTypes.func
},
render: function() {
return(
<Modal modalOpen={this.props.modalOpen} onClose={this.props.onClose}>
<div className="pdModal">
This is where product details would go if we had them...
</div>
</Modal>
);
}
});
var ProductGrid = React.createClass({
getInitialState: function() {
return {
modalIsOpen: false
}
},
openModal: function() {
this.setState({
modalIsOpen: true
});
},
closeModal: function() {
this.setState({
modalIsOpen: false
});
},
render: function() {
return (
<div>
<div onClick={this.openModal}>CLICK ME TO OPEN THE MODAL</div>
<ProductModal modalOpen={this.state.modalIsOpen} onClose={this.closeModal} />
</div>
);
}
});
ReactDOM.render(
<ProductGrid/>,
document.getElementById('container')
);
Fiddle available here. Yes I know the fiddle works on IE9, which is weirder because this is exactly how this is implemented on our site. The only difference is that we are making an ajax request and waiting for results before rendering.
Any thoughts?
I'm trying to get familiar with how inheritance works between components in react.js and I'm having a bit trouble.
Requirements - Basically, what I want to achieve is for the value of my check box to change when I click on the button.
The check box is inheriting the value of 'checkedVal', which is set in state in the Heading.
I can get the correct value in the checkbox when it first loads but cannot change it when I click on the button. Any ideas would be appreciated?
var Heading = React.createClass({
propTypes: {
name: React.PropTypes.string,
age: React.PropTypes.number
},
getDefaultProps: function(){
return {
name: 'Keir',
age: 24,
}
},
getInitialState: function(){
return {
manU: false,
checkedVal: false
}
},
manUFan: function(){
this.setState(function(previousState, currentProps){
return {
manU: !previousState.manU,
checkedVal: !previousState.checkedVal
}
});
},
render: function(){
var msg;
if(this.state.manU){
msg = "I am a United fan."
} else {
msg = "I dream of being a united fan."
}
return (
<div>
<h1>Attempting React</h1>
<ul>
<li>{this.props.name}</li>
<li>{this.props.age}</li>
</ul>
<button onClick={this.manUFan}>Do You Support Man U?</button>
<CheckBox checkBoxVal={this.state.checkedVal}/>
<p>{msg}</p>
</div>
)
}
});
var CheckBox = React.createClass({
propTypes: {
checkBoxVal: React.PropTypes.bool
},
render: function(){
return (
<div>
<input type="checkbox" defaultChecked={this.props.checkBoxVal}/>
</div>
)
}
});
ReactDOM.render(<Heading />, document.getElementById('content'));
The defaultValue and defaultChecked props are only used during initial render. If you need to update the value in a subsequent render, you will need to use a controlled component. https://facebook.github.io/react/docs/forms.html#controlled-components
So in your case here's how you'd implement a controlled CheckBox.
var Heading = React.createClass({
...
getInitialState: function(){
return {
checkedVal: false
}
},
handleChange: function(event){
this.setState({checkedVal: event.target.value});
},
render: function(){
...
return (
<div>
...
<CheckBox onChange={this.handleChange} checkBoxVal={this.state.checkedVal}/>
...
</div>
);
}
});
var CheckBox = React.createClass({
propTypes: {
checkBoxVal: React.PropTypes.bool
},
render: function(){
return (
<div>
<input type="checkbox" onChange={this.props.onChange} value={this.props.checkBoxVal}/>
</div>
);
}
});
i see rubix code
http://wrapbootstrap.com/preview/WB09498FH (site right up demo click)
it is code in react component
javascript
//react ES6
var InboxItem = React.createClass({
mixins: [State, Navigation],
statics: {
ID: 0,
resetID: function() {
InboxItem.ID = 0;
},
getID: function() {
return ++InboxItem.ID;
}
},
handleClick: function(e) {
e.preventDefault();
e.stopPropagation();
this.transitionTo('/app/mailbox/mail');
},
render: function() {
var classes = classNames({
'inbox-item': true,
'unread': this.props.unread
});
var props = {
href: '/app/mailbox/mail',
onClick: this.handleClick,
...this.props,
className: classes
};
return (
<a {...props}>
<div className='inbox-avatar'>
<img src={this.props.src} width='40' height='40' className={this.props.imgClass + ' hidden-xs'} />
<div className='inbox-avatar-name'>
<div className='fg-darkgrayishblue75'>{this.props.name}</div>
<div><small><Badge className={this.props.labelClass} style={{marginRight: 5, display: this.props.labelValue ? 'inline':'none'}}>{this.props.labelValue}</Badge><span>{this.props.description}</span></small></div>
</div>
<div className='inbox-date hidden-sm hidden-xs fg-darkgray40 text-right'>
<div style={{position: 'relative', top: 5}}>{this.props.date}</div>
<div style={{position: 'relative', top: -5}}><small>#{InboxItem.getID()}</small></div>
</div>
</div>
</a>
);
}
});
onClick next line code
...this.props
and
return next line code
a {...props}
what is this "..." ?
As #zerkms mentioned in the comments; it is the Object Rest/Spread Properties syntax in the ECMAScript 2016 (ES7) Proposal, also mentioned in the React docs.
The code you see
var props = {
href: '/app/mailbox/mail',
onClick: this.handleClick,
...this.props,
className: classes
};
gets evaluated to the following, where the props object properties get extended onto the new props object:
var props = {
href: '/app/mailbox/mail',
onClick: this.handleClick,
src: 'https://example.com',
name: 'myName',
labelClass: 'myLabelClass',
labelValue: 'mylabelValue',
className: classes
};