Layer over complete page not displaying correctly - css

I have an issue in my react application. I'm using styled-components for using styling (CSS-in-JS).
The issue:
When the user performs a specific action, a layer over the complete page should be displayed. I've created for this an seperate component. But the layer is not working as expected (see the image). Layer 1 should cover the complete page. Layer 2 should be in the middle of the page.
See my code of the component:
import React, { Component, Fragment } from 'react';
import styled from 'styled-components';
import axios from 'axios';
const uuidv4 = require('uuid/v4');
const RefreshLink = styled.a`
text-decoration: underline;
cursor: pointer;
color: #155724;
&:hover {
color: #155724;
}
`
const Background = styled.div`
position:fixed;
width:100%;
height:100%;
background-color:#aeaeae;
opacity:0.5;
z-index:10000;
`
const PopUp = styled.div`
position:fixed;
z-index:10001;
left:50%;
margin-left:-25%;
width:450px;
top:50%;
margin-top:-25%;
`
class UpdatingFreightsInfo extends Component {
_isMounted = false;
signal = axios.CancelToken.source();
constructor(props) {
super(props);
this.state = {
freightsInUpdateProcess: false,
hasFreightsBeenInUpdateStatusSincePageLoad: false,
intervalId: -1,
freightsUpdating: [],
};
this.checkForUpdatingFreights = this.checkForUpdatingFreights.bind(this);
}
componentDidMount() {
this._isMounted = true;
this.getUpdatingFreightsInfo();
}
componentWillUnmount() {
this.signal.cancel();
clearInterval(this.state.intervalId);
this._isMounted = false;
}
componentDidUpdate(prevProps) {
if (this.props.updateTrigger !== prevProps.updateTrigger) {
this.checkForUpdatingFreights();
}
}
getUpdatingFreightsInfo() {
this.checkForUpdatingFreights();
let intervalId = setInterval(() => {
this.checkForUpdatingFreights();
},30000);
this.setState({
intervalId: intervalId
});
}
checkForUpdatingFreights = async () => {
try {
const response = await axios.get('../data/get/json/freightsCurrentlyUpdating', {
cancelToken: this.signal.token,
})
.then((response) => {
console.log(response);
if(response != undefined && response != null) {
if (this._isMounted) {
if(response.data.length > 0) {
this.setState({
freightsUpdating: response.data,
freightsInUpdateProcess: true,
hasFreightsBeenInUpdateStatusSincePageLoad: true,
});
}
else {
this.setState({
freightsUpdating: [],
freightsInUpdateProcess: false,
});
}
}
}
})
.catch(function (error) {
console.log(error);
});
}
catch(err) {
if (axios.isCancel(err)) {
console.log('Error: ', err.message); // => prints: Api is being canceled
} else {
}
}
}
render() {
return (
(this.state.freightsInUpdateProcess || (this.state.hasFreightsBeenInUpdateStatusSincePageLoad && !this.state.freightsInUpdateProcess )) &&
<Fragment>
<Background key={uuidv4()}></Background>
<PopUp key={uuidv4()}>
<div className="container-fluid">
<div className="row">
<div className="col-12 col-sm-12 col-md-12 col-lg-12">
{
this.state.freightsInUpdateProcess &&
<div className="alert alert-warning text-center" role="alert">
<h4 className="alert-heading">Updating freights in process</h4>
<p className="mb-0">{ this.state.freightsUpdating.length } freight entries are currently being updated.</p>
</div>
}
{
this.state.hasFreightsBeenInUpdateStatusSincePageLoad && !this.state.freightsInUpdateProcess &&
<div className="alert alert-success text-center" role="alert">
<h4 className="alert-heading">Updating freights finished</h4>
<p className="mb-0">
The update process has been finished.
<br />
<span className="fa fa-refresh"></span> <RefreshLink href="/" target="_self">Please refresh the page</RefreshLink>
</p>
</div>
}
</div>
</div>
</div>
</PopUp>
</Fragment>
);
}
}
export default UpdatingFreightsInfo;
Is it because the component is being nested in other components? It seems like that, but I thought, when using CSS
position: fixed with combination of left and top
that this code is independent from the components. And also strange that in PopUp it seems to work (almost) correctly.

