How to read and modify Object passed to a function in React - javascript

In my main function App(), in useEffect(), I get data (variable named document) using some API with success. My data is the Object with some fields ie title and text.
I pass this data through my functions and I want different functions to use different parts of the document. Later, I render title with success:
import React from 'react'
import "./Title.css"
function Title({document}) {
return (
<div className="title">
{document.title}
</div>
)
}
export default Title;
I want to render 'text' field too, BUT I'd like to split it on newlines
import {useState, useEffect} from 'react'
import React from 'react'
function SourceText({ document }) {
return (
<div>
{document.text.split()}
</div>
)
}
export default SourceText
Which does not work and returns error
TypeError: document.text is undefined
which is weird because when I return just document.text in divs, this object exists.
I tried to add something like this
const [text, setText] = React.useState(null);
React.useEffect(() => {
setText(document.text)
console.log(document.text);
}, []);
But it does not look like it sets document.text value to text variable. What I can't get too is that console in the browser prints the entire object after adding these lines of code.
I am new to React and JavaScript and I really don't get how to modify and use the value passed to a function.
Thanks
EDIT:
I pass the document from App to TabGroup, then to Source and then to SourceText. The last one is here:
import './Source.css';
import SourceText from './SourceText';
import Title from './Title';
function Source({document}) {
return (
<div className="source">
<Title title={document.title}/>
<SourceText document={document} />
</div>
);
}
export default Source;
As I mentioned Title always renders, and using just {document.text} in SourceText does work too

document.text.split() will return an array. str.split() without any parameters returns an array.
You cannot render arrays directly unless you loop through each item. Also, always add checks for null | undefined when trying to render values.
{document?.text && document.text.split().map...}

After #Tom Bombadil post I was able to find the solution
import {useState, useEffect} from 'react'
import React from 'react'
function SourceText({ document }) {
return (
<div>
{document.text && document.text.split('at').map((line) => (line))}
</div>
)
}
export default SourceText
EDIT: didn't take too long to realize my earlier notes were wrong. Seems like it was indeed some async issue - hard to understand for me because the error and result depend on the duration of data fetching.

Related

How to get return data from another file outside of a react component?

