How to send file from react-dropzone to other api - javascript

I need to send a file from react-dropzone to a variable in a .js file. I wrote this code for dropzone:
const baseStyle = {
flex: 1,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
padding: '20px',
borderWidth: 2,
borderRadius: 2,
borderColor: '#eeeeee',
borderStyle: 'dashed',
backgroundColor: '#fafafa',
color: '#bdbdbd',
outline: 'none',
transition: 'border .24s ease-in-out'
};
const activeStyle = {
borderColor: '#2196f3'
};
const acceptStyle = {
borderColor: '#00e676'
};
const rejectStyle = {
borderColor: '#ff1744'
};
const maxSize = 5000000 // bytes
const acceptedFileTypes = '.csv, text/csv, application/csv, text/x-csv, application/x-csv, text/comma-separated-values, text/x-comma-separated-values'
const TFApartCsvInput = (props) => {
const [files, setFiles] = useState([]);
const {
getRootProps,
getInputProps,
isDragActive,
isDragAccept,
isDragReject,
acceptedFiles,
} = useDropzone({
accept: acceptedFileTypes,
multiple: false,
minSize: 0,
maxSize: maxSize,
onDrop: (acceptedFiles, rejectedFiles) => {
console.log('Accepted files:', acceptedFiles);
console.log('Rejected files:', rejectedFiles);
},
onDropAccepted: props.onCSVUpload,
onDropRejected: props.CSVTooBig
});
const style = useMemo(() => ({
...baseStyle,
...(isDragActive ? activeStyle : {}),
...(isDragAccept ? acceptStyle : {}),
...(isDragReject ? rejectStyle : {})
}), [
isDragActive,
isDragReject,
isDragAccept
]);
//ACCEPTED
const acceptedFileItems = acceptedFiles.map(file => (
<li key={file.path}>
{file.path}
</li>
));
// RETURN
return (
<div className="container">
<div {...getRootProps({style})}>
<input {...getInputProps()} />
<p>Drag 'n' drop some files here, or click to select files</p>
<aside>
<h4>Drag 'n' drop here .CSV files</h4>
<ul>{acceptedFileItems}</ul>
</aside>
</div>
</div>
);
}
export default TFApartCsvInput;
and i have my import.js file which have a variable like this one:
let app_stream = fs.createReadStream("app.csv");
let csvData_app = [];
let csvData = [];
//other code
I wanna insert the file that the user drop in dropzone inside my app_stream variable of import.js. I can see from console that file is taken but I can't undestand how to manage it. Sorry if it sounds stupid, this is my first react project.

Your import.js will need to export a class or function, which will need to be imported from your Dropzoned component:
import.js
export default function (filename) {
// `fs` is a NodeJS library not suited for browsers. Are you sure?
let app_stream = fs.createReadStream(filename);
let csvData_app = [];
let csvData = [];
//other code
}
dropzoned.jsx
import Importer from './import.js'
// ...
onDropAccepted: (...args) => {
Importer(args); // I don't know what `args` contains
props.onCSVUpload(...args);
},
// ...

Related

Prime React Chart Axios data does not load

