Handling the screen orientation change in ReactJS - reactjs

I am trying to create a Component whose content changes when the screen orientation(portrait/landscape) changes. This is what I am doing:
var Greeting = React.createClass({
getInitialState: function() {
return {orientation: true}
},
handleChange: function() {
if ('onorientationchange' in window) {
window.addEventListener("orientationchange", function() {
this.setState({
orientation: !this.state.orientation
})
console.log("onorientationchange");
}, false);
} else if ('onresize' in window) {
window.addEventListener("resize", function() {
this.setState({
orientation: !this.state.orientation
})
console.log("resize");
}, false);
}
},
render: function() {
var message = this.state.orientation ? "Hello" : "Good bye"
return <p>{message}</p>;
}
});
ReactDOM.render(
<Greeting/>, document.getElementById('container'));
How to make sure the state is mutated when the orientation change event is fired .

Your calling to this.setState is wrong. Need to change it to be like:
handleChange: function() {
var self = this; // Store `this` component outside the callback
if ('onorientationchange' in window) {
window.addEventListener("orientationchange", function() {
// `this` is now pointing to `window`, not the component. So use `self`.
self.setState({
orientation: !self.state.orientation
})
console.log("onorientationchange");
}, false);
}

Related

React testing 'componentWillReceiveProps'

I am a newbie in React.js. While trying to understand the lifecycles in React, i stumbled upon componentWillReceiveProps. Even though i got hold of other functions, i am still not able to figure out componentWillReceiveProps. I created a small snippet where on every button click, i am incrementing the variable 'val'. When val becomes a multiple of 5, i want to change the value of 'increasing', which i am not able to do.
My Code is:
var Increment = React.createClass({
getInitialState: function() {
return {val: 0, increasing: false};
},
componentWillMount: function() {
console.log("componentWillMount");
},
componentDidMount: function() {
console.log("componentDidMount");
},
handleClick: function() {
console.log("inHandleClick");
console.log(this.state.val);
this.setState({val: (this.state.val+1)});
},
componentWillReceiveProps : function(nextProps) {
this.setState({
increasing: (nextProps.val > this.props.val)
});
},
shouldComponentUpdate: function(nextProps, nextState) {
return (nextState.val % 5 ==0)
},
render: function() {
console.log(this.state.increasing);
return (
<div>
<button onClick={this.handleClick}>{this.state.val}</button>
</div>
);
}
});
ReactDOM.render(<Increment />, mountNode);
Any Leads? Thanks in advance
See this fiddle
var IncrementButton = React.createClass({
componentWillReceiveProps : function(nextProps) {
this.setState({
increasing: (nextProps.val > this.props.val)
});
},
render: function() {
return (<button onClick={this.props.handleClick}>{this.props.val}</button>);
}
});
var Increment = React.createClass({
getInitialState: function() {
return {val: 0, increasing: false};
},
handleClick: function() {
console.log("inHandleClick");
console.log(this.state.val);
this.setState({val: (this.state.val+1)});
},
shouldComponentUpdate: function(nextProps, nextState) {
return (nextState.val % 5 ==0)
},
render: function() {
console.log(this.state.increasing);
return (
<div>
<IncrementButton handleClick={this.handleClick} val={this.state.val}/>
</div>
);
}
});
React.render(<Increment />, mountNode);
(Thanks to #Aaron for a more accurate description below)
componentWillReceiveProps is called if your component's props get set; note it may be called even though the props haven't changed in value (You seem to take this into account with your greater than check). Since you want to compare a new value of props to an old value, you need the state to be managed outside your component. I have therefore, in this sample, split your component into two pieces by extracting the button.

React Component DidMount not called when refresh the Page

I have developed the Component it's look like,
var ManageViewPage = React.createClass({
// Get initial state from stores
getInitialState: function() {
return setViewData();
},
componentDidMount: function() {
SystemMetaItemStore.CallSystemMetaItem("Views");
ItemStore.addChangeListener(this._onChange);
SystemMetaItemStore.addChangeListener(this._onChange);
alert("Did mount");
},
// Remove change listers from stores
componentWillUnmount: function() {
ItemStore.removeChangeListener(this._onChange);
SystemMetaItemStore.removeChangeListener(this._onChange);
alert("Did Unmount");
},
preventDefault: function (event) {
event.preventDefault();
},
DeleteViewclick:function(event)
{
},
render: function() {
return (
<div className="row">
</div>
)
},
_onChange: function() {
this.setState(setViewData());
}
});
module.exports =ManageViewPage;
When I will call this page first time using routing then it will call the alert "did mount" but when I press F5 to refresh the browser it will not called the alert "did mount" so can anyone guide me what I did wrong here ?

How to manage UI feedback?

Is there an established pattern used to manage user interactions with individual components, such as displaying loader spinners, disabling input fields while a form is saving/loading, etc.?
I'm finding myself doing the following in my stores in order to keep components somewhat decoupled from any implied state:
function CampaignStore() {
EventEmitter.call(this);
AppDispatcher.register(payload => {
switch (payload.type) {
// [#1] ---------------v (main action)
case CampaignContants.SAVE:
// [#2] ------------------------v (prepare for the main action)
this.emit(CampaignContants.WILL_SAVE);
const data = payload.data;
if (data.id) {
// [#3] ---v (perform main action in store)
updateCampaign(payload.data).then(_ => {
// [#4] ------------------------v (after main action)
this.emit(CampaignContants.DID_SAVE, 0)
});
} else {
insertCampaign(payload.data).then(campaignId => this.emit(CampaignContants.DID_SAVE, campaignId));
}
break;
// ...
}
}
}
Basically, I just fire an event saying that some action is about to take place, then I perform the action (make API call, etc.), then emit another event when the action completes.
Inside a component, I can just subscribe to a WILL_<action> event, render all the spinners and such, then clear up the screen when the DID_<action> is fired. While this seems to work, it does feel pretty boilerplattie and repetitive, as well as super messy (way too much state that only exists to tweak the UI based on where an action is (between WILL_<action> and *DID_<action>.
// some component
var MyComponent = React.createClass({
getInitialState: function () {
return {
items: [],
loading: false,
saving: false,
checkingPasswordStrength: fase,
// ...
};
},
render: function(){
return (
<div>
{this.state.loading && (
<p>Loading...</p>
)}
{!this.state.loading && (
// Display component in not-loading state
)}
</div>
);
}
});
I think you would be better off using the lifecycle methods such as componentWillMount, componentDidMount, componentWillUpdate, and componentWillUnmount. Using those methods you can inspect the previous/current/next props/state (depending on the method) and respond to that. That way your store only handles your state, and your components become more pure.
we have found a simple loading container component helps here.
so something like this:
const LoadingContainer = React.createClass({
getDefaultProps: function() {
return {isLoadedCheck:(res) => res.data!=null }
},
getInitialState: function() {
return {isLoaded:false, errors:[]}
},
componentDidMount: function() {
if(this.props.initialLoad) { this.props.initialLoad(); }
if(this.props.changeListener) { this.props.changeListener(this.onChange); }
},
onChange: function() {
let res = this.props.loadData();
this.setState({errors: res.errors, isLoaded: this.props.isLoadedCheck(res)});
},
render: function() {
if(!this.state.isLoaded) {
let errors = this.state.errors && (<div>{this.state.errors.length} errors</div>)
return (<div>{errors}<LoadingGraphic /> </div>)
}
return <div>{this.props.children}</div>
}
});
const Wrapper = React.createClass({
getDefaultProps: function() {
return {id:23}
},
render: function() {
let initialLoad = () => someActionCreator.getData(this.props.id);
let loadData = () => someStore.getData(this.props.id);
let changeListener = (fn) => someStore.onChange(fn);
return (<div><LoadingContainer initialLoad={initialLoad}
changeListener={changeListener}
loadData={loadData}
isLoadedCheck={(res) => res.someData != null}><SomeComponent id={this.props.id} /></LoadingContainer></div>)
}
});
while it adds another stateless wrapper, it gives a clean way to make sure your components dont just load on mount and a common place to show api feedback etc.
and with react 14 these sort of pure stateless wrappers are getting a bit of a push, with perf improvements to come, so we've found it scales nicely
This is the pattern which will help you in getting your individual components to manage user interactions
var MyComponent = React.createClass({
getInitialState: function() {
return {
item: [],
loading: true,
};
},
componentDidMount: function() {
//Make your API calls here
var self = this;
$.ajax({
method: 'GET',
url: 'http://jsonplaceholder.typicode.com/posts/1',
success: function(data) {
if (self.isMounted()) {
self.setState({
item: data,
loading: false
});
}
}
});
},
render: function() {
var componentContent = null;
if (this.state.loading) {
componentContent = (<div className="loader"></div>);
} else {
componentContent = (
<div>
<h4>{this.state.item.title}</h4>
<p>{this.state.item.body}</p>
</div>
);
}
return componentContent;
}});

HTML select onChange doesn't fire when value changes

When this.state.selected changes, the select box changes its value correctly, but its onChange method is not called. This is probably because I need two-way-bindings for that, so I've tried the valueLink pattern from the docs, but it still doesn't get fired:
render: function() {
return (
React.createElement("select", { valueLink: { value: this.state.selected, requestChange: this.changeHandler } },
React.createElement("option", { value: 1 }, "1"),
React.createElement("option", { value: 2 }, "2")
)
)
}
See the whole fiddle: http://jsbin.com/tisahiliqi/1/edit?html,output
How can I get requestChange executed without firing an event manually (which is, in my opinion, what two-way-bindings should do for me)?
Did I misunderstand something?
Your code is a little mixed up with React's LinkedStateMixin. If you want to fire your own event handler you can use this:
http://jsbin.com/fuwowifoqe/1/
var MySelect = React.createClass({
getInitialState: function() {
return { selected: 1 }
},
componentDidMount: function() {
// Imagine some AJAX that takes 1s
window.setTimeout(function() {
this.setState({ selected: 2 });
}.bind(this), 1000);
},
changeHandler: function(e) {
// ... Doesn't fire...
alert("Something changed!");
this.setState({selected : e.target.value })
},
render: function() {
return (
React.createElement("select", { value: this.state.selected, onChange: this.changeHandler },
React.createElement("option", { value: 1 }, "1"),
React.createElement("option", { value: 2 }, "2")
)
)
}
});
React.render(React.createElement(MySelect, null, "Hi"), document.getElementById("app"));
Note that the handler is not fired when you change value with setState, but when value is changed via user interaction.
UPDATE
Then you can observe changes to this.state or this.state.selected using one of the life cycle methods such as componentWillUpdate or componentDidUpdate:
jsbin: http://jsbin.com/lipovucapi/1/
componentDidUpdate: function(prevProps, prevState){
if(this.state.selected != prevState.selected)
alert("selected changed!");
},

this.props.children is undefined in ReactJS

I am working with ReactJS and I am trying to get the children from this.props.children however, it is returning undefined. According to the documentation I should have access to this special property.
componentDidMount: function() {
console.log("this",this) // this ReactCompositeComponent.createClass.Constructor
this.setMenuListeners.apply(this);
this.loadMenuFromServer();
},
setMenuListeners: function() {
pubSub.on('mainMenu.menuItemClicked',function() {
console.log(this.props.children) // undefined
}.bind(this))
},
And here is some of the code that is rendering the children:
loadMenuFromServer: function() {
var menus = []
$.getJSON(APPFS.menuItems,function(data){
for(var s in data) {
menus.push(<MenuItem expandable={true} content={s} />)
menus.push(<ul onClick={this.menuItemClicked} className="main-menu-submenu">{
this.loopAndAddMenu(data[s]).map(function(result){
return(result)
})
}</ul>)
}
this.setState({data:menus})
}.bind(this));
},
loopAndAddMenu: function(data) {
var menus = []
for(var s in data) {
menus.push(<MenuItem expandable={false} content={s} key={data[s]} />)
}
return menus
},
render: function(){
return (
<ul className="main-menu">
{this.state.data}
</ul>
)
}

Resources