I'm trying to get some data returned from a function printed on the screen(In a tag). In other words, I trying to call a function and output the return value to the screen. If you don't get what I mean here is some code:
foo.js:
import random from "./script/stuff/myfantasticfile.js";
export const myFantasticFunction = () =>{
return "Hello world!";
}
App.jsx:
import react from "react";
import Stuff from "./stuff.jsx"
import {myFantasticFunction} from "./foo.js"
function App(){
const myVariable = myFantasticFunction();
return(
<div>
<Stuff/>
<p>{myVariable}</p>
</div>
)
At first glance, the code looks fine, but when you run it, the tag will return 'undefined'. However, the function is returning 'Hello world'.
I have tried to search on google, stackoverflow and some other online coding websites ie: grepper.
If anyone has any idea please share it to me by posting an answer.
Any help will be greatly appreceated
Maybe your function is not loaded when it render the component, I suggest to try that:
<p>{myVariable ? myVariable : '' }</p>
I have solved the bug by adding state to the variable, in other words I am assigning the return value to the state.
Code:
function App(){
const [myVariableState,setMyVariableState] = React.useState();
setMyVariableState(myFantasicFunction());
return(
<div>
<Stuff/>
<p>{myVariableState}</p>
</div>
)
}
Documentation links on how I solved it: https://reactjs.org/docs/hooks-intro.html

I did localstorage.setItem() in one component and i want to do localstorage.getItem() in second component

I have 2 components in ReactJS and I did localstorage.setItem() in one component and I want to do localstorage.getItem() in second component. how should i do it. right now I did both setitem() and getItem() in the same component and passed the value of getItem using props to the second component. But I want to do getItem() in the second component is there any way to do so?
Local Storage is a property of the window interface. You can find more information in the MDN Web Docs. This means that you can access it form any point of your application. Look at the below example to understand this notion.
containerComponent.js
import React from 'react';
import PresentationalComponent from './PresentationalComponent'
const containerComponent = () => {
localStorage.setItem("hello", "hi"); // localStorage only accepts string values
return <PresentationalComponent />
}
export default containerComponent;
PresentationalComponent.js
import React from 'react';
const PresentationalComponent = () => {
return <h1>{`The hello localStorage key has a value of ${localStorage.getItem("hello")}`}</h1>
}
export default PresentationalComponent;
Example:
in Login component, you can set your user object/ or any field:
localStorage.setItem('user', user);
in any another component, you can access it like this:
let userData = localStorage.getItem('user');

Do React Hooks use more memory than Class Components?

My understanding is that Javascript classes store their methods on the Class prototype and therefore all Class instances use the same function definition in memory when invoking those methods. i.e. an single function definition in memory is used by every instance.
For React Hooks, a functional component can update state through the function returned by useState(). e.g.
import React, { useState } from 'react'
function MyComponent(){
const [greeting, setGreeting] = useState("Hello")
return <h1>{greeting}</h1>
}
If my application was to render 100 MyComponents, would the setGreeting() function in all 100 of the components refer to the same setGreeting() function in memory or would there be 100 copies of the same function in memory?
No, for 100 Components it will be 100 setGreeting would be created.SetGreeting is refrence to the function. So there will be 100 refrences.
Please refer below sandbox link: https://codesandbox.io/s/eager-kowalevski-x20nl
Explanation:
In below code I am storing references to setName function, just to verify whether it's same function or not. I am storing in two variables at window level. If the first variable is being stored, I store it in second one so that later I can compare. When I compare these two, they are different. Not a single occurence I get the console message saying "true". So each time a different function is being created.
import React, { useState } from "react";
import "./styles.css";
export default function App() {
const [name, setName] = useState("asutosh");
if (window.s1) {
window.s2 = setName;
} else {
window.s1 = setName;
}
console.log(window.s1 === window.s2);
return (
<div className="App">
<h1>Hello {name}</h1>
</div>
);
}

Dynamic tag name

I'm trying to convert a dynamic tag naming system from React into a more hook like approach, what I'm doing is first I import and export a few components so that I can pull them all at once on a array, like this:
import Component1 from './Component1/Component1'
import Component2 from './Component2/Component2'
export {
Component1,
Component2
}
And then I load them like so:
import { useState, useEffect } from "react";
import * as Components from './../AllComponents/Components'
function importHook() {
const [states, setStates] = useState({
components: [],
currentComponent: 0
})
useEffect(() => {
Object.entries(Components).forEach(component => {
setStates(prevState => ({ components: [...prevState.components, component[1]]}))
})
}, []) // Look's into Components and adds every component to the 'components' array so that I can use that array in the next step.
return states;
}
export default importHook
And after that I proceed to do so:
import React from 'react'
import './MainComponent.scss'
import importHook from '../../importHook'
function MainComponent() {
const { components, currentComponent } = importHook() // Pull and set the values using the hook
const TagName = components[currentComponent] // Created the tag name by targeting the first function, seeing as currentComponent should be 0 at the time
console.log('Tag: ' + TagName) // undefined
return (
<div className="h-100">
<TagName /> // crashes everything
</div>
)
}
export default MainComponent
So I have figured out that the reason that <TagName /> crashes everything is because something runs twice.
If you remove <TagName /> so that you can get the output from console.log and change currentComponent inside the const TagName to 0, you notice that the first time console.log runs is returns undefined, while the second run returns the actual function that is stored inside the array.
So really my question is just, why / what executes twice? I have an idea, I'm assuming its because of the forEach that's adding to the array or something like that, but I'm not completely sure.
What can be done so that we can have all the values ready before returning here? I haven't tried this yet, but I assume I could introduce a if statement that would check and see if the variable is empty and if so, display some kind of loading screen or fidget, but this doesn't seem like the best solution to me, I know there are a lot of ways to do something but not all are good and since I'm really new to all of this its better to read / ask.
About the read part, couldn't find much about solving this or the implementation that I've mentioned, I have tried useEffect, useCallback and other such, not sure if I've been doing it wrong though...

Meteor flow router and getting params of route in a react component

How do I get the params of a route inside a react component
Im using react containers from the react composer package
if this is the whole route
https://learnbuildrepeat-tevinthuku.c9users.io/ReadProjectMeta/wD98XTTtpf8ceyRJT
How do I get only
wD98XTTtpf8ceyRJT
and store its value in a variable inside a react component.
Ive tried to use
FlowRouter.getParam() but it doesnt work. I keep getting undefined
import React from 'react';
export default class ReadProjectMetaLayout extends React.Component {
render() {
var category = FlowRouter.getQueryParam();
console.log(category);
return (
<div>
<h4>Hello World</h4>
</div>
)
}
}
this is the route
FlowRouter.route("/ReadProjectMeta/:_id", {
name: 'project.meta',
action(params) {
mount(ReadProjectMetaLayoutContainer, {
components: (<ReadProjectMeta _id={params._id}/>)
})
}
});
What could be the problem and how do I solve it
To only get the last part of the string:
location.pathname.substr((location.pathname.lastIndexOf('/')+1))
Another pure meteor based thing you can try is from this reference:
FlowRouter.getParam(":_id");
NOTE: Your solution didn't work as you are getting query parameter, query parameters are the parameters that are passed in the url after '?'
i.e. /apps/this-is-my-app?show=yes&color=red
Here in above code color and show are query parameters, while apps is a part of pathname
FlowRouter.getParam(paramName) returns the value of a single URL
parameter
FlowRouter.getQueryParam(paramName) returns the value of a single URL query parameter
Reference:
https://guide.meteor.com/routing.html#accessing-route-info

Categories