I have the following JSON Data coming out of Firebase RTDB:
{"\"1\"":{"itemDescription":"This is a description of the item.","itemName":"Item Name","itemValue":{"costAmount":200,"costType":"dol"}},
"\"2\"":{"itemDescription":"This is an item description.","itemName":"Item Name 2","itemValue":{"costAmount":500,"costType":"dol"}}}
and so on...
The data is parsed (json.parse) and stored a variable called parsedJSONData in state.
I've tried looping through it using other recommendations on this site and others, such as:
this.state.parsedJSONData.map(json => {
<div className="item">
<p>Item: {json.itemName}</p>
</div>;
});
And I'm getting errors like the below:
Line 68: Expected an assignment or function call and instead saw an expression no-unused-expressions
Any tips on what I can do? I know the data is parsed correctly, because if I output the contents of the parsedJsonData to the console, I can see the data is structured correctly?
Try Using forEach() instead of map()
You are not returning anything inside of your map(). Here you can look at the different ways to return values from an arrow function, but in short, data will be returned in these two forms:
json => json.itemName
json => {return json.itemName;}
Drop the {} inside of your map or throw a return inside like so:
this.state.parsedJSONData.map(({itemName}) =>
<div className="item">
<p>Item: {itemName}</p>
</div>
);
or
this.state.parsedJSONData.map(({itemName}) => {
return <div className="item">
<p>Item: {itemName}</p>
</div>;
});
Try this. I have tried this and it works for the your json Data.
render() {
var tempData = [];
const theDataWeHave = this.state.parsedJSONData;
for(var row in theDataWeHave){
var rowEntry = theDataWeHave[row];
tempData.push(rowEntry);
}
var renderVariable = tempData.map(function(item,index) {
return ( <RenderThisComponent key={index} item={item}/> )
})
}
return(
//your code for other stuff
{renderVariable} //Place this where you want to render the component
)
The component you want to render will be a separate functional component with props passed to it.
You can write in the same file or you can write in separate file and import+export
.I have done in the same file so it do not need to be exported or imported.
const RenderThisComponent = (props) => (
<div className="item">
<p>Item: {props.item.itemName}</p>
</div>
)
Related
I am facing difficulties rendering array on screen when I navigate back to the component. I have been trying and searching since morning for the solution but no luck. Please let me explain
I have a react component called ShowTags.tsx that contains a callback function handleTagReading() which return strings every second (async behavior).
When the string tag arrives I am storing it in [storeTags] state array and in the return method, using map function to iterate and display the tags.
The Sample code
export default function ShowTags() {
//array to store string tags
const [storeTags, setStoreTags] = useState<String[]>([]);
//callback method
const handleTagReading = (tag) => {
console.log("print the tag" + tag) // this line runs everytime
setStoreTags(storeTags => [...storeTags!, tag]);
}
return (
<>
/*This component contains a button, on button click it runs the loop method which runs
the parent callback method*/
<ReadTags parentCallback = {handleTagReading} />
<div className="container">
{storeTags && storeTags!.map((item, index) => {
return (
<div>
{item}
</div>)
})}
</div>
</>
)
}
This code works perfectly as long as I am on The ShowTags component for the first time. The moment I navigate to a different component and come back, the map method shows nothing. But console.log() still runs showing the tags coming from a callback.
I have tried using the useEffect(), cleanup(), boolean states variables, non state variables but the component does not render when switching back to ShowTags component.
Please help me out here and let me know if you need more information
UPDATE -edit
For simplicity I said async behavior but actually I am using Serial USB API to read data from RFID reader (external hardware device connected via USB)
The ReadTags() component contains lot of code but I am sharing the necessary bits
export default function ReadTags(props) {
//send diffenent commands to reader on button press
async function sendSerialLine() {
try{
await writer.write(dataToSend);
}catch(e){
console.log("the write error")
setShowConnect(true)
}
}
//The listenToPort method runs continuously when the RFID reader gets connected via Serial USB and does not stop.
async function listenToPort(){
/*serial USB API implementation*/
textDecoder = new TextDecoderStream();
readableStreamClosed = port.readable.pipeTo(textDecoder.writable);
reader = textDecoder.readable.getReader();
while (true) {
const { value, done } = await reader.read();
if (done) {
reader.releaseLock();
break;
}
//parent callback
props.parentCallback(value);
}}
return (
<div>
<p onClick={() => sendSerialLine()} className="btn btn-primary">Start Reading</p>
</div>
)
}
Try to use useCallback with handleTagReading
I've been trying to work out whats going in the below code all day and after searching through stack over flow and you-tube, I still cant figure out whats wrong with my code.
Essentially I have a user document stored on firebase firestore. Inside the document I have an array of 'friends'.
[Heres what my firebase backend looks like.
I'm pulling the whole document into my React JS project and saving it onto a global state called friendsList.
Inside my profile page component.The console logs the user attribute of each user in the friend array (so its definitely getting the data), console log output
Now inside the return section on my profile page component, I go to pass in the friend as an object and display the FriendItemUI component, however nothing displays and no error occurs. I even tried to just display a paragraph <p and log just the user ID of the currently selected array item, but nothing showed in the console log, no errors, and nothing displayed on the component itself.
Now if i place the
console.log(friend.friend.user)
inside the return statement, it will log the users ID to the console without any issues.
So it seems to be that i can log the information to the console, inside and outside the return function, but i cant pass the actual array object into another component and i cant actually visiually show any information from the array in a div?
I'm not sure what im doing wrong and any help is appreciated.
Profile Page Component:
render(){
const { friendsList } = this.props;
return (
<div>
<a class="waves-effect waves-light btn" onClick={() => this.sendFriendRequest()}>Add
Friend</a>
{ friendsList && friendsList.map(friendsList => {
{ friendsList.friends.map(friend => {
//friendsList is a firebase firestore document.
// friendsList.friends is the array 'friends' inside the document
(async() => {
console.log("waiting for variable");
while(typeof friend.friend.user == "undefined")
await new Promise(resolve => setTimeout(resolve, 1000));
(console.log("variable is defined: " + friend.friend.user))
return(
<div>
<p>{friend.friend.user}</p>
<FriendItemUI friend={friend}/>
</div>
)
})();
})}
})}
</div>
)
}
FriendItemUI.JS component
class FriendItemUI extends Component {
render() {
const { friend } = this.props;
// this log doesnt even display anything to the console
console.log(friend + 'test')
if(friend) {
return <p> testing {friend.friend.user} | {friend.friend.personalMessage} | {friend.friend.friendStatus} </p>
}
else {
return(
<div>
<p>error loading friendlist</p>
</div>
)
}
}}
export default FriendItemUI
Now heres where it gets even more weird, If i dont want to go through all the friends in the array object and just want to display one friend, I can with the following code. [this code will now pass the friends array object into the FriendItemUI component and successfully display the name, personalMessage and friendStatus which is all taken from the firestore document array object..
const { friendsList } = this.props;
{ friendsList && friendsList.map(friendsList => {
return (
<FriendItemUI friend={friendsList.friends[1]}/>
)
I'm just really confused, I dont want to hard code which index values of the array i want to show, I'm trying to make the component check to see how many objects in the array there is, loop through the array and pass each of the friends from the array into the FriendItemUI component.
I'm super silly!, turns out that console.log and manually rendering a state was fine because react JS was smart enough to only render once the state values were defined with my firebase data.
All i had to do was modify the code as per below and add a check to only loop through the array if the array state value is != null. If the array state value is == null then return a loading results text message.
everything now works. Posting this answer incase someone runs into a similar issue.
render(){
console.log(this.props); // debug log
const { friendsList, profile } = this.props;
console.log('test log' + profile);
if(profile.friends!=null){
return(
<div className="container">
<a class="waves-effect waves-light btn" onClick={() => this.sendFriendRequest()}>Submit Friend Request</a>
{ profile && profile.friends.map(profile => { //if valid survey, return
return (
<div>
<FriendItemUI friend={profile}/>
</div>
)
})}
</div>
)
} else{
return (
<div>
<p style={{textAlign: 'center'}}>Loading Results</p>
</div>
)
}
}
function validate is supposed to return element if function getConjugation doesn't return error, the valid input is passed to getConjugation, but it just renders nothing in browser
import React from 'react'
import {getConjugation} from 'german-verbs'
import GermanVerbsDict from 'german-verbs-dict'
export default ({word})=>{
const renderVerbs =(w)=>{
return (
}
const validate = (w) =>{
try{
return(
<ul>
<li>{w.toLowerCase()}</li>
<li>{getConjugation(GermanVerbsDict, "haben",'PRASENS', 2,'S' )}</li>
<li>{getConjugation(GermanVerbsDict,"haben",'PRATERITUM', 1,'S' )}</li>
<li>{getConjugation(GermanVerbsDict, "haben",'PERFEKT', 1,'S', "HABEN")}</li>
</ul>)
}catch {return false}
}
return (
<div className="verb">{validate(word)}</div>
)
}
You may try 3 things
Complete the renderVerbs function since now is missing a bracket.
This part of code seems to be exported out. Have you added this component to where it suppose to be?
Check whether validate function is actually been called. Here is what I will do.
const validate = (w) =>{
console.log("the word is: ", w);
return(
<ul>
<li>{w.toLowerCase()}</li>
//if your function return an array
YourArray.map(elem => (
<li>{elem}</li>
))
</ul>)
}
}
return (
<div className="verb">{validate(word)}</div>
)
If it does work, add one extra block code each at a time until it comes to your original code mentioned here. Hope you may find which part is buggy in this process. Good luck.
I want to concatenate two strings in react such that the first displays bold and the second does not. I have the string I want bolded in a JSON file and I have the string I want to concatenate coming from backend API call. Here's my setup:
This is in a JSON file:
{ stuff: {
stuffIWantBolded: "bold text"
}
}
And my frontend looks like this:
render() {
// props for this component in which I'm rendering SomeComponent (see below)
const { data } = this.props
const { theStringFromBackend } = data
// a method to get the string that is working for me
const stuff = this.getTheStringFromTheJSON();
const textIWantToDisplay = `${stuff.stuffIWantBolded} ${theStringFromBackend}`;
return (
<SomeComponent someProp={textIWantToDisplay} />
);
};
That concatenates the two strings successfully. I've tried using .bold() at the end of stuff.stuffIWantBolded, but that apparently doesn't work, because then the string renders as <b>bold text</b> the string from backend (assuming that's what the string from backend says), with the HTML tags written out explicitly instead of rendering actual bold text. Is there something I'm missing? I don't think one can just make the string bold in the JSON...perhaps I need to use a regex? Any help would be greatly appreciated.
How about this:
return (
<>
<span style={{fontWeight: "bold"}}>{stuff.stuffIWantBolded}</span>
<span>{theStringFromBackend}</span>
</>
);
The <> and </> effectively allow you to return multiple items from one render function.
I would do it by using composition (I prefer the strong tag to b to make text bold):
render() {
// props for this component in which I'm rendering SomeComponent (see below)
const { data } = this.props
const { theStringFromBackend } = data
// a method to get the string that is working for me
const stuff = this.getTheStringFromTheJSON();
return (
<SomeComponent>
<p><strong>{stuff.stuffIWantBolded}</strong> {theStringFromBackend}</p>
</SomeComponent>
);
};
And in SomeComponent you will find the nested html inside props.children
for more info check here: https://reactjs.org/docs/composition-vs-inheritance.html
It turns out you CAN pass in a prop within a self-closing tag component the way I want to. Not sure if it's conventionally sound/overly bloated but it looks like this:
render() {
// props for this component in which I'm rendering SomeComponent (see below)
const { data } = this.props
const { theStringFromBackend } = data
// a method to get the string that is working for me
const stuff = this.getTheStringFromTheJSON();
const theBoldedText = `${stuff.stuffIWantBolded}`;
return (
<SomeComponent someProp={<span><b>{theBoldedText}</b> <span>{theStringFromBackend}</span></span>} />
);
};
I am trying to use the sweetalert-react package (https://github.com/chentsulin/sweetalert-react) as a modal for my app.
Right now I got it to work, but I want to be able to display a const that has my component:
const clusterDoors = lock.doors.map(clusterDoor => {
return (
<div key={clusterDoor.port_id}>
<ClusterListItem
clusterDoor={clusterDoor}
customer={
clusterDoor.allocation.customer ? (
keyedCustomers[clusterDoor.allocation.customer]
) : (
false
)
}
.....
So I read their docs and found out that I can achieve that with ReactDOMServer.renderToStaticMarkup. So I simple need to:
text={renderToStaticMarkup(<MyComponent />)}
But the problem is that my component is inside of a constant, so if I try to do:
text={renderToStaticMarkup({clusterDoors})}
I will get the error:
You must pass a valid ReactElement.
I wonder if there's some workaround to this?
I did some research and tried also tried to do:
const clusterDoors = React.createClass({
render: function() {
lock.doors.map(clusterDoor => {
return (
<div key={clusterDoor.port_id}>
<ClusterListItem
clusterDoor={clusterDoor}
customer={
clusterDoor.allocation.customer ? (
keyedCustomers[clusterDoor.allocation.customer]
) : (
false
)
}
delivery={
clusterDoor.allocation.delivery ? (
keyedDeliveries[clusterDoor.allocation.delivery]
) : (
false
)
}
/>
</div>
)
})
}
})
But that didn't do the trick.
If I pass it a valid react component (ClusterListItem) my app won't break, but nothing will show because of the array clusterDoor wont exist.
I hope I explained my situation well. Thanks for reading.
The problem with your code is that you are passing an array of elements because clusterDoors is an array and renderToStaticMarkup is expecting a single element. Therefore you are getting this error.
Solution: Just wrap your array in a div tag so it becomes a single node element like this
text={renderToStaticMarkup(<div>{clusterDoors}</div>)}