async load iframe in react - reactjs

I am using an iframe on the webpage which is blocking the rest of the page from rendering until the iframe is completely loaded. How can I enable an async iframe load (or delay the load of the iframe) so the web page element isn't blocked? *the iframe is not providing async loading.

You could initialize the iframe after your componentDidMount like this:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
showIframe: false
};
}
componentDidMount() {
this.setState({showIframe: true});
}
render() {
const { showIframe } = this.state;
return (
<div>
{ showIframe &&
<iframe src={'https://www.example.com'} />
}
</div>
);
}
}
This will render the iframe after your component has mounted.

Related

componentDidMount does not fire on second time then I pass second router paramater value

I am handling react component by using router parameter,and also I have set router paramater value in state using componentDidMount event life cycle.It works fine as per my requirement,but "componentDidMount" does not fire on second time when I pass second router paramater value.Please check my below code and advise how to do this.
import React, { Component } from 'react';
import ConfigItem from '../../Config';
import axios from 'axios';
class ZohoDashboard extends Component {
constructor(props) {
super(props);
this.state = {url: ''};
}
componentDidMount() {
console.log('mount');
axios.get(ConfigItem[0].APIPath+'Menus/'+this.props.match.params.id)
.then(res => {
console.log(res.data.data[0].URL);
this.setState({url:res.data.data[0].URL});
})
}
render() {
console.log('render');
return (
<div class="embed-responsive embed-responsive-21by9">
<iframe class="embed-responsive-item" src={this.state.url} allowfullscreen></iframe>
</div>
);
}
}
export default ZohoDashboard;
Router params in url are supposed to trigger a prop change and hence do not remount the component. Instead they trigger a re-render, you can make use of componentDidUpdate to trigger an API when route param changes
class ZohoDashboard extends Component {
constructor(props) {
super(props);
this.state = {url: ''};
}
componentDidMount() {
console.log('mount');
this.fetchData();
}
fetchData = () => {
axios.get(ConfigItem[0].APIPath+'Menus/'+this.props.match.params.id)
.then(res => {
console.log(res.data.data[0].URL);
this.setState({url:res.data.data[0].URL});
})
}
componentDidUpdate(prevProps) {
if(prevProps.match.params.id !== this.props.match.params.id) {
this.fetchData()
}
}
render() {
console.log('render');
return (
<div class="embed-responsive embed-responsive-21by9">
<iframe class="embed-responsive-item" src={this.state.url} allowfullscreen></iframe>
</div>
);
}
}

React material UI open login dialog if token expired