Related

React CSS: trying to give Color to class for a few seconds when there is a change on state vs prevState

Goal: I want to compare prevState with actualState to display a different class on a <div> depending on the comparision.
Problem: When the iteration results in no switch of class,i cant see the difference since the className doesnt trigger the keyframe event.
JSX:
import React, { useEffect, useState, useRef } from "react";
import styles from "./CoinContainer.module.css";
function usePrevious(data) {
const ref = useRef();
useEffect(() => {
ref.current = data;
}, [data]);
return ref.current;
}
export default function CoinContainer({ coin, price }) {
const [priceUpdated, setPrice] = useState("");
const prevPrice = usePrevious(priceUpdated);
useEffect(() => {
setInterval(priceUpdate, 20000);
});
const toggleClassName = () => {
return prevPrice > priceUpdated ? styles.redPrice : styles.greenPrice;
};
function priceUpdate() {
return fetch(
`https://api.coingecko.com/api/v3/simple/price?ids=${coin}&vs_currencies=usd`
)
.then((data) => data.json())
.then((result) => {
let key = Object.keys(result);
setPrice(result[key].usd);
});
}
return (
<div className={styles.padding}>
<h2>{coin}</h2>
<h3 className={toggleClassName()}>
{priceUpdated ? priceUpdated : price}$
</h3>
</div>
);
}
CSS:
#keyframes upFadeBetween {
from {
color: green;
}
to {
color: white;
}
}
#keyframes downFadeBetween {
from {
color: red;
}
to {
color: white;
}
}
.redPrice {
color: white;
animation: downFadeBetween 5s;
}
.greenPrice {
color: white;
animation: upFadeBetween 5s;
}
Thanks so much for any feedback/help!

how to reload page after handle state?

