I have some variables that are set within a function in one component of my react application that I need to reuse in other components.
I set the variables in component 1 like so (this is a much simplified version but captures the structure)
export default function Example() {
const [market, setMarket] = useState('');
return (
<button onClick={setMarket('1')}>Click 1</button>
<button onClick={setMarket('2')}>Click 2</button>
<button onClick={setMarket('3')}>Click 3</button> )}
How can I export the 'market' variable specifically, so that I can import it into another component (in a separate jsx file) and render as necessary. I know that I can just import the whole component, or set a variable outside of this function in component 1 and export it but I do not know how I would then conditionally set it based on which button is clicked.
Thank you
Hey #Milo there are different ways to use state value in another component.
First is props-
Create a component that passes values like-
const passValue = () => {
const [ value, setValue ] = useState("")
return (
)
}
While in the second component we get the value like-
const SecondComponent = ({value})=>{
return(
<div>
{value}
</div>
)
}
While Second method is to pass value using state and get it by useLocation in another component-
First Component like-
const FirstComponent = () =>{
return(
<div>
<Link to="/secondpage" state={{value:yourValue/state}}>Click Here</Link>
</div>
)
}
Second Component Like-
const Second Component = () => {
const {state} = useLocation()
return(
<div>{state}</div>
)
}
Hope these solution helps to solve your problem. If you still facing issue lemme know, i will help you.
Thanks
Related
In react I can do something like:
App.jsx
const App = () => {
const [state, setState] = useState("old value")
return (
<>
<ChildComponent setState={setState} />
</>
)
}
ChildComponent.jsx
const ChildComponent = ({ setState }) => {
const changeState = () => setState("new value")
return (
<div>
<button onClick={changeState}>Click</button>
</div>
)
}
Then the parent state will be updated.
I don't know how to do the same in Svelte...
I have this:
index.svelte
<script>
import { ChildComponent } from "#components"
let state = "old value"
</script>
<main>
<ChildComponent {state} />
</main>
ChildComponent.svelte
<script>
export let state
const changeState = () => {
// I need to do something like:
state = "new value"
}
</script>
<div>
<button on:click={changeState}>Click</button>
</div>
And see the new value reflected in the parent.
I wanna to do it without use stores... I don't know if it's possible.
Maybe store is the only way to proceed.
I'm ears
There are two ways of doing this in Svelte:
With two-way binding
This will create a sort of connection between parent and child, where updating one will automatically update the other.
<!-- Parent.svelte -->
<script>
import Child from './Child.svelte';
let state = "initial";
</script>
<Child bind:state />
<!-- Child.svelte -->
<script>
export let state;
function changeState() {
state = "new value";
</script>
<button on:click={changeState}>Click</button>
Using events
Just like props go down, events are used to pass informaton up. This can be used if you don't want a strict equivalence between the two states and is a touch more versatile (but also more verbose).
<!-- Parent.svelte -->
<script>
import Child from './Child.svelte';
let state = "initial"
function handleChange(ev) {
state = ev.detail.state
}
</script>
<Child {state} on:change={handleChange} />
<!-- Child.svelte -->
<script>
import { createEventDispatcher } from 'svelte';
export let state
const dispatch = createEventDispatcher()
function changeState() {
// first argument is the event name
// second is an object placed in ev.detail
dispatch('change', { state: "new value" });
}
</script>
<button on:click={changeState}>Click</button>
Which of these to use is up to you and likely depends on the situation, but both benefit that they do not actively rely on what is happening outside the component. If nobody used bind the component doesn't care, it still works. If nobody is listening to this event, again the component doesn't care and keeps on working. Contrast this to the situation where no function is passed, or the function has the wrong signature, suddenly your component is dependent on something that it cannot control which is not a good pattern.
Why this does not work ?
import React from 'react';
function Room() {
let check = null;
const ibegyouwork = () => {
check = <button>New button</button>;
}
return (
<div>
<button onClick={ibegyouwork}>Display my button now !!!!</button>
{check}
</div>
);
}
export default Room;
And this works fine ?
import React from 'react';
function Room() {
let check = null;
return (
<div>
<button>No need for this button because in this case the second button is auto-displayed</button>
{check}
</div>
);
}
export default Room;
Basically I try to render a component based on a condition. This is a very basic example. But what I have is very similar. If you wonder why I need to update the check variable inside that function is because in my example I have a callback function there where I receive an ID which I need to use in that new component.
The example that I provided to you is basically a button and I want to show another one when I press on this one.
I am new to React and despite I searched in the past 2 hours for a solution I couldn't find anything to address this issue.
Any tips are highly appreciated !
Your component has no idea that something has changed when you click the button. You will need to use state in order to inform React that a rerender is required:
import React, {useState} from 'react'
function Room() {
const [check, setCheck] = useState(null);
const ibegyouwork = () => {
setCheck(<button>New button</button>);
}
return (
<div>
<button onClick={ibegyouwork}>Display my button now !!!!</button>
{check}
</div>
);
}
export default Room;
When you call setCheck, React basically decides that a rerender is required, and updates the view.
The latter is working because there are no changes to the check value that should appear on the DOM.
If check changes should impact and trigger the React render function, you would want to use a state for show/hide condition.
import React from 'react';
const Check = () => <button>New button</button>;
function Room() {
const [show, setShow] = React.useState(false);
const ibegyouwork = () => {
setShow(true);
}
return (
<div>
<button onClick={ibegyouwork}>Display my button now !!!!</button>
{show && <Check />}
</div>
);
}
export default Room;
Lets say for instance that I have three components in React, an App (the parent component), a button component and a component that is meant to display something, can be anything doesn't really matter. Lets say in the button component is activated, how would I pass the information (ie that the event actually happened) to the App parent component back down to the other child component to let it know a specific event happened to display some message?
this is how I would go about dong this using hooks :
const Parent=(props)=>{
[eventHappend,setEventHappend]=useState(false)
return (
<div>
<Child1 setEventHappend={setEventHappend} />
<Child2 eventHappend={eventHappend} />
</div>
)
}
const Child =({setEventHappend})=>{
return (
<div>
<button onClick={e=>setEventHappend(true)} > click me 1 </button>
</div>
)
}
const Child2 =({eventHappend})=>{
return (
<div>
<button onClick={e=>{/* some code*/ }} > {eventHappend?'event happend':'event didnt happen yet '} </button>
</div>
)
}
There are various ways you can achieve this pass state as props to the child elements (must know before other methods), context or use redux which has a store.
Generally speaking. React has one way data flow, uni directional. As in the parent will hold the state and will be passed to child elements.
Here App holds the state buttonClick which has the information about the event.
const App = () => {
const [ buttonClick, setButtonClick] = React.useState(false);
const messageToBeDispalyed = "The button has been clicked"
return (
<div>
<CustomButton setEventHappened={setButtonClick} />
<DisplayText value = {buttonClick ? messageToBeDispalyed : ""} />
</div>
)
}
const CustomButton = (props) =>{
return <button onClick={(e)=>props.setEventHappened(true)} > Click Me </button>
}
const DisplayText = (props) => {
return <h1> {props.value} </h1>
}
Similar answers to the others, but you would pass down a method to the child from the parent to update the state. But be aware that by doing this will cause a rerender for all of the parent's children.
const Parent = () => {
const [state, setState] = React.useState(false);
const handleClick = value => {
setState(value);
};
return (
<Child state={state} handleClick={handleClick} />
<OtherChild isTrue={state} /> // this component needs data changed by <Child />
)
};
const Child = props => {
const {state, handleClick} = props;
return (
<button onClick={() => handleClick(!state)} >click me</button>
);
};
This way the parent alone handles the state change and provides that method to the child.
as #Loveen Dyall and #Shruti B mentioned you can use RXJS for a more modular approach ,While RxJS is typically thought of as being used with Angular projects, it's a completely separate library that can be used with other JavaScript frameworks like React and Vue.
When using RxJS with React, the way to communicate between components is to use an Observable and a Subject (which is a type of observable), I won't go too much into the details about how observables work here since it's a big subject, but in a nutshell there are two methods that we're interested in: Observable.subscribe() and Subject.next().
learn more about RXJS and Observables : https://blog.logrocket.com/understanding-rxjs-observables/
Observable.subscribe()
The observable subscribe method is used by React components to subscribe to messages that are sent to an observable.
Subject.next()
The subject next method is used to send messages to an observable which are then sent to all React components that are subscribers (a.k.a. observers) of that observable.
here is how you implement it in this use case :
this is called a service and you would put this file in a services folder
import { Subject } from 'rxjs';
const subject = new Subject();
//here where sending { event: eventTitle } , that way you can listen to diffrent events , for example 'INCREMENTED' you could even send values
export const eventsService= {
sendEvent: eventTitle => subject.next({ title: eventTitle }),
getEventNotification: () => subject.asObservable()
};
in your Child 1 component you would subscribe to the observable in useEffect or compoentDidMount if your using class component:
import { eventsService} from '../services';
const Child1 =()=>{
const [child2EventFired,setChild2EventFired]=useState(false)
useEffect(()=>{
let subscription = eventsService.getEventNotification().subscribe(eventTitle =>
{
if (eventTitle=="CHILD2_BUTTON_CLICK" ) {
setChild2EventFired(true)
}else{
setChild2EventFired(false)
}
});
return ()=>{
subscription.unsubscribe();
}
},[])
return <div>
<button> {child2EventFired? 'child2 button event fired':'event not fired yet'} </button>
</div>
}
in your Child 2 component
import { eventsService} from '../services';
const Child2 =()=>{
Child2Click=(e)=>{
//some code,
//then send messages to the observable observable
eventsService.sendEvent('CHILD2_BUTTON_CLICK');
}
return <div>
<button onClick={Child2Click} >click me</button>
</div>
}
This question already has answers here:
Push method in React Hooks (useState)?
(8 answers)
Closed 2 years ago.
Im working on a todo aplication in react using useState, im trying to save user input and then after they click submit push it to the listArray, later to display it...
I think im doing something wrong in the updateArray function, but I can seem to understand what.
import React, { useState } from "react";
function App() {
const listArray = [""];
const [list, updateList] = useState("");
function handleChange(event) {
const { name, value } = event.target;
updateList(value);
//console.log(list);
}
function updateArray() {
console.log(list);
listArray.push(list);
console.log(listArray);
}
return (
<div className="container">
<div className="heading">
<h1>To-Do List</h1>
</div>
<div className="form">
<input name="entry" onChange={handleChange} type="text" />
<button>
<span onSubmit={updateArray}>Add</span>
</button>
</div>
<div>
<ul>
<li>{listArray[0]}</li>
</ul>
</div>
</div>
);
}
export default App;
There are several issues with your current code and I will briefly describe and provide a solution to fix them.
Your functions are working fine and as expected, but in a React application there are few ways to re-render a page or component and changing the local variable is not one of them. So you need to use a local state instead of local listArray variable. Since there is one state already you should either define another state or make your current state an object and put your component related states into it in one place I will go with the second approach, because it's more elegant and cleaner one.
const [state, setState] = useState({ list: [], input: "" });
After you define your state, you need to change them properly without effecting unnecessary ones. You just need to send the previous state, save it in the new one and only change the related state in each function. So with ES6 syntax, updating input state will look like this:
setState((prev) => ({ ...prev, input: value })); // immediate return "({})" of an object with iterating through the previous values "...prev" and updating input "input: value"
NOTE: You can read more about spread operator (...) here.
So your handle and updateArray function will look like this:
function handleChange(event) {
const { value } = event.target;
setState((prev) => ({ ...prev, input: value }));
}
function updateArray() {
setState((prev) => ({ ...prev, list: [...state.list, state.input] }));
}
onSubmit event will only work on forms or submit buttons so you need to change it to onClick. Also, to make the whole button catch the onclick action you need to set it on the button itself, instead of span element.
<button onClick={updateArray}> <!-- It's better to assign onclick action to an element with a function or arrow function to prevent it from running in the first render "(event) => updateArray(event)" -->
<span>Add</span>
</button>
And finally you need to map through the updated array of todo items in your JSX.
<ul>
{state.list.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
Working Demo:
Save the current value into the state, and keep the list as well into the state so that it isn't cleared each render cycle.
import React, { useState } from "react";
function App() {
const [list, updateList] = useState([]);
const [currentValue, setCurrentValue] = useState()
function handleChange(event) {
setCurrentValue(event.target.value)
}
function handleClick() {
updateList([...list, currentValue])
}
return (
<div className="container">
<div className="heading">
<h1>To-Do List</h1>
</div>
<div className="form">
<input name="entry" onChange={handleChange} type="text" />
<button type="button" onClick={handleClick}>
<span>Add</span>
</button>
</div>
<div>
<ul>
{list.map((res) => (
<li key={res}>{res}</li>
))}
</ul>
</div>
</div>
);
}
export default App;
Also, moving the onClick to the button makes more sense semantically (and even for the UX) but it's up to you.
listArray is cleared with every rerender.
You should store your data in state. So
const [listArray, setListArray] = useState([])
And updateArray should look like:
function updateArray() {
setListArray([...listArray, list]);
}
I guess, in updateArray function should be some logic to clear list
Notice how listArray will always go back to the default value when your app component re-renders (using useState may re-render the component)
I would instead make the string the user inputs a normal const and use useState for the array so the values in the array will be saved across re-renders
The problem is I can't access the value of actuve
or change it? Is this because of the fact that
props are immutable? and if so I should I
create a separate variable for each
EventInLife element/component?
import React from 'react';
import styled,{ css } from 'styled-components';
const EventInLife = (props) => {
/*
adds the active theme to each element(example: if active then the styles
would be barbar and barbaractive if not they would be barbar and barbar)
*/
return (
<div className={`barbar barbar${ props.actuve }`}>
<div className={`square square${ props.actuve }`}></div>
<div className={`heading heading${ props.actuve }`}>{props.heading}</div>
<div className={`date date${ props.actuve }`}>{props.date}</div>
</div>
);
}
function App() {
//Manages which value is active
var lastactive=0;
function bruh(t,n){
document.getElementsByName(t)[lastactive].actuve='';
document.getElementsByName(t)[n].actuve = 'active';
lastactive=n;
}
return(
<EventInLife heading={'Top'} date={'145'} actuve={'active'} onClick={()=>bruh('EventInLife',0)}/>
<EventInLife heading={'trop'} date={'456456'} actuve={''} onClick={()=>bruh('EventInLife',1)}/>
<EventInLife heading={'brop'} date={'45646'} actuve={''} onClick={()=>bruh('EventInLife',2)}/>
<EventInLife heading={'crop'} date={'45646'} actuve={''} onClick={()=>bruh('EventInLife',3)}/>
<EventInLife heading={'wrop'} date={'145645'} actuve={''} onClick={()=>bruh('EventInLife',4)}/>
);
}
/*the css style names (i made them only overide what they needed to)*/
.barbar{}
.barbaractive{}
.squareactive{}
.squareactive{}
.headingactive{}
.headingactive{}
.dateactive{}
.dateactive{}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Yes props are immutable, think of them as arguments being passed to a function. Any values that will change over the lifecycle of a component should be stored in the state of the component, changing the state will cause the component to rerender and thus display the changes on the DOM if the state is utilized correctly. Here is a simple example where each component has a button that triggers the active state to toggle thus triggering a rerender of the component which causes the classes variable to be recomputed therefore changing the class names passed to the div element. I have made the assumption each element is initially false.
import React , {useState} from 'react';
const RandComponent = (props) => {
const [isActive , setIsActive] = useState(false);
const classes = isActive ? 'bar barActive' : 'bar';
return(
<>
<div className={classes}>hi</div>
<button onClick={() => setIsActive(!isActive)}>{isActive ? 'make me inactive' : 'make me active'}</button>
</>
);
}