So I'm trying to use a react Timer in one of my class components. I figured out how to connect it, but now I need to save the time into the parent's state. How can I go upon doing that? Since the time is being measured on the child component. So essentially I need to save the time measured from the child component to the parent's state.
CodePudding user response:
The phrase that comes to mind is Lifting State up. React has a 'top-down' data flow. So your state needs to be initialised in the parent component and passed down to the child components that need it. e.g. (pseudocode, may not work)
function Parent() {
const [text, setText] = useState('hello world')
return (
<>
<Child text={text} />
<OtherChild text={text} setText={setText} />
</>
)
}
function Child({ text }) {
return <p>{text}</p>
}
function OtherChild({ text, setText }) {
return (
<input
onChange={e => setText(e.target.value)}
value={text} />
)
}
CodePudding user response:
You'll need to pass a function that updates the parent's state to the child component via props:
In this particular example, both the child and the parent props have a state hook that keeps track of time - the parent's updateParentTime
function get's called any time the child's time
value changes.
NOTE: it's probably not necessary to keep state in both places...I was just showing an example. If the parent needs has state for time
, you could also just pass that down to the child component
const Parent = (props) => {
const [time, setTime] = useState(0);
const updateParentTime = (t) => {
setTime(t);
}
return (
<Child updateParentTime={updateParentTime}/>
)
}
const Child = (props) => {
const {updateParentTime} = props;
const [time, setTime] = useState(0);
useEffect(() => {
updateParentTime(time)
}, [time]);
return (
<div>
{/* something goes here */}
</div>
)
}
CodePudding user response:
The following defines two React components: Parent
and Child
.
Parent
declares a piece of state named time
and a mutator method for that state named setTime
.
The current value of time
is passed to Child
via the prop named time
.
setTime
is passed to Child
via the prop named notify
.
Child
configures a timer that invokes notify
(ie setTime
) once a second.
Invoking notify
tells React that a state change has occurred and triggers a re-rendering of both components, causing the time to be rendered by each component, once every second.
pre { border: 1px solid black; padding: 10px; }
<script src="https://unpkg.com/@babel/standalone@7/babel.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<script type="text/babel">
const { useState, useEffect } = React
const Parent = () => {
const [ time, setTime ] = React.useState('--- --- -- ----')
return <pre>
Parent: { time }
<Child notify={setTime} time={ time }/>
</pre>
}
const Child = ({ notify, time }) => {
useEffect(()=>{
const id = setInterval(() => notify(Date()), 1000)
return () => clearInterval(id)
})
return <pre>Child: {time}</pre>
}
ReactDOM.render(<Parent/>, document.querySelector('main'))
</script>
<main></main>