I try to load data in a graph using a rest api, but it doesn't load for some reason,
can you help me
this is the data that the api brings
{
"avg_soc_fleet": 74.85
}
here is the code
const Rem = () => {
const [avgSoc, SetAvgSoc] = useState({});
useEffect(() => {
axios.get('http://127.0.0.1:8000/other/avgsoc_fleet').then(response => {
SetAvgSoc(response.data);
})
}, []);
const [avgChart] = useState({
labels: ['Soc', 'Pressure', 'Isolation', 'BattVolt24'],
datasets: [
{
data: [Object.values(avgSoc)],
fill: false,
borderColor: '#4bc0c0',
tension: .4
},
]
});
const options = {
legend: {
display: true,
}
};
return (
<div className="grid">
<div className="col-8">
<div className="card">
<Chart type="line" data={avgChart} options={options} />
</div>
</div>
</div>
);
};
export default Rem;
render chart
I hope I can load the data from the api in the graph in react
You need to update the avgChart after getting the response from axios. In that case avgSoc seems unnecessary, try the following:
const Rem = () => {
const [avgChart, setAvgChart] = useState();
useEffect(() => {
axios.get('http://127.0.0.1:8000/other/avgsoc_fleet').then(response => {
const chartOptions={
labels: ['Soc', 'Pressure', 'Isolation', 'BattVolt24'],
datasets: [
{
data: [Object.values(response.data)],
fill: false,
borderColor: '#4bc0c0',
tension: .4
},
]
}
setAvgChart(chartOptions);
})
}, []);
const options = {
legend: {
display: true,
}
};
return (
<div className="grid">
<div className="col-8">
<div className="card">
<Chart type="line" data={avgChart} options={options} />
</div>
</div>
</div>
);
};
export default Rem;
OBS: This is an example of how to proceed, not necessarily the only possible implementation.
Once you get the data, you need to update the avgChart again. use a setState method
const [avgChart, setAvgChart] = useState({
add new useEffect
useEffect(() => {
if(avgSoc.length){
setAvgChart({
...avgChart,
datasets: {
...avgChart.datasets
data: [Object.values(avgSoc)],
}
})
}
}, [avgSoc]);

socket.io-client emmitting event multiple times in react native

I am new to using socket.io with react native.I am able to connect the socket.io instance with my node.js backend but the socket.io client is emmitting events multiple times.The app has grown quite complex so,I am also trying to explain what I did.
Main.js (User is redirected here from App.js)
I am using a library called react-native-tab-view and I used useContext to pass the socket instance.I have checked that the hook is working properly.
export const SocketObj = createContext()
const Main = ({ route }) => {
let [socket, setSocket] = useState(undefined)
const routesLength = useNavigationState(state => state.routes.length);
const connect = async () => {
if (routesLength == 1) {
setSocket(io("http://192.168.43.115:8000", {
transports: ['websocket'],
query: {
token: await AsyncStorage.getItem("token")
}
}))
} else {
const { socketInstanse } = route.params
setSocket(socketInstanse)
}
}
connect()
const layout = useWindowDimensions();
const [index, setIndex] = useState(0);
const [routes] = useState([
{ key: 'first', title: 'CHAT' },
{ key: 'second', title: 'PEOPLE' },
]);
const renderScene = SceneMap({
first: SplashScreen,
second: PeopleScreen,
});
return (
<SocketObj.Provider value={socket} >
<TabView
navigationState={{ index, routes }}
renderScene={renderScene}
onIndexChange={(number) => {
setIndex(number)
}}
initialLayout={{ width: layout.width }}
/>
</SocketObj.Provider>
);
}
export default Main;
PeopleScreen.js
The user is directed here from Main.js. I have used the context api here to get the socket instance.
As you can see , i am using an event to log "Connected" to the console when connected but it is emitting multiple times.I don't want to emit it multiple times.Help me
import { SocketObj } from "./Main"
const PeopleScreen = ({ route, navigation }) => {
let socket = useContext(SocketObj)
socket.on("connect", () => console.log("Connect"))
const [peopleList, setPeople] = useState([])
useEffect(
() => {
const fetchData = async () => {
try {
const response = await API.get('get/users', {
headers: {
'Content-Type': 'application/json',
"auth-token": await AsyncStorage.getItem("token")
}
})
setPeople(response.data)
} catch (err) {
console.log(err.response)
}
}
fetchData()
}, []
)
return (
<View style={{
flex: 1,
backgroundColor: '#fff',
width: '100%',
height: '100%'
}} >
<View>
{
peopleList.map(
(i, key) => {
return (
<View style={{
display: 'flex',
flexDirection: 'row',
top: 40,
marginVertical: 5,
marginBottom: 10,
backgroundColor: 'grey',
height: 50
}}
key={key} >
<Text style={{
maxWidth: "50%"
}} >{i.firstName + ' ' + i.email}</Text>
<TouchableOpacity
onPress={
async () => {
console.log(socket)
API.post('post/add-friend', {
friend_email: i.email
}, {
headers: {
"auth-token": await AsyncStorage.getItem("token")
}
}).then(
data => console.log(data.data)
)
}
}
style={{
backgroundColor: 'rgb(255, 105, 105)',
width: 130,
justifyContent: 'center',
alignItems: 'center',
left: 150
}}
activeOpacity={0.6} >
<Text style={{
color: 'white',
}} >Add Friend</Text>
</TouchableOpacity>
</View>
)
}
)
}
</View>
</View >
)
}
export default PeopleScreen
I have ignored unnecessary imports.
Try to put your connect() inside an useEffect with an empty array as second argument of useEffect, then your connect function will be called only at the first render of Main.js.
...
const connect = async () => {
if (routesLength == 1) {
setSocket(io("http://192.168.43.115:8000", {
transports: ['websocket'],
query: {
token: await AsyncStorage.getItem("token")
}
}))
} else {
const { socketInstanse } = route.params
setSocket(socketInstanse)
}
}
useEffect(() => {
connect();
}, []);
...
if (!socket) return null; // or you can return a loading page
return (
<SocketObj.Provider value={socket} >
<TabView
navigationState={{ index, routes }}
renderScene={renderScene}
onIndexChange={(number) => {
setIndex(number)
}}
initialLayout={{ width: layout.width }}
/>
</SocketObj.Provider>
);
It happens due to initialisation of socket multiple time.Put instance in Main.js .
If socket instance is empty then initialise socket.
{ useEffect(() => { if(!isConnected){ connect() } });

how to map an array of images and use it as inline style in React

I have an array of 3 images and I want to use it as a background image.
import React from 'react'
import Bin1 from './images/bin1.png'
import Bin2 from './images/bin2.png'
import Bin3 from './images/bin3.png'
const array = ['Bin1', 'Bin2', 'Bin3'];
const style = {
height: '20rem',
width: '15rem',
marginRight: '1.5rem',
marginBottom: '1.5rem',
color: 'white',
padding: '1rem',
textAlign: 'center',
fontSize: '1rem',
lineHeight: 'normal',
float: 'left',
backgroundImage : `url(${Bin1})`
}
So instead of one URL of image, I want to map all three of them. I am new in React and really wanted to know how to solve this one.
So for Dustbin.jsx you will need to create an object of images with key-value as name of the image and the source. Then, appending backgroundImage while passing the style object to the div. Now, when you create a Dustbin component, just pass the name of the image you want to render as a prop (I called it bgImageName). Like this:
Dustbin.jsx
import React from "react";
import { DropTarget } from "react-dnd";
// THIS IS THE IMAGES LIST
const backgroundsList = {
tree:
"https://cdn.pixabay.com/photo/2020/02/17/19/33/tree-4857597_960_720.png",
avocado:
"https://cdn.pixabay.com/photo/2020/05/04/18/55/avocado-5130214_960_720.png",
snowman:
"https://cdn.pixabay.com/photo/2019/12/22/01/14/snowman-4711637_960_720.png"
};
const style = {
height: "12rem",
width: "12rem",
marginRight: "1.5rem",
marginBottom: "1.5rem",
color: "white",
padding: "1rem",
textAlign: "center",
fontSize: "1rem",
lineHeight: "normal",
float: "left",
backgroundSize: "contain" // TO FIT DIV
};
export const Dustbin = ({
accepts,
isOver,
canDrop,
connectDropTarget,
lastDroppedItem,
bgImageName
}) => {
const isActive = isOver && canDrop;
let backgroundColor = "#222";
if (isActive) {
backgroundColor = "darkgreen";
} else if (canDrop) {
backgroundColor = "darkkhaki";
}
let backgroundImage = `url(${backgroundsList[bgImageName]})`; // PASS A PROPERTY CALLED bgImageName WITH THE NAME OF THE IMAGE WE WANT.
return connectDropTarget(
<div style={{ ...style, backgroundColor, backgroundImage }}> // APPEND HERE
{isActive
? "Release to drop"
: `This dustbin accepts: ${accepts.join(", ")}`}
{lastDroppedItem && (
<p>Last dropped: {JSON.stringify(lastDroppedItem)}</p>
)}
</div>
);
};
export default DropTarget(
(props) => props.accepts,
{
drop(props, monitor) {
props.onDrop(monitor.getItem());
}
},
(connect, monitor) => ({
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver(),
canDrop: monitor.canDrop()
})
)(Dustbin);
And in Container.jsx add a property of background image to each dustbin object, and pass it to the component. like this:
Container.jsx
import React, { useState, useCallback } from "react";
import { NativeTypes } from "react-dnd-html5-backend";
import Dustbin from "./Dustbin";
import Box from "./Box";
import { ItemTypes } from "./ItemTypes";
import update from "immutability-helper";
export const Container = () => {
// ADD bgImageName TO EACH DUSTBIN OBJECT
const [dustbins, setDustbins] = useState([
{ accepts: [ItemTypes.GLASS], lastDroppedItem: null, bgImageName: "tree" },
{
accepts: [ItemTypes.FOOD],
lastDroppedItem: null,
bgImageName: "avocado"
},
{
accepts: [ItemTypes.PAPER, ItemTypes.GLASS, NativeTypes.URL],
lastDroppedItem: null,
bgImageName: "snowman"
},
{
accepts: [ItemTypes.PAPER, NativeTypes.FILE],
lastDroppedItem: null,
bgImageName: "tree"
}
]);
const [boxes] = useState([
{ name: "Bottle", type: ItemTypes.GLASS },
{ name: "Banana", type: ItemTypes.FOOD },
{ name: "Magazine", type: ItemTypes.PAPER }
]);
const [droppedBoxNames, setDroppedBoxNames] = useState([]);
function isDropped(boxName) {
return droppedBoxNames.indexOf(boxName) > -1;
}
const handleDrop = useCallback(
(index, item) => {
const { name } = item;
setDroppedBoxNames(
update(droppedBoxNames, name ? { $push: [name] } : { $push: [] })
);
setDustbins(
update(dustbins, {
[index]: {
lastDroppedItem: {
$set: item
}
}
})
);
},
[droppedBoxNames, dustbins]
);
return (
<div>
<div style={{ overflow: "hidden", clear: "both" }}>
{dustbins.map(({ accepts, lastDroppedItem, bgImageName }, index) => (
<Dustbin
accepts={accepts}
lastDroppedItem={lastDroppedItem}
onDrop={(item) => handleDrop(index, item)}
key={index}
bgImageName={bgImageName} // DONT FORGET TO PASS bgImageName PROPERTY TO Dustbin COMPONENT
/>
))}
</div>
<div style={{ overflow: "hidden", clear: "both" }}>
{boxes.map(({ name, type }, index) => (
<Box
name={name}
type={type}
isDropped={isDropped(name)}
key={index}
/>
))}
</div>
</div>
);
};
Codesandbox here

using custom variables or functions inside a makeStyle()

Im working on a React Material Ui component currently.
currently the goal is to be able to change JSS styling according to some custom function or values in another part of the application, without needing to add / remove classes
This is my current setup:
stepControl.js
const stepControl = () => {
const [activeStep, setActiveStep] = useState(0)
const [completed, setCompleted] = useState(new Set())
const [stepCount, setStepCount] = useState(0)
const completedSteps = () => {
return completed.size
}
const totalSteps = () => {
return stepCount
}
const allStepsCompleted = () => {
return completedSteps() === totalSteps()
}
return {
state: {
activeStep,
completed
},
actions: {
totalSteps,
completedSteps,
allStepsCompleted,
setActiveStep,
setCompleted,
setStepCount
}
}
}
export default stepControl
index.styles.js
import { makeStyles } from '#tim/functional'
import stepControl from './stepControl.js'
const useStyles = () => {
const { state, actions } = stepControl()
return makeStyles(theme => ({
root: {
width: '70%',
margin: 'auto',
'& .MuiPaper-root': {
backgroundColor: 'transparent'
},
'& .MuiStepConnector-lineHorizontal': {
borderTopWidth: 6,
borderRadius: 1,
marginTop: -2,
borderColor: actions.allStepsCompleted()
? theme.palette.primary
: rgba(0, 0, 0, 0.24)
}
},
button: {
marginRight: theme.spacing(1)
},
backButton: {
marginRight: theme.spacing(1)
},
completed: {
display: 'inline-block',
'& .MuiStepConnector-lineHorizontal': {
borderTopWidth: 6,
borderRadius: 1,
borderColor: theme.palette.primary
}
},
instructions: {
marginTop: theme.spacing(1),
marginBottom: theme.spacing(1)
}
}))
}
export default useStyles
Currently im getting too many rerenders error even if i just return a fixed value in the function in question allStepsCompleted() . how would i go about doing this in Material Ui?
Im running:
React 16.9
Mui 4.9.5
on a webpack 4.4 server on macOS 10.15
Thanks in advance for any suggestions

Component looping over infinitely after updating state

I'm trying to update state under a promise. But the component is going over and over again infinitely until it max out the heap size. I don't know what I'm missing here.
This is my code
import {useDropzone} from 'react-dropzone';
import File from './File'
import parser from 'subtitles-parser'
const baseStyle = {
flex: 1,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
padding: '20px',
borderWidth: 2,
borderRadius: 2,
borderColor: '#eeeeee',
borderStyle: 'dashed',
backgroundColor: '#fafafa',
color: '#bdbdbd',
outline: 'none',
transition: 'border .24s ease-in-out'
};
const activeStyle = {
borderColor: '#2196f3'
};
const acceptStyle = {
borderColor: '#00e676'
};
const rejectStyle = {
borderColor: '#ff1744'
};
function Drag(props) {
const {
getRootProps,
getInputProps,
isDragActive,
isDragAccept,
isDragReject,
acceptedFiles
} = useDropzone();
const style = useMemo(() => ({
...baseStyle,
...(isDragActive ? activeStyle : {}),
...(isDragAccept ? acceptStyle : {}),
...(isDragReject ? rejectStyle : {})
}), [
isDragActive,
isDragReject
]);
const [data, setData] = useState(null)
if(acceptedFiles.length === 1){
const readUploadedFileAsText = (acceptedFiles) => {
const temporaryFileReader = new FileReader();
return new Promise((resolve, reject) => {
temporaryFileReader.onerror = () => {
temporaryFileReader.abort();
reject(new DOMException("Problem parsing input file."));
};
temporaryFileReader.onload = () => {
resolve(parser.fromSrt(temporaryFileReader.result));
};
temporaryFileReader.readAsText(acceptedFiles);
});
};
let file = acceptedFiles[0]
readUploadedFileAsText(file)
.then(res => {
setData({
data: res
})
})
}
return (
<div className="container">
<div {...getRootProps({style})}>
<input {...getInputProps()} />
<p>Drag 'n' drop some files here, or click to select files</p>
</div>
<File file={data} />
{console.log(data)}
</div>
);
}
export default Drag
Let me know if I have to use any lifecycle methods. I tried using componentDidMount and componentWillReceiveProps but both didn't work for me or I hadn't done them in right way.
Take your readUploadedFileAsText function outside of the if statement it is in. Then you can add your if and function call to React.useEffect which will call the function on initial load, but not on every subsequent re-render.
function Drag(props) {
const { getRootProps, getInputProps, isDragActive, isDragAccept, isDragReject, acceptedFiles } = useDropzone();
const style = useMemo(
() => ({
...baseStyle,
...(isDragActive ? activeStyle : {}),
...(isDragAccept ? acceptStyle : {}),
...(isDragReject ? rejectStyle : {})
}),
[isDragActive, isDragReject]
);
const [data, setData] = useState(null);
const readUploadedFileAsText = acceptedFiles => {
const temporaryFileReader = new FileReader();
return new Promise((resolve, reject) => {
temporaryFileReader.onerror = () => {
temporaryFileReader.abort();
reject(new DOMException('Problem parsing input file.'));
};
temporaryFileReader.onload = () => {
resolve(parser.fromSrt(temporaryFileReader.result));
};
temporaryFileReader.readAsText(acceptedFiles);
});
};
React.useEffect(() => {
if (acceptedFiles.length === 1) {
let file = acceptedFiles[0];
readUploadedFileAsText(file).then(res => {
setData({
data: res
});
});
}
}, [acceptedFiles]);
return (
<div className='container'>
<div {...getRootProps({ style })}>
<input {...getInputProps()} />
<p>Drag 'n' drop some files here, or click to select files</p>
</div>
<File file={data} />
{console.log(data)}
</div>
);
}

Categories