Skip to content

Instantly share code, notes, and snippets.

@marvinpinto
Last active October 10, 2017 18:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marvinpinto/731a0d5ac87a9cc923f7779d2bc50bc2 to your computer and use it in GitHub Desktop.
Save marvinpinto/731a0d5ac87a9cc923f7779d2bc50bc2 to your computer and use it in GitHub Desktop.
Demo for Displaying a loading message while initializing a React component
html,
body {
display: flex;
min-height: 100vh;
min-width: 100vw;
background: white;
}
#container {
display: flex;
flex: 1 1 auto;
justify-content: center;
align-items: center;
}
.loading-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.spinner {
width: 40px;
height: 40px;
position: relative;
}
.double-bounce1,
.double-bounce2 {
width: 100%;
height: 100%;
border-radius: 50%;
background-color: #333;
opacity: 0.6;
position: absolute;
top: 0;
left: 0;
-webkit-animation: sk-bounce 2s infinite ease-in-out;
animation: sk-bounce 2s infinite ease-in-out;
}
.double-bounce2 {
-webkit-animation-delay: -1s;
animation-delay: -1s;
}
@-webkit-keyframes sk-bounce {
0%,
100% {
-webkit-transform: scale(0);
}
50% {
-webkit-transform: scale(1);
}
}
@keyframes sk-bounce {
0%,
100% {
transform: scale(0);
-webkit-transform: scale(0);
}
50% {
transform: scale(1);
-webkit-transform: scale(1);
}
}
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/3.7.2/redux.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/5.0.6/react-redux.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux-thunk/2.2.0/redux-thunk.js"></script>
<div id="container"></div>
const { Provider, connect } = ReactRedux;
const { createStore, applyMiddleware } = Redux;
const thunk = ReduxThunk.default;
const sleep = time => {
return new Promise(resolve => setTimeout(resolve, time));
};
//============
// Reducer
//============
const defaultState = {
isRefreshingSettings: false,
isRetrievingToken: false,
appToken: null
};
const reducer = (state = defaultState, action) => {
switch (action.type) {
case "MAKE_REFRESH_SETTINGS_REQUEST":
return {
...state,
isRefreshingSettings: true
};
case "RECEIVE_REFRESH_SETTINGS_RESULT":
return {
...state,
isRefreshingSettings: false
};
case "MAKE_RETRIEVE_TOKEN_REQUEST":
return {
...state,
isRetrievingToken: true
};
case "RECEIVE_RETRIEVE_TOKEN_RESULT":
return {
...state,
isRetrievingToken: false,
appToken: action.result
};
default:
return state;
}
};
//============
// Actions
//============
const initiateRefreshSettingsRequest = () => {
return dispatch =>
Promise.resolve().then(() => {
dispatch({ type: "MAKE_REFRESH_SETTINGS_REQUEST" });
return Promise.resolve()
.then(() => {
return sleep(600);
})
.then(() => {
dispatch({ type: "RECEIVE_REFRESH_SETTINGS_RESULT" });
})
.catch(error => {
dispatch({ type: "RECEIVE_REFRESH_SETTINGS_RESULT" });
throw error;
});
});
};
const initiateRetrieveTokenRequest = () => {
return dispatch =>
Promise.resolve().then(() => {
dispatch({ type: "MAKE_RETRIEVE_TOKEN_REQUEST" });
return Promise.resolve()
.then(() => {
return sleep(600);
})
.then(() => {
dispatch({
type: "RECEIVE_RETRIEVE_TOKEN_RESULT",
result: "SECRETTOKEN"
});
return "SECRETTOKEN";
})
.catch(error => {
dispatch({
type: "RECEIVE_RETRIEVE_TOKEN_RESULT",
result: null
});
throw error;
});
});
};
//============
// Application
//============
class SampleApplication extends React.Component {
constructor(props) {
super(props);
this.state = {
initializationComplete: false
};
}
componentDidMount() {
const { dispatch } = this.props;
Promise.resolve()
.then(() => {
return dispatch(initiateRetrieveTokenRequest());
})
.then(token => {
// ... do something here that pegs the main thread for a noticable
// amount of time - like perhaps validating the token
return sleep(100).then(() => {
return token;
});
})
.then(token => {
// ... now use the token to make the settings retrieval request
return dispatch(initiateRefreshSettingsRequest(token));
})
.then(result => {
this.setState({ initializationComplete: true });
console.log("Initialization complete");
return sleep(3000);
});
}
render() {
const { appToken } = this.props.globalState;
const { initializationComplete } = this.state;
if (!initializationComplete) {
return (
<div className="loading-container">
<span>
<strong>Please Wait</strong>
</span>
<div className="spinner">
<div className="double-bounce1" />
<div className="double-bounce2" />
</div>
</div>
);
}
return (
<span>
Your token is: <strong>{appToken}</strong>
</span>
);
}
}
const mapStateToProps = state => {
return {
globalState: state
};
};
const store = createStore(reducer, applyMiddleware(thunk));
const Container = connect(mapStateToProps)(SampleApplication);
ReactDOM.render(
<Provider store={store}>
<Container />
</Provider>,
document.getElementById("container")
);
name: Demo for Displaying a loading message while initializing a React component
description: See https://disjoint.ca/til/2017/10/09/displaying-a-loading-message-while-initializing-a-react-component for details.
authors:
- Marvin Pinto
normalize_css: no
wrap: b
panel_js: 3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment