i have this array of objects, the thing that i am trying to do is to take the array from the file it's sitting in, and transfer it to another file where i can map the items. This is my code (the formatting and spacing is not on point) :
const Upload = () => {
const photos = [
{
id: new Date().getMilliseconds().toString(),
imagePath: "url..."
},
];
return (
<>
// Markup ....
</>
);
};
And i want to do something like this:
import photos from './COMPONENT_NAME';
const Func = () => {
return (
<> {photos.map((item) => <div> code... </div> )} </>
);
Is there any way to do it?
You can simply export them.
First, move the list outside of the Upload function and then put export key before the declaration like so.
export const photos = [
{
id: new Date().getMilliseconds().toString(),
imagePath: "url..."
},
];
const Upload = () => {
return (
<>
// Markup ....
</>
);
};
Then import them.
import { photos } from './COMPONENT_NAME';
Related
Just like the title says I'm passing down pokemon data and rickandmorty data. I also happen to be using the tailwind select menu for react thats pretty long. Is there a better way to do it than conditionally map through the data? I know I can do this
{pokemons ? (
{pokemons?.map((pokemon, idx) => (
**30 line long code for the select menu**
))}
) : (
{rickAndMorty?.map((character, idx) => (
**Another 30 long line code for the select menu**
))}
)}
Is this the only way to do it or is there a cleaner way? Any help would be greatly appreciated. Thanks!
I suggest to try and separate any duplicated code out into some generic component, like:
const GenericSelectItem = (props)=>{
return (<>{/* props.itemValues */}</>);
};
const GenericSelectList = (props)=>{
const { selectItems } = props;
return (<SelectList>
{ selectItems.map( selectItem => <GenericSelectItem selectItem={ selectItem } /> ) }
</SelectList>);
};
const Example = (props)=>{
const itemsToDisplay = pokemons || rickAndMorty;
return (<>
{ !itemsToDisplay ? null : <GenericSelectList selectItems={ itemsToDisplay } /> }
</>);
};
In case the SelectItems are very different, add specific components, like:
const PokemonItem = (props)=>{
return (<GenericSelectItem>{/* pokemon specific variations */}</GenericSelectItem>);
};
const RickAndMortyItem = (props)=>{
return (<GenericSelectItem>{/* rickAndMorty specific variations */}</GenericSelectItem>);
};
I have data mapped in a component like this:
import React from "react";
import { useState } from "react";
import { useEffect } from "react";
import { get } from "lodash";
const Products = ({ data }) => {
return (
data.map((item, index) = > (
<div id={index}>
<img src={item.img} /> <br />
{item.name} <br />
{get(moreData, `[${item.name.toLowerCase()}].info[0]`)}
{get(moreData, `[${item.name.toLowerCase()}].info[1]`)}
{get(moreData, `[${item.name.toLowerCase()}].info[2]`)}
</div>
I want to be able to store this data:
{item.name}
{get(moreData, `[${item.name.toLowerCase()}].info[0]`)}
{get(moreData, `[${item.name.toLowerCase()}].info[1]`)}
{get(moreData, `[${item.name.toLowerCase()}].info[2]`)}
in a string, like string = {item.name},{moreData.item.name.toLowerCase().info[0]},...//etc
However you cannot declare variables inside of a component (as far as i know, still new to this).
I've tried .concat() - after each line and .push() with array instead of string:
{item.name} <br />
{dataString.concat(item.name)}
{dataArr.push(item.name)}
{get(moreData, `[${item.name.toLowerCase()}].info[0]`)}
{get(moreData, `[${item.name.toLowerCase()}].info[1]`)}
{get(moreData, `[${item.name.toLowerCase()}].info[2]`)}
I was going to use DOM, but i've been told it's bad practice to use DOM in react.
I've also tried using state in the same way:
const [dataString, setDataString] = useState("");
...
{item.name}
{setDataString((dataString += item.name))}
But nothing seems to work as intended for me, and i'm out of ideas.
Edit:
I want to be able to copy the 'string/text' to clipboard eventually. So it can be imported to another site. Their required format is Item1, item1-info1, item1-info2, item1-info3, item2, item2-info1, item2-info2, item2-info3...etc
here is an example of how you can use the data object outside of the mapped objects.
also an example how to convert the data to an string in the format required.
because I don't know the structure of the data object of yours I just created an one, take this code and change it to the data structure
const data = [
{
name: "name1",
info1: "info1-1",
info2: "info1-2",
info3: "info1-3",
},
{
name: "name2",
info1: "info2-1",
info2: "info2-2",
info3: "info2-3",
},
{
name: "name3",
info1: "info3-1",
info2: "info3-2",
info3: "info3-3",
},
];
change this function to one that fits your needs.
const getStringOfData = (data) => {
let stringArray = [];
data.map((item) => {
stringArray.push(item.name);
stringArray.push(item.info1);
stringArray.push(item.info2);
stringArray.push(item.info3);
});
let stringResult = stringArray.join(",");
return stringResult;
};
useEffect(() => {
console.log("onMounte with useEffect");
let stringResult = getStringOfData(data)
console.log(stringResult);
}, []);
you can also call this function on onClick function depend in your requirement , the data object is available almost everywhere in your component
Continuing our discussion from the comments, it looks like there are two different things you are trying to do here:
display the UI to the user in a certain way
to be able to copy the information in a specific stringified format
I would advice to split these two behaviors, because they are totally unrelated to each other in terms of logic.
Start by aligning the information in your components how you need it.
const Product = ({ item, index }) => {
// do whatever you need to do with the information
// to display it correctly
const identifier = name.toLowerCase()
const infos = (moreData[identifier] && moreData[identifier].info) || {}
return (
<div>
{ info[0] && <p> info[0] </p>}
{ info[1] && <p> info[1] </p>}
{ info[1] && <p> info[2] </p>}
</div>
)
}
const Products = ({ data }) => {
const onClick = useCallback(
async () => {
// parse data and copy it using a separate
// util method.
const dataToString = /* actual implementation of the formatting to a string representation */
copyTextToClipBoard(dataToString)
},
[data]
)
return (
<div>
<button onClick={onClick} />
<div>
data.map((item, index) => (
<Product item={item} index={index} key={item.id} />
))
</div>
</div>
)
};
Now this would be your UI, the copyToClipboard method, is a bit of a hack, and looks like so:
const copyTextToClipBoard = (text) => {
const element = document.createElement('textarea');
element.style = { display: 'none' }; // eslint-disable-line
element.value = text;
document.body.appendChild(element);
element.select();
document.execCommand('copy');
document.body.removeChild(element);
};
I've a component call KeywordLocation.js, and It has one prop named location.
this component is a mapped array and on click I want to save the object of location in localStorage. I created here an empty array and pushing the object on every click. For now I'm getting 5 mapped location objects. when I click on any of them, it saves the object but on 2nd click it doesn't stop duplicating the object. How do I stop this duplication?
searchedLocation.map((location, i) => {
return (
<KeywordLocation
setShowMap={props.setShowMap}
location={location}
key={i}
getPositionFromManualSearch={props.getPositionFromManualSearch}
/>
);
});
KeywordLocation.js
const Component = ({ location }) => {
let allSearchedLocations = [];
const redirectToMap = async () => {
allSearchedLocations.push(location);
allSearchedLocations = allSearchedLocations.concat(
JSON.parse(localStorage.getItem("recent_location_searched") || "[]")
);
const previousLocation = JSON.parse(
localStorage.getItem("recent_location_searched")
);
console.log(previousLocation);
localStorage.setItem(
"recent_location_searched",
JSON.stringify(allSearchedLocations)
);
};
return (
<div onClick={() => redirectToMap()} className="pt-md cursor-pointer">
<p>{location.structured_formatting.main_text}</p>
<p className="text-xs border-b border-black pb-md ">
{location.description}
</p>
</div>
);
};
Are you entirely sure the duplication is ocurring on local storage?
As long as you use the same key, recent_location_searched, there will be only one value stored on that key. Take a look at the "Storage" tab on your browser's debug console to see what's actually being stored.
All evidence seems to point that the duplication is ocurring at the searchLocations variable, not atlocalStorage.
You might try to add some conditional logic that prevents you from pushing to searchLocations if the location is the same as the one on the last item on the array.
The problem is not related to localStorage but more about the usage of the array structure. You could rely on JavaScripts object to store the unique values. You lose the insertion order but you can create a companion array that keep a reference to the order.
const Test = ({ location }) => {
const redirectToMap = () => {
const locations =
JSON.parse(localStorage.getItem("recent_location_searched")) || {};
locations[location.name] = location;
localStorage.setItem("recent_location_searched", JSON.stringify(locations));
};
return (
<div onClick={() => redirectToMap()} className="pt-md cursor-pointer">
<p>{location.name}</p>
</div>
);
};
export default function App() {
const data =
JSON.parse(localStorage.getItem("recent_location_searched")) || {};
return (
<div>
<div className="App">
{[
{ name: "location1" },
{ name: "location3" },
{ name: "location2" }
].map((location) => (
<Test key={location.name} location={location} />
))}
</div>
<ul>
{Object.values(data).map((location) => (
<li key={location.name}>Saved {location.name}</li>
))}
</ul>
</div>
);
}
I have the following which is changing the values, but it's always one step behind. For example, when you click on the "paid: false" for a customer, it changes to true but the app doesn't rerender and you have to update another thing on the app in order to see the change. Is there a simple way to fix this in React? I don't know how to research what I'm looking for so a point in the right direction will help a lot.
const [receipt, setReceipt] = useState(receiptData);
// const [currentReceipt, setCurrentReceipt] = useState({});
// For some reason I do not know yet, everything is working but this and onSubmitFromApp are one step behind.
const handlePaid = (index) => {
for (let receiptPaid in receiptData) {
if (receiptPaid === index) {
receiptPaid.paid = !receiptPaid.paid;
console.log(receiptPaid);
}
}
setReceipt(receiptData);
}
Link to full code: https://codesandbox.io/s/korilla-receipts-starter-forked-01xz0?file=/src/App.js:206-675
Your approach is kind of weird and involves mutations. You're better off doing something like this (I removed the form stuff cos that's unrelated):
// App.js
export default function App() {
const [receipts, setReceipts] = useState(receiptData);
// Map over the current state, not the imported array
const handlePaid = (id) => {
setReceipts(
receipts.map((receipt) =>
receipt.id === id ? { ...receipt, paid: !receipt.paid } : receipt
)
);
};
return (
<div className="App">
<Receipts receiptsArr={receipts} handlePaid={handlePaid} />
</div>
);
}
// Receipts.js
const Receipts = (props) => {
const receiptMap = props.receiptsArr.map((receipt, index) => {
return (
<Receipt
...
handlePaid={() => props.handlePaid(receipt.id)}
/>
);
});
return <div className="container">{receiptMap}</div>;
};
// Receipt.js
const Receipt = (props) => {
return (
...
<span onClick={props.handlePaid} >Paid: {props.paid ? 'true' : 'false'}</span>
</div>
)
}
You can check out the sandbox here
I'm new to React & I'm working on a personal project using it.
I'm currently trying to implement a feature that allows the user to click a button that takes them to their file explorer & let's them select a file (just a standard file selector).
ISSUE:I'm unable to find a good React package/library for this that actually makes sense. Every option I evaluated made no sense to me, and therefore I don't want to use it.
Currently I have a button that allows me to select a file, but I'm trying to figure out how to get the file's name and then print the file out?
MY CODE:
import { FilePicker } from 'react-file-picker';
MyComponent = () => (
<FilePicker
extensions={['.docx']}
// onChange={FileObject => ()}
// onError={errMsg => ()}
>
<Button style={{backgroundColor: "#f57505", width: "75px"}}>Upload</Button>
</FilePicker>
)
Thanks!
how to get the file's name
The FileObject return a File type. which means you can get the file name by doing FileObject.name.
and then print the file out
You will need a third party library like this: https://www.npmjs.com/package/mammoth
Here's an working example:
import React, { Component } from "react";
import { FilePicker } from "react-file-picker";
import { render } from "react-dom";
import mammoth from "mammoth";
class App extends Component {
constructor() {
super();
this.state = {
title: "",
text: ""
};
}
extractWordRawText = arrayBuffer => {
mammoth
.extractRawText({ arrayBuffer })
.then(result => {
const text = result.value; // The raw text
const messages = result.messages; // Please handle messages
this.setState({ text });
})
.done();
};
handleFileChange = file => {
const reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = e => {
this.extractWordRawText(e.target.result);
};
this.setState({ title: file.name });
};
render() {
const { title, text } = this.state;
return (
<div>
<h1>{title}</h1>
<p>{text}</p>
<FilePicker
extensions={["docx"]} // Notice that I removed the "."
onChange={this.handleFileChange}
onError={errMsg => console.log(errMsg)} // Please handle error
>
<button style={{ backgroundColor: "#f57505", width: "75px" }}>
Upload
</button>
</FilePicker>
</div>
);
}
}
render(<App />, document.getElementById("root"));
Hope it helps. Happy coding.