I am using react material UI. I am frequently checking if token is expired using setInternval() and if its expire than login dialog should be open and setInterval should be cleared using clearInterval(). Below is my code but I am getting warning as Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. and not able to achieve the required result.
App.js
import AuthService from './includes/AuthService.js';
class App extends React.Component {
constructor(props) {
super(props);
this.Auth = new AuthService();
}
componentDidMount(){
setInterval(() => {this.Auth.checkToken()}, 10000);
}
}
AuthService.js
class AuthService extends React.Component{
constructor(props) {
super(props);
this.state = {email: '', password : '', loginOpen : false};
}
checkToken() {
console.log("token checked");
if (decode(localStorage.getItem('jwtToken')).exp < Date.now() / 1000) {
this.setState({loginOpen : true}, () => {
console.log('state updated');
console.log(this.state.loginOpen);
clearInterval();
});
}
}
render(){
const { onRequestClose } = this.props;
const actions = [
<FlatButton
label="Close"
primary={true}
onClick={this.handleClose}
/>,
];
return (
<MuiThemeProvider>
<Dialog title="Result Details"
actions={actions}
modal={false}
open={this.state.loginOpen}
onRequestClose={this.handleClose}
autoScrollBodyContent={true}
>
</Dialog>
</MuiThemeProvider>
}
loginOpen and checkToken() look like something that can be moved up to App component, and be passed to AuthService as props.
Alternatively, you can simply move down and call checkToken() on componentDidMount() function of AuthService.
Like this:
class AuthService extends React.Component{
constructor(props) {
super(props);
// ...
this.checkToken = this.checkToken.bind(this);
this.intervalId = null;
}
componentDidMount(){
this.intervalId = setInterval(() => {this.checkToken()}, 10000);
}
checkToken() {
console.log("token checked");
if (decode(localStorage.getItem('jwtToken')).exp < Date.now() / 1000) {
this.setState({loginOpen : true}, () => {
console.log('state updated');
console.log(this.state.loginOpen);
if (this.itv) {
clearInterval(this.intervalId);
}
});
}
}
See which approach will work better, and see if my fix works, and I can add more explanations.
One more thing I want to point out is that clearInterval(..) takes the ID returned from setInterval.
Hence the setting of this.intervalId and passing it to clearInterval(..).
From your comment:
how can I change state in parent component i.e. app component from its
child component. Becase login modal is in app component.
You are rendering login modal in App component.
You can conditionally render the login modal based on App's this.state.loginOpen.
For example, if your App render function contains a login modal component called LoginModal
render() {
<div>
{ this.state.loginOpen && <LoginModal /> }
</div>
Or, if you are calling some function to show the login modal, you can do something like if (this.state.loginOpen) { showLoginModal(); }.

Using fake xhr request with componentWillMount()

'Home' is an intermediate component that redirects based on a xhr response. I expected 'Home' to display 'Loading ...' as per its render/return, until it receives the xhr response.
But surprisingly,
1) I never see 'Loading ...' at all, but I only see the redirected page.
2) Changing the delay in fake xhr request has no impact, i.e. I still get the response in < 5s
3) Changing componentWillMount() to componentDidMount() has no impact
4) If I comment out componentWillMount() { ... }, then I see 'Loading ...'
Can you please help me understand why ?
xhr.js
const myData = {
getData(cb) {
setTimeout(cb(true), 25000); // fake async
}
};
export default myData;
Home.js
"use strict";
import React from 'react';
import xhr from '../../utils/xhr';
import PropTypes from 'prop-types';
import {withRouter} from 'react-router-dom';
class Home extends React.Component {
constructor(props) {
super(props);
}
componentWillMount() {
const {history} = this.props;
xhr.getData((flag) => {
flag ? history.push('/myData') : history.push('/welcome');
});
}
render() {
return (
<div>Loading ...</div>
);
}
}
Home.propTypes = {
history: PropTypes.object.isRequired
};
export default withRouter(Home);
Your code should work fine with componentDidUpdate except one thing, you didnt run setTimeout correctly
Example:
const getData = cb => {
setTimeout(() => cb(false), 2500); // fake async
};
class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
pageName: "Loading..."
};
}
componentDidMount() {
getData(flag => {
flag
? this.setState({ pageName: "myData" })
: this.setState({ pageName: "wellcome" });
});
}
render() {
return <div>{this.state.pageName}</div>;
}
}
ReactDOM.render(<Home />, document.getElementById("root"));
<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="root"></div>
Update
As commented below i should explain why and where you should invoke async operations.
componentWillMount - Is almost the same as the constructor, it
runs one time before the component is mounted to the DOM.
The render method can be invoked before your async operation has finished
hence it is not ideal to do async operation in this method. By the
way, in the DOCS its clearly says not to use this method and use
the constructor instead.
componentDidMpunt - Will invoked right after the component is
mounted to the DOM, this is the ideal method to run async operations.
Setting the state in this method will trigger a re-render (which
exactly what happens in the example above) DOCS.

Call external Api on button click and then render a child component with the api result data

<!--Weather.js-->
<!-- begin snippet: js hide: false console: true babel: false -->
import React from 'react'
import MyApi from '../api/MyApi';
import InputCity from './InputCity'
import WeatherData from './WeatherData'
export default class Weather extends React.Component{
constructor(props){
super(props);
this.state = {
weather:[],
city: ''
}
}
makeRequest = (city) => {
MyApi.getWeather(city)
.then(function (res) {
this.setState(function () {
return{
weather:res
}
})
}.bind(this));
}
componentDidMount(){
this.makeRequest(this.state.city)
}
setCity = (mycity) =>{
this.setState(function () {
return{
city:mycity
}
})
}
render(){
const showWeatherData = this.state.weather;
return(
<div>
<InputCity setCity={this.setCity}/>
{showWeatherData && <WeatherData city={this.state.city}/>}
{console.log(this.state.weather)}
</div>
);
}
}
I have three components:
Weather
InputText
WeatherData
Now the InputText Component is rendered when the main Weather component is rendered, the InputText component contains a textfield and a button.
So now when i click the button need to call an openweathermap api and then display the result in WeatherData Component.
The WeatherData component must be rendered only after the button click.
How can i achieve this??
add some state to the Weather component, call it showWeatherData for example, set it to null in the beginning. Give it a value after you receive back the data from your api.
in your JSX inside Weather component, use the && to short circuit the WeatherData component (just a short way instead of using an if or a tertiary operator)
render(){
<InputText />
{ ShowWeatherData && <WeatherData /> }
}

DOM event not working with server side rendering in React js and node js application

I am developing a application which using React js and node js as backend.
Here is my code :
I am using above code, any events like onclick and form submit is not working. Please let me know any reference or help to run my application.
Class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: 'Initial data...'
}
this.updateState = this.updateState.bind(this);
}
updateState() {
console.log('event is working');
}
render() {
return (
<div>
<button onClick={this.updateState}>CLICK</button>
</div>
);
}
}
export default App;

Resources