New to RJS, Trying to access my variable "txt" outside the Data.map callback where it was originally declared, how would I be able to do this and have full access to the variable?
CodeSandbox
import Data from "./names.json";
export default function App() {
//want to access txt in here <==============
// console.log(txt) and stuff after accessing it here
return (
<div className="App">
{Data.map((post) => {
var txt = post.Name;
return <h1>{post.Name}</h1>;
})}
</div>
);
}
Thanks
Many ways, but the useState hook is pretty solid especially if you want to take advantage of React's speed.
import Data from "./names.json";
export default function App() {
const [ txt, setTxt ] = useState(""); // sets it to an empty string to begin with
useEffect(() => {
console.log(txt); // every time the 'txt' variable changes, log it
}, [ txt]); // << React calls this a dependency and will only run this function when this value changes.
console.log(txt); // also accessible here
return (
<div className="App">
{Data.map((post) => {
setTxt(post.Name); // This updates the 'txt' variable from earlier ^^
return <h1>{post.Name}</h1>;
})}
</div>
);
}
If all that is too long-winded, just keep your txt variable outside of the function component, and React won't reset it every loop. You'll still be able to access its value anywhere in the file. Example:
import Data from "./names.json";
let txt = "";
export default function App() {
return (
<div className="App">
{Data.map((post) => {
txt = post.Name;
return <h1>{post.Name}</h1>;
})}
</div>
);
}
afaik you can't because text is scoped to the map function and you can't access it outside of it. You can try putting it in a state or make a function and make it an argument of that function from inside the map function.
import Data from "./names.json";
import {useState} from 'react'
export default function App() {
//want to access txt in here <==============
// console.log(txt) and stuff after accessing it here
const [text,setText] = useState()
function getText(text) {
console.log(text) // this function gets called in every instance of the map loop
//you can run your logic here to find specific information and then set it to the state like in this example
if (text === "myText") {
setText(text)
}
}
return (
<div className="App">
{Data.map((post) => {
var txt = post.Name;
getText(txt) // will run and recieve the var txt every instance
return <h1>{post.Name}</h1>;
})}
</div>
);
}
Related
I am totally blank on how to use a function that is inside a component and needs to be used in another component.
Here is a simple program:
Test.js
export default function Test(){
const testFunc = () => {
console.log("it is working")
}
return(
<div>
Hi
</div>
)
}
Test2.js
export default function Test2(){
return(
<button onClick={}> // Here I want to use testFunc() from Test file
Click
</button>
)
}
Could someone please explain how can it be achieved to access the function in Test2 file.
Thanks in advance!!
You will want to pass the function as a prop to the child component. You can't or I should say shouldn't pass a prop to a parent, you can do this but is not a react way and never recommended. What you would do in this case is but the logic in the parent because both siblings are needing access to it.
const App = () => {
const clickHandler = () => {
alert("Click event")
}
return (
<div className="App">
<ChildOne clickHandler={clickHandler}/>
<ChildTwo clickHandler={clickHandler}/>
</div>
)
}
}
You can either pass it down from a parent component, shown below, or you can use a custom hook
Parent Component:
import Child from './Child.js'
export default function Parent() {
const functionToBePassed = () => { ... }
return (
<Child func={functionToBePassed}>
)
}
Or you can do it via a custom hook
Two files, first one is the hook
export default function useFunc() {
const functionToBeShared = () => {...}
return { functionToBeShared }
}
//this is any component that wants to use the hook
import useFunc from ./useFunc;
export default function ComponentThatUsesHook() {
const {functionToBeShared} = useFunc();
}
Welcome to the React community.
To use a function that is inside a component and needs to be used in another component.
You need a common parent, that handles the function.
Let's say you have the following structure.
export const ParentComponent = () => {
return <>
<Test1 />
<Test2 />
<>
}
If you want some function in Test1 to affect Test2, then you do what in react is called lifting state up https://reactjs.org/docs/lifting-state-up.html
ParentComponent
export const ParentComponent = () => {
const [value, setValue] = useState('')
return <>
<Test1 setValue={setValue} />
<Test2 value={value} />
<>
}
Test1
export const Test1 = (props) => {
return <>
<input onChange={(e) => props.setValue(e.target.vale} />
<>
}
Test2
export const Test2 = (props) => {
return <p>{props.value}</p>
}
When a component renders another component, it is called the parent of the rendered child. Imagine React as a tree data structure where the App.tsx/jsx will be the tree's root.
Inspecting the code above, we can see that we have a function held in the parent. This is the function you would probably consider putting in Test1. However, if you need to use it in another component, that is not a child of the current element. You will need to find the nearest common parent and pass the functionality down like in the example above.
I hope it makes sense. If not, I recommend glancing at the Main Concepts part of the official React documentation. https://reactjs.org/docs/getting-started.html
As Konrad said in the comments, this can't be possible since these 2 components lack no relationship (Neither Components are rendering or calling each other within)
Something you could do is Render the Test2.js component within Test.js and add a callback like so:
Test.js
import Test2 from '...';
export default function Test(){
const testFunc = () => {
console.log("it is working")
}
return(
<div>
Hi
<Test2 callbackProp={testFunc} />
</div>
)
}
Test2.js
export default function Test2({callbackProp}){
return(
<button onClick={() => {callbackProp();} }> // Here I want to use testFunc() from Test file
Click
</button>
)
}
Now whenever Test.js is rendered, it will also render Test2 (Since Test is rendering a Test2 Component) but whenever you click the button within Test2, it will execute the callback which is a function passed from Test
Nonetheless though, it's impossible to call any functions from another Component without passing down a prop like this (for future reference)
Solution
Usually, context is used to share the same state between many components that aren't in parent-children relations.
codesandbox
Creating context
First, create a context:
const MyContext = createContext();
And context provider:
const MyContextProvider = ({ children }) => {
const [myState, setMyState] = useState(0);
return (
<MyContext.Provider value={{ myState, setMyState }}>
{children}
</MyContext.Provider>
);
};
And context hook (for convenience):
const useMyContext = () => useContext(MyContext);
Using context
Remember to use the provider in the common ancestor of the components:
function App() {
return (
<MyContextProvider>
<Component1 />
<Component2 />
</MyContextProvider>
);
}
Create your components:
function Component1() {
// as you can see, you can access the function here
const { setMyState } = useMyContext();
return (
<button onClick={() => setMyState((state) => state + 1)}>click me</button>
);
}
function Component2() {
// and the value here
const { myState } = useMyContext();
return myState;
}
I have written the following code to pass values to infobox but i am getting an error
uncaught TypeError: Cannot read properties of undefined (reading '0').please tell where i am wrong.
import React,{useState} from 'react'
function App() {
const [specificState, setSpecificState] = useState({});
const jsondata1 = await fetch('https://covid-19-fastest-update.p.rapidapi.com/summary');
const myData1 = await jsondata1.json();
const indData = myData1.Countries[77];
const getdata=()=>{
const temp =[];
temp ['Confirmed']= [indData.NewConfirmed, indData.TotalConfirmed]
temp['Recovered'] = [indData.NewConfirmed, indData.NewConfirmed - indData.TotalDeaths]
temp ['Deaths']= [indData.TotalDeaths, indData.NewDeaths]
setSpecificState(temp);
}
useEffect(() => {
getdata();
}, [])
return (
<div> <InfoBox title="Coranavirus cases" cases={ specificState.Confirmed[0] }
total={ specificState.Confirmed[1] } /> </div>
)
}
export default App
You need to make your fetch requests inside of useEffect.
update your get data function like this;
const getdata=()=>{
const jsondata1 = await fetch('https://covid-19-fastest-update.p.rapidapi.com/summary');
const myData1 = await jsondata1.json();
const indData = myData1.Countries[77];
const temp =[];
temp ['Confirmed']= [indData.NewConfirmed, indData.TotalConfirmed]
temp['Recovered'] = [indData.NewConfirmed, indData.NewConfirmed - indData.TotalDeaths]
temp ['Deaths']= [indData.TotalDeaths, indData.NewDeaths]
setSpecificState(temp);
}
remove the fetch and other operations from the body of the component.
then you need to wait for state to be fetched, you need to render your component conditionally.
return (
<div> {spesificState.Confirmed && <InfoBox title="Coranavirus cases" cases={ specificState.Confirmed[0] }
total={ specificState.Confirmed[1] } /> } </div>
)
}
maybe something like this.
When state is initially loaded, specificState is an empty object so no Confirmed property is found (undefined)
So at first render, this will throw this exception.
When useEffect runs and retrieves results, then this property is loaded and then you can use your InfoBox class.
So instead use
return (
{specificState.Confirmed ? <div> <InfoBox title="Coranavirus cases" cases={ specificState.Confirmed[0] }
total={ specificState.Confirmed[1] } /> </div> : null }
)
You can create statement using if operator in useEffect hook, because right now your fetched data is not uploaded yet when you try to use indData. Just cover your getdata function in useEffect like this:
useEffect(() => {
if (indData) {
getdata();
}
}, [indData])
Also, you need to add extra values while passing cases and total attributes in InfoBox component, just pass empty array using | []
This is what my code looks like:
Context.js:
const Context = createContext();
export default Context;
ContextProvider.js:
import Context from './Context';
const ContextProvider = () =>
{
....
return(<Context.Provider value={data: 1}>{props.children}</Context.Provider>
}
ParentClass.js:
const ParentClass = () =>
{
...
return(
<div>
...
{boolValue ? (
<ContextProvider>
<ConsumerComponent/>
</ContextProvider>)
</div>)
}
ConsumerComponent.js:
import Context from './Context.js';
const ConsumerComponent = () => {
const contextData = useContext(Context);
...
}
My issue is that ConsumerComponent doesn't seem to be able to access context data; it doesn't render at all when I add the const contextData = useContext(Context); line, and nothing gets logged when I try to print contextData. Where exactly did I go wrong? From my understanding, I followed the necessary steps of creating context + a provider, making sure that the consuming component has a provider as one of its ancestor components, and then accessing the context with useContext().
Considering you want the value prop of the Context Provider to be an object like
{ data : 1 }
you probably forgot the extra curly braces, because the first pair is the JSX syntax to interpret the content as JavaScript instead of a string.
So your value prop on ContextProvider.js file probably should look like this:
<Context.Provider value={{data: 1}}>{props.children}</Context.Provider>
I am new to React and GraphQL. Trying to update React state with GraphQL subscription feed but it generates the update depth error.
Here is the simplified code:
import { Subscription } from 'react-apollo';
...
function Comp() {
const [test, setTest] = useState([]);
const Sub = function() {
return (
<Subscription subscription={someStatement}>
{
result => setTest(...test, result.data);
return null;
}
</Subscription>
);
};
const Draw = function() {
return (
<div> { test.map(x => <p>{x}</p>) } </div>
);
};
return (
<div>
<Sub />
<Draw />
<div/>
);
};
export default Comp;
Regular query works fine in the app and the Subscription tag returns usable results, so I believe the problem is on the React side.
I assume the displayed code contains the source of error because commenting out the function "Sub" stops the depth error.
You see what happens is when this part renders
<Subscription subscription={someStatement}>
{
result => setTest(...test, result.data);
return null;
}
</Subscription>
setTest() is called and state is set which causes a re-render, that re-render cause the above block to re-render and setTest() is called again and the loop goes on.
Try to fetch and setTest() in your useEffect() Hook so it does not gets stuck in that re-render loop.
useEffect like
useEffect(() => {
//idk where result obj are you getting from but it is supposed to be
//like this
setTest(...test, result.data);
}, [test] )
Component Like
<Subscription subscription={someStatement} />
I have this file that I'm keeping a INITIAL_VALUE for a form field, that I'm building.
INITIAL_VALUE.js
const INITIAL_VALUE = [];
export default INITIAL_VALUE;
And the problem is that INITIAL_VALUE is an array. A non-primitive, that is handled by reference.
Component1.js
import INITIAL_VALUE from "./INITIAL_VALUE";
import React, { useState } from "react";
function Component1(props) {
const [myState, setMyState] = useState(INITIAL_VALUE);
const [boolean, setBoolean] = useState(false);
function handleClick() {
setMyState(prevState => {
prevState.push(1);
return prevState;
});
setBoolean(prevState => !prevState);
props.forceUpdateApp();
}
return (
<React.Fragment>
<div>This is my state: {JSON.stringify(myState)}</div>
<button onClick={handleClick}>Modify State Comp1</button>
</React.Fragment>
);
}
export default Component1;
Component2.js
The same as Component1, but it's named Component2 and it has its own file.
App.js
function App() {
const [boolean, setBoolean] = useState(false);
function forceUpdateApp() {
setBoolean(prevState => !prevState);
}
return (
<React.Fragment>
<Component1 forceUpdateApp={forceUpdateApp} />
<Component1 forceUpdateApp={forceUpdateApp} />
<Component2 forceUpdateApp={forceUpdateApp} />
</React.Fragment>
);
}
CodeSandbox
PROBLEM
Component1.js and Component2.js both import the INITIAL_VALUE file. And I was under the impression that, each one of these imports would get a brand new instance of the INITIAL_VALUE object. But that is not the case as we can see from the GIF below:
QUESTION
Is there a way to keep an array as a initial value living declared and imported from another file and always get a new reference to it on each import? Is there another pattern I can use to solve this? Or should I stick with only primitive values and make it null instead of [] and intialize it in the consumer file?
Is there a way to keep an array as a initial value living declared and imported from another file and always get a new reference to it on each import?
No, that's not possible. The top-most level code of a module will run once, at most. Here, the top level of INITIAL_VALUE.js defines one array and exports it, so everything that imports it will have a reference to that same array.
Easiest tweak would be to export a function which creates the array instead:
// makeInitialValue.js
export default () => {
const INITIAL_VALUE = [];
// the created array / object can be much more complicated, if you wish
return INITIAL_VALUE;
};
and then
import makeInitialValue from "./makeInitialValue";
function Component1(props) {
const INITIAL_VALUE = makeInitialValue();
const [myState, setMyState] = useState(INITIAL_VALUE);
In the simplified case that you just need an empty array, it would be easier just to define it when you pass it to useState.
All that said, it would be much better to fix your code so that it does not mutate the existing state. Change
setMyState(prevState => {
prevState.push(1);
return prevState;
});
to
setMyState(prevState => {
return [...prevState, 1];
});
That way, even if all components and component instances start out with the same array, it won't cause problems, because the array will never be mutated.