My sidebar in the responsive mode not working correctly, i'm use #media for controller width of page, when is responsive i use position:absolute for sidebar button stay in up of content, i created a state for onclick is active change this position:relative but is not working, help please. The page in the mode normal funciton correctly, and mode responsive (Ctrl + shift + I) too but i click in the button the problemn happens.
Sidebar.js
export default class Menu extends Component {
constructor(props) {
super(props);
this.state = {
classStyle: "sidebar"
};
}
// handleSidebar(value) {
// this.setState = ({ classStyle : value });
// }
handleSidebar = (value) => {
this.setState = ({ classStyle: value });
}
render() {
return (
<div className={this.state.classStyle}>
<Navbar bg="light" variant="light" sticky="top" expand="lg">
<Navbar.Toggle aria-controls="navbarSupportedContent" onClick={() => handleSidebar("sidebarR")} />
<Navbar.Collapse id="navbarSupportedContent">
Index.css
#media (max-width: 600px)
{
.sidebar
{
position: absolute;
}
.sidebarR
{
position: relative;
}
}
Please try this one, it is working
Replace this function in your component
handleSidebar = () => {
console.log("clicked");
this.setState({ classStyle: "sidebarR" });
}
If you want toggle class then use below function,
handleSidebar = () => {
console.log("clicked");
const classStyle = this.state.classStyle == "sidebar" ? "sidebarR" : "sidebar";
this.setState({ classStyle: classStyle });
}
Running Component without Navbar Component,
import React,{Component} from 'react';
import './Menu.css';
export default class Menu extends Component {
state = {
classStyle: "sidebar"
};
handleSidebar = () => {
console.log("clicked");
this.setState({ classStyle: "sidebarR" });
}
render() {
return (
<div className={this.state.classStyle}>
<p onClick={() => this.handleSidebar()} >Menu</p>
</div>
)
}
}
When you call handleSidebar on onClick, you need to use this
Navbar.Toggle aria-controls="navbarSupportedContent" onClick={() => this.handleSidebar("sidebarR")} />

TypeError: results.map is not a function Function.renderemployeeTable

I was trying to display api data using reactJs Application. i used the following code but i keep getting the following error
TypeError: results.map is not a function
Function.renderemployeeTable
export class FetchData extends Component {
static displayName = FetchData.name;
constructor(props) {
super(props);
this.state = { results: [] };
}
componentDidMount() {
fetch('urll', {
method: 'GET',
headers: {
'api-key': 'api-key'
}
})
.then(results => results.json())
.then(data => this.setState({ results: data }));
}
static renderemployeeTable(results) {
return (
<div class="container-fluid" class="row" fluid={true}>
{
results.map(results =>
<div class="col-sm-3" key={results.Employee_Number}>
<div class="card our-team" >
<div class="card-body">
<p class="card-text">{results.first_name}</p>
<p class="card-text">{results.last_name}</p>
</div>
</div>
Detail
</div>
)
}
</div>
);
}
render() {
let contents = this.state.loading
? <p><em>Loading...</em></p>
: FetchData.renderemployeeTable(this.state.results);
return (
<div>
<h1 id="tabelLabel" >-</h1>
{contents}
</div>
);
}
async populateemployeeData() {
const response = await fetch('table');
const data = await response.json();
this.setState({ results: data, loading: false });
}
}
but i get this error message
TypeError: results.map is not a function
Function.renderemployeeTable
This is the output of console.log(results).
"data": {
"Table": [
{
"id": 14258,
"first_name": "yibgeta",
"last_name": "solans",...
}]}],
Now it will work------
constructor(props) {
super(props);
this.state = { results: [] };
}
componentDidMount() {
fetch('http://web.api.services/api/v2/tultula/employees/all', {
method: 'GET',
headers: {
'api-key': '7cefc4163dula77bf0f41ba741c'
}
})
.then(results => results.json())
.then(data => this.setState({ results: data }));
}
render() {
if(this.state.result != null && this.state.result!= undefined){
return (
<div class="container-fluid" class="row" fluid={true}>
{
this.state.results.map(results =>
<div class="col-sm-3" key={results.Employee_Number}>
<div class="card our-team" >
<div class="card-body">
<p class="card-text">{results.first_name}</p>
<p class="card-text">{results.last_name}</p>
</div>
</div>
Detail
</div>
)
}
</div>
);}
let contents = this.state.loading
? <p><em>Loading...</em></p>
: FetchData.renderemployeeTable(this.state.results);
return (
<div>
<h1 id="tabelLabel" >-</h1>
{contents}
</div>
);
}
async populateemployeeData() {
const response = await fetch('table');
const data = await response.json();
this.setState({ results: data, loading: false });
}
}
Did you have ever try to write down like this?
data => this.setState({
results: data.Table
})
Or
results.Table.map(result => ...)
Try
{
results.Table && results.Table.map( result =>...)
}
This will ensure that the array exists and then you can use map function on it.
Try in this way:-
import React, { Component } from "react";
class Example extends Component {
constructor(props) {
super(props);
this.state = { results: [] };
}
componentDidMount() {
fetch("url", {
method: "GET",
headers: {
"api-key": "api-key"
}
})
.then(results => results.json())
.then(data => this.setState({ results: data }));
}
renderemployeeTable(results) {
return (
<div className="container-fluid" className="row" fluid={true}>
{results.map(results => (
<div className="col-sm-3" key={results.Employee_Number}>
<div className="card our-team">
<div className="card-body">
<p className="card-text">{results.first_name}</p>
<p className="card-text">{results.last_name}</p>
</div>
</div>
<a href="#" className="btn btn-primary">
Detail
</a>
</div>
))}
</div>
);
}
render() {
let contents = this.state.loading ? (
<p>
<em>Loading...</em>
</p>
) : (
this.renderemployeeTable(this.state.results)
);
return (
<div>
<h1 id="tabelLabel">-</h1>
{contents}
</div>
);
}
async populateemployeeData() {
const response = await fetch("table");
const data = await response.json();
this.setState({ results: data, loading: false });
}
}
export default Example;

How to upload file with redux-form?

I can't get correct value into the store when trying to upload a file. Instead of file content, I get something like { 0: {} }.
Here's the code:
const renderInput = field => (
<div>
<input {...field.input} type={field.type}/>
{
field.meta.touched &&
field.meta.error &&
<span className={styles.error}>{field.meta.error}</span>
}
</div>
);
render() {
...
<form className={styles.form} onSubmit={handleSubmit(submit)}>
<div className={styles.interface}>
<label>userpic</label>
<Field
name="userpic"
component={renderInput}
type="file"
/>
</div>
<div>
<button type="submit" disabled={submitting}>Submit</button>
<div>
</form>
...
}
All the examples on the web that I found were made using v5 of redux-form.
How do I do file input in redux-form v6?
Create a Field Component like:
import React, {Component} from 'react'
export default class FieldFileInput extends Component{
constructor(props) {
super(props)
this.onChange = this.onChange.bind(this)
}
onChange(e) {
const { input: { onChange } } = this.props
onChange(e.target.files[0])
}
render(){
const { input: { value } } = this.props
const {input,label, required, meta, } = this.props //whatever props you send to the component from redux-form Field
return(
<div><label>{label}</label>
<div>
<input
type='file'
accept='.jpg, .png, .jpeg'
onChange={this.onChange}
/>
</div>
</div>
)
}
}
Pass this component to the Field component where you needed. No need of additional Dropzone or other libraries if you are after a simple file upload functionality.
My example of redux form input wrapper with Dropzone
import React, {Component, PropTypes} from 'react';
import Dropzone from 'react-dropzone';
import { Form } from 'elements';
import { Field } from 'redux-form';
class FileInput extends Component {
static propTypes = {
dropzone_options: PropTypes.object,
meta: PropTypes.object,
label: PropTypes.string,
classNameLabel: PropTypes.string,
input: PropTypes.object,
className: PropTypes.string,
children: PropTypes.node,
cbFunction: PropTypes.func,
};
static defaultProps = {
className: '',
cbFunction: () => {},
};
render() {
const { className, input: { onChange }, dropzone_options, meta: { error, touched }, label, classNameLabel, children, name, cbFunction } = this.props;
return (
<div className={`${className}` + (error && touched ? ' has-error ' : '')}>
{label && <p className={classNameLabel || ''}>{label}</p>}
<Dropzone
{...dropzone_options}
onDrop={(f) => {
cbFunction(f);
return onChange(f);
}}
className="dropzone-input"
name={name}
>
{children}
</Dropzone>
{error && touched ? error : ''}
</div>
);
}
}
export default props => <Field {...props} component={FileInput} />;
Hot to use it:
<FileInput
name="add_photo"
label="Others:"
classNameLabel="file-input-label"
className="file-input"
dropzone_options={{
multiple: false,
accept: 'image/*'
}}
>
<span>Add more</span>
</FileInput>
Another way to do it that will render a preview image (the below example uses React 16+ syntax and only accepts a single image file to send to an API; however, with some minor tweaks, it can also scale to multiple images and other fields inputs):
Working example: https://codesandbox.io/s/m58q8l054x
Working example (outdated): https://codesandbox.io/s/8kywn8q9xl
Before:
After:
containers/UploadForm.js
import React, { Component } from "react";
import { Form, Field, reduxForm } from "redux-form";
import DropZoneField from "../components/dropzoneField";
const imageIsRequired = value => (!value ? "Required" : undefined);
class UploadImageForm extends Component {
state = { imageFile: [] };
handleFormSubmit = formProps => {
const fd = new FormData();
fd.append("imageFile", formProps.imageToUpload.file);
// append any additional Redux form fields
// create an AJAX request here with the created formData
alert(JSON.stringify(formProps, null, 4));
};
handleOnDrop = (newImageFile, onChange) => {
const imageFile = {
file: newImageFile[0],
name: newImageFile[0].name,
preview: URL.createObjectURL(newImageFile[0]),
size: newImageFile[0].size
};
this.setState({ imageFile: [imageFile] }, () => onChange(imageFile));
};
resetForm = () => this.setState({ imageFile: [] }, () => this.props.reset());
render = () => (
<div className="app-container">
<h1 className="title">Upload An Image</h1>
<hr />
<Form onSubmit={this.props.handleSubmit(this.handleFormSubmit)}>
<Field
name="imageToUpload"
component={DropZoneField}
type="file"
imagefile={this.state.imageFile}
handleOnDrop={this.handleOnDrop}
validate={[imageIsRequired]}
/>
<button
type="submit"
className="uk-button uk-button-primary uk-button-large"
disabled={this.props.submitting}
>
Submit
</button>
<button
type="button"
className="uk-button uk-button-default uk-button-large"
disabled={this.props.pristine || this.props.submitting}
onClick={this.resetForm}
style={{ float: "right" }}
>
Clear
</button>
</Form>
<div className="clear" />
</div>
);
}
export default reduxForm({ form: "UploadImageForm" })(UploadImageForm);
components/dropzoneField.js
import React from "react";
import PropTypes from "prop-types";
import DropZone from "react-dropzone";
import ImagePreview from "./imagePreview";
import Placeholder from "./placeholder";
import ShowError from "./showError";
const DropZoneField = ({
handleOnDrop,
input: { onChange },
imagefile,
meta: { error, touched }
}) => (
<div className="preview-container">
<DropZone
accept="image/jpeg, image/png, image/gif, image/bmp"
className="upload-container"
onDrop={file => handleOnDrop(file, onChange)}
>
{({ getRootProps, getInputProps }) =>
imagefile && imagefile.length > 0 ? (
<ImagePreview imagefile={imagefile} />
) : (
<Placeholder
error={error}
touched={touched}
getInputProps={getInputProps}
getRootProps={getRootProps}
/>
)
}
</DropZone>
<ShowError error={error} touched={touched} />
</div>
);
DropZoneField.propTypes = {
error: PropTypes.string,
handleOnDrop: PropTypes.func.isRequired,
imagefile: PropTypes.arrayOf(
PropTypes.shape({
file: PropTypes.file,
name: PropTypes.string,
preview: PropTypes.string,
size: PropTypes.number
})
),
label: PropTypes.string,
onChange: PropTypes.func,
touched: PropTypes.bool
};
export default DropZoneField;
components/imagePreview.js
import React from "react";
import PropTypes from "prop-types";
const ImagePreview = ({ imagefile }) =>
imagefile.map(({ name, preview, size }) => (
<div key={name} className="render-preview">
<div className="image-container">
<img src={preview} alt={name} />
</div>
<div className="details">
{name} - {(size / 1024000).toFixed(2)}MB
</div>
</div>
));
ImagePreview.propTypes = {
imagefile: PropTypes.arrayOf(
PropTypes.shape({
file: PropTypes.file,
name: PropTypes.string,
preview: PropTypes.string,
size: PropTypes.number
})
)
};
export default ImagePreview;
components/placeholder.js
import React from "react";
import PropTypes from "prop-types";
import { MdCloudUpload } from "react-icons/md";
const Placeholder = ({ getInputProps, getRootProps, error, touched }) => (
<div
{...getRootProps()}
className={`placeholder-preview ${error && touched ? "has-error" : ""}`}
>
<input {...getInputProps()} />
<MdCloudUpload style={{ fontSize: 100, paddingTop: 85 }} />
<p>Click or drag image file to this area to upload.</p>
</div>
);
Placeholder.propTypes = {
error: PropTypes.string,
getInputProps: PropTypes.func.isRequired,
getRootProps: PropTypes.func.isRequired,
touched: PropTypes.bool
};
export default Placeholder;
components/showError.js
import React from "react";
import PropTypes from "prop-types";
import { MdInfoOutline } from "react-icons/md";
const ShowError = ({ error, touched }) =>
touched && error ? (
<div className="error">
<MdInfoOutline
style={{ position: "relative", top: -2, marginRight: 2 }}
/>
{error}
</div>
) : null;
ShowError.propTypes = {
error: PropTypes.string,
touched: PropTypes.bool
};
export default ShowError;
styles.css
img {
max-height: 240px;
margin: 0 auto;
}
.app-container {
width: 500px;
margin: 30px auto;
}
.clear {
clear: both;
}
.details,
.title {
text-align: center;
}
.error {
margin-top: 4px;
color: red;
}
.has-error {
border: 1px dotted red;
}
.image-container {
align-items: center;
display: flex;
width: 85%;
height: 80%;
float: left;
margin: 15px 10px 10px 37px;
text-align: center;
}
.preview-container {
height: 335px;
width: 100%;
margin-bottom: 40px;
}
.placeholder-preview,
.render-preview {
text-align: center;
background-color: #efebeb;
height: 100%;
width: 100%;
border-radius: 5px;
}
.upload-container {
cursor: pointer;
height: 300px;
}
I managed to do it with redux-form on material-ui wrapping TextField like this:
B4 edit:
After edit:
<Field name="image" component={FileTextField} floatingLabelText={messages.chooseImage} fullWidth={true} />
with component defined as:
const styles = {
button: {
margin: 12
},
exampleImageInput: {
cursor: 'pointer',
position: 'absolute',
top: 0,
bottom: 0,
right: 0,
left: 0,
width: '100%',
opacity: 0
},
FFS:{
position: 'absolute',
lineHeight: '1.5',
top: '38',
transition: 'none',
zIndex: '1',
transform: 'none',
transformOrigin: 'none',
pointerEvents: 'none',
userSelect: 'none',
fontSize: '16',
color: 'rgba(0, 0, 0, 0.8)',
}
};
export const FileTextField = ({
floatingLabelText,
fullWidth,
input,
label,
meta: { touched, error },
...custom })=>{
if (input.value && input.value[0] && input.value[0].name) {
floatingLabelText = input.value[0].name;
}
delete input.value;
return (
<TextField
hintText={label}
fullWidth={fullWidth}
floatingLabelShrinkStyle={styles.FFS}
floatingLabelText={floatingLabelText}
inputStyle={styles.exampleImageInput}
type="file"
errorText={error}
{...input}
{...custom}
/>
)
}
If you need base64 encoding to send it to your backend, here is a modified version that worked for me:
export class FileInput extends React.Component {
getBase64 = (file) => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
}
onFileChange = async (e) => {
const { input } = this.props
const targetFile = e.target.files[0]
if (targetFile) {
const val = await this.getBase64(targetFile)
input.onChange(val)
} else {
input.onChange(null)
}
}
render() {
return (
<input
type="file"
onChange={this.onFileChange}
/>
)
}
}
Then your field component would look like:
<Field component={FileInput} name="primary_image" type="file" />
For React >= 16 and ReduxForm >= 8 (tested version are 16.8.6 for React and 8.2.5)
works following component.
(Solution posted in related GitHub issue by DarkBitz)
const adaptFileEventToValue = delegate => e => delegate(e.target.files[0]);
const FileInput = ({
input: { value: omitValue, onChange, onBlur, ...inputProps },
meta: omitMeta,
...props
}) => {
return (
<input
onChange={adaptFileEventToValue(onChange)}
onBlur={adaptFileEventToValue(onBlur)}
type="file"
{...props.input}
{...props}
/>
);
};
export const FileUpload = (props) => {
const { handleSubmit } = props;
const onFormSubmit = (data) => {
console.log(data);
}
return (
<form onSubmit={handleSubmit(onFormSubmit)}>
<div>
<label>Attachment</label>
<Field name="attachment" component={FileInput} type="file"/>
</div>
<button type="submit">Submit</button>
</form>
)
}
With Redux Form
const { handleSubmit } = props;
//make a const file to hold the file prop.
const file = useRef();
// create a function to replace the redux-form input-file value to custom value.
const fileUpload = () => {
// jsx to take file input
// on change store the files /file[0] to file variable
return (
<div className='file-upload'>
<input
type='file'
id='file-input'
accept='.png'
onChange={(ev) => {
file.current = ev.target.files;
}}
required
/>
</div>
);
};
//catch the redux-form values!
//loop through the files and add into formdata
//form data takes key and value
//enter the key name as multer-config fieldname
//then add remaining data into the formdata
//make a request and send data.
const onSubmitFormValues = (formValues) => {
const data = new FormData();
for (let i = 0; i < file.current.length; i++) {
data.append("categoryImage", file.current[i]);
}
data.append("categoryName", formValues.categoryName);
Axios.post("http://localhost:8080/api/v1/dev/addNewCategory", data)
.then((response) => console.log(response))
.catch((err) => console.log(err));
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
You can also use react-dropzone for this purpose. The below code worked fine for me
filecomponent.js
import React from 'react'
import { useDropzone } from 'react-dropzone'
function MyDropzone(props) {
const onDrop = (filesToUpload) => {
return props.input.onChange(filesToUpload[0]);
}
const onChange = (filesToUpload) => {
return props.input.onChange(filesToUpload[0]);
}
const { getRootProps, getInputProps } = useDropzone({ onDrop });
return (
<div {...getRootProps()}>
<input {...getInputProps()} onChange={e => onChange(e.target.files)} />
<p> Drop or select yout file</p>
</div>
)
}
export default MyDropzone;
In form use this
<Field
name="myfile"
component={renderFile}
/>

Reactjs - render child asynchronous

I am showing loading gif, until canvas is fully rendered, i make then callback to set visible of loading gif to off. But all time during rendering, gif rotating is stopped and other parts of page doesn't react too. So is there any way ho to render any component asynchronous to prevent influencing with other parts of page?
class GraphPage extends React.Component {
constructor(props) {
super(props);
this.state = {
loaded: false,
print: null,
loading: true
}
}
componentDidMount(){
this.setReady();
}
render(){
const graphList = graphStore.getGraphValue();
var {data} = this.props;
return(
<div>
<div className="inputs">
<Inputs modal={false} unit='%' list={graphList.rotation} descTitle={data.graph.machine}/>
<Inputs modal={false} unit='mm' list={graphList.machine} descTitle={data.graph.rotation}/>
</div>
<div className="graph">
{this.state.loading? <img src={loadingIcon}/> : false}
{this.state.print? <Print readyToRender={this.update.bind(this)}/> : false}
</div>
</div>
)
}
update(){
this.setState({
loading: false
})
}
setReady(){
setTimeout(function() {
this.setState({print: new Print()})
}.bind(this), 1000);
}
}
I would put the rotating gif in the renderer of Print.
class Print extends React.Component {
constructor(props) {
super(props);
this.state = {
renderFinished: true
}
this.calculate().then(function() {
/* Canvas done => display it! */
this.setState({ renderFinished: true })
}.bind(this))
calculate() {
var result = new Promise();
// Something asyncronous, just an example
setTimeout(function(){
while(doCalc) {
if(calcIsDone) {
// Ready for render
result.resolve(theResult);
}
}
}.bind(this), 0);
return result;
}
render() {
return {
renderFinished ?
<div>
{ /* Here goes the rendered canvas output */ }
</div>
:
<img src={loadingIcon}/>
}
};
}
And then GraphPage looks like this
class GraphPage extends React.Component {
constructor(props) {
super(props);
}
render(){
// It look like graphStore is globally available so Print also can access it directly
const graphList = graphStore.getGraphValue();
var {data} = this.props;
return(
<div>
<div className="inputs">
<Inputs modal={false} unit='%' list={graphList.rotation} descTitle={data.graph.machine}/>
<Inputs modal={false} unit='mm' list={graphList.machine} descTitle={data.graph.rotation}/>
</div>
<div className="graph">
{ /* Maybe graphStore should be given here as a prop? */ }
<Print/>
</div>
</div>
)
}
}

Resources