I am trying to import a CSV for use with the D3 library to create a chart within a Create React App project, but importing the file is throwing a "Cannot find module" error even though the path to the CSV file is correct.
I have a feeling this might be something to do with CRA's Webpack config under the hood but it looks like this is using the file loader so I'm not sure what the issue is. The data file is within CRA's src directory.
The console log in the code below is running with the correct data in, which means the data must be being accessed. The error is thrown after this (Although the path to the CSV is underlined red in my editor).
I am using TypeScript but I don't think this has anything to do with the problem.
import React from 'react';
import * as d3 from 'd3';
import CSVData from '../data/data.csv';
const BarChart: React.FC = () => {
d3.csv(CSVData).then(res => {
console.log(res);
});
return <div>Test</div>;
};
export default BarChart;
CRA doesn't support importing .csv files. Without ejecting from CRA, your best option is to copy that file along with the results of yarn/npm build to your web server and then fetching it at runtime.
If that CSV is big (more than a few kb), then it is also the better option in terms of performance/code splitting.
Thanks to Nick Ribal for his answer, I found a similar solution by moving my data file into the public folder and then referencing this via the PUBLIC_URL environment variable.
I used the D3 CSV method which will get data from a URL if passed one rather than using fetch and parsing this as text.
With D3 CSV method:
import React, { useState } from 'react';
import { DSVRowArray } from 'd3';
import * as d3 from 'd3';
type CSVData = DSVRowArray | null;
const BarChart: React.FC = () => {
const initialState: CSVData = null;
const [fetchedCSVData, setFetchedCSVdata] = useState<CSVData>(initialState);
if (!fetchedCSVData) {
d3.csv(`${process.env.PUBLIC_URL}/data/data.csv`).then(res => {
setFetchedCSVdata(res);
});
}
return <div>Test</div>;
};
export default BarChart;
Without D3 CSV method:
import React, { useState } from 'react';
type CSVData = string | null;
const BarChart: React.FC = () => {
const initialState: CSVData = null;
const [fetchedCSVData, setFetchedCSVData] = useState<CSVData>(initialState);
if (!fetchedCSVData) {
fetch(`${process.env.PUBLIC_URL}/data/data.csv`)
.then(res => res.text())
.then(stringData => {
console.log(stringData);
setFetchedCSVData(stringData);
});
}
return <div>Test</div>;
};
export default BarChart;
Related
I am trying out a small sample in nextjs. All that the proj does is to fetch json data from a file and try displaying it in list of a component. But the behavior is weird. Its getting into infinite loop and I have no clue what's wrong. Could some one take a look at https://github.com/SamplesForMurthy/sampleCode and help me figure out what the issue is? Not able to fetch the data nor I am able to display.
I cloned and fixed. You don't need to use fs.readFileSync here, or fs at all for that matter. You can simply import the .json file as an arbitrarily named variable then map it out.
Here is how I got the data rendering:
import React from 'react';
import testData from '../TestData/SampleData.json';
import SampleParentComponent from '../components/SampleParentComponent';
function TestPage({ filecontent }) {
console.log(`filecontent: ${filecontent}`);
return (
<div>
<SampleParentComponent data={filecontent}></SampleParentComponent>
</div>
);
}
export const getStaticProps = async ctx => {
console.log(ctx.query);
const filecontent = await testData;
return {
props: { filecontent }
};
};
export default TestPage;
/**
* (property) filecontent: {
data: {
seqNo: number;
contactName: string;
}[];
}
*/
I have been working on a React Native project with Expo that uses a json file to store local data. I am importing the data like so
import data from '../database.json'
I am making changes (adding and removing) to the imported JSON by using data.push(new_data). These changes are not persistent when I close the app because I cannot figure out how to save them. I have looked at using the expo-file-system library as so:
import * as FileSystem from 'expo-file-system';
...
FileSystem.writeAsStringAsync(FileSystem.documentDirectory + 'database.json', data);
This is from looking at examples in the API documentations. This however always throws promise rejections and doesn't end up writing the file. Can you point me in the right direction?
Also, should I import the database.json in a different way so I will already have the uri to save it to?
The documentation doesn't give an example of it's returned props in promises, so I was overlooking it for longer than I care to admit 😅. I was really dedicated to figuring this out so I could use the Expo solution, and totally missed the return Promise for createFileAsync, so hopefully this saves someone a significant amount of time in the future.
import * as FileSystem from 'expo-file-system';
const { StorageAccessFramework } = FileSystem;
const saveFile = async () => {
const permissions = await StorageAccessFramework.requestDirectoryPermissionsAsync();
// Check if permission granted
if (permissions.granted) {
// Get the directory uri that was approved
let directoryUri = permissions.directoryUri;
let data = "Hello World";
// Create file and pass it's SAF URI
await StorageAccessFramework.createFileAsync(directoryUri, "filename", "application/json").then(async(fileUri) => {
// Save data to newly created file
await FileSystem.writeAsStringAsync(fileUri, data, { encoding: FileSystem.EncodingType.UTF8 });
})
.catch((e) => {
console.log(e);
});
} else {
alert("You must allow permission to save.")
}
}
Use AsyncStorage instead. The react native package is deprecated but working, or use #react-native-community/async-storage and convert json to string (AsyncStorage can only store strings)
Set item
import AsyncStorage from '#react-native-community/async-storage';
...
await AsyncStorage.setItem('myData', JSON.stringify(data))
Get item
const data = await AsyncStorage.getItem('myData')
I found #JayMax answer very helpful however it's only for Android.
On iOS all you need to do is use Sharing.shareAsync and then you can save data to the file. Check this example:
const fileUri = FileSystem.documentDirectory + 'data.txt';
FileSystem.writeAsStringAsync(fileUri, 'here goes your data from JSON. You can stringify it :)', {
encoding: FileSystem.EncodingType.UTF8,
});
const UTI = 'public.text';
Sharing.shareAsync(fileUri, {UTI}).catch((error) => {
console.log(error);
});
If you using AsyncStorage, it only store for small data. Maybe 6mb or 10 mb.
You can use expo fileSystem
import * as FileSystem from 'expo-file-system';
...
FileSystem.writeAsStringAsync(FileSystem.documentDirectory + 'database.json', data);
Convert your data (Type json to string) Such as this:
writeData = async () => {
var persons = ''
await axios.get(`http://192.168.0.48:4000/api/sql/student`)
.then(res => {
persons = res.data
})
await FileSystem.writeAsStringAsync(FileSystem.documentDirectory + `offline_queue_stored.json`, JSON.stringify(persons));
}
#1.If the JSON File is in your Project Folder (PC/Laptop)
import data from './database.json';
#2. If the JSON File is in your Phone
import * as FileSystem from 'expo-file-system';
import * as DocumentPicker from 'expo-document-picker';
this.state = {
fileURI: null,
};
componentDidMount = () =>{
this._pickDocument();
}
_pickDocument = async () => {
let result = await DocumentPicker.getDocumentAsync({});
this.setState({
fileURI: result.uri
})
let fileData = await FileSystem.readAsStringAsync(this.state.fileURI)
console.log(fileData)
};
I'm trying to have my add data from a local static JSON file to the Vue vuex store.
I want my JSON file separated from the bundle process, so that i can change the content anytime in future, without rebuilding the whole site.
I have my json file [test.json] in the public folder
And with the following code, i managed to import the data, but its still being bundled on build of the site.
import data from '../public/test';
export const state = () => ({
allData: {}
})
export const mutations = {
SET_ALL_DATA(state, data) {
state.allData = data
}
}
export const actions = {
nuxtServerInit({ commit }) {
commit('SET_ALL_DATA', data)
}
}
I have also tried hosting the JSON file on a web server and doing an axios call to it on nuxtServerInit like so. but the called upon json file still gets bundled, as changing the hosted json file does nothing to update the content.
export const actions = {
async nuxtServerInit ({ commit }, { $axios }) {
const res = await $axios.$get('https://www.amq.fariskassim.com/testjson/test.json')
commit('SET_ALL_DATA', res)
}
}
I'm all out of solutions so if anyone can point me in the right direction, i would be totally grateful
To illustrate the problem i started a new App using the create-react-app tool (from https://github.com/facebook/create-react-app)
I want to be able to load in data from CSV files, I am using the CSV method from d3:
csv('data.csv').then(data => {
console.log(data)
});
I added this function to the App.js file:
import React from 'react';
import './data.csv';
import { csv } from 'd3'
function App() {
csv('data.csv').then(data => {
console.log(data)
});
return (
<div className="App">
</div>
);
};
export default App;
Every time I attempt this the code returns an Array of the Index.html code (pictured) instead of the data in the CSV file. I am sure as to why this is happening?
The CSV file is in the /src folder
Screenshot of console log
Let me first explain what went wrong. In your code, you are trying to access the file which is not there. And I'm not talking about the import. After the import when you are using the file name in csv function it doesn't have a proper path.
use this import statement - import data from './data.csv';
once application is compiled the data have the url of the file. Now if you console.log the data you'll get this - /static/media/data.csv
Note: Path may differ based on the tool used for compilation. I'm using yarn.
Now pass the data into csv function like this:
csv(data).then(response => {
console.log(response)
})
I hope this helps you understand how this is working. Refer the code shown below for the calling structure.
function App(){
console.log(data);
csv(data).then(response => {
console.log(response)
})
return (
<div className="App">Test</div>
);
}
If you have any questions or queries feel free to reach out.
Cheers :)
You need to perform the csv action somewhere in return part of the function like
import React from 'react';
import './data.csv';
import { csv } from 'd3'
function App() {
return (
<div className="App">
{csv('data.csv').then(data => {
console.log(data)
// perform all here
});}
</div>
);
};
export default App;
also you dont need to import the csv and correct csv path should be given in csv function. The most probable issue is you are not getting the file due to incorrect path.
Try importing your dataset first using React's method and then parse it using D3.csv function
import React from 'react';
import data from './data.csv';
import { csv } from 'd3';
function App() {
csv(data, function(error, data) {
if (error) throw error;
console.log(data);
});
return (
<div className="App">
</div>
);
};
export default App;
Im setting my store on my react native app, is working fine with redux-dev-tools,
but I dont know how to refactor.
const store = createStore(reducer, /* preloadedState, */
composeEnhancers(
applyMiddleware(...middleware)));
const configureStore = () => {
return store;
};
export { configureStore };
The goal is to export only "store" as a function
Why do you want to export store as a function as you could just as well export it as an object?
export const store = configureStore();
This way you could also just import it in any file you like:
import {Â store }Â from '...';
// Now you can access the redux store and dispatch actions:
store.getState() ...
store.dispatch(...)