简体   繁体   中英

Update parent state from child component and re-render this child when parent state is update

I'm learning React and I have trying to find resolution to my problem whole day without success. Then decided to make my first question here.

I have child component including React-Datepicker component and separate "Next day" and "Previous day" buttons to change the selected date.

SelectedDate is stored in parent component's state.

I'm trying to update the parent component's state from child and then when state is updated the child component should re-render as this state is passed as props to this same child.

I have managed to change the parent state from child, but child component is not re-rendering and therefore the Datepicker date is not updated.

How should I solve this issue?

Below is my code without import lines.

// App.js

function App() {
  const [selectedDate, setSelectedDate] = useState(new Date())

  const incrementDate = () => {
    let next = selectedDate
    next.setDate(next.getDate() + 1)

    setSelectedDate(next)
  }

  const decrementDate = () => {
    let previous = selectedDate
    previous.setDate(previous.getDate() - 1)

    setSelectedDate(previous)
  }

  return (
    <div className="App">
      <Child 
        selectedDate={selectedDate}
        setSelectedDate={setSelectedDate}
        decrementDate={decrementDate}
        incrementDate={incrementDate} />
    </div>
  )
}

// Child.js

const Child = ({ selectedDate, setSelectedDate, decrementDate, incrementDate }) => {
  return (
    <div className='datepicker-wrapper'>
      <ArrowLeft className='date-arrow' onClick={decrementDate} />
        <DatePicker
          selected={selectedDate}
          onChange={(date) => setSelectedDate(date)}
        />
      <ArrowRight className='date-arrow' onClick={incrementDate} />
    </div>
  )
}

SOLUTION:

Changed in the increment and decrement functions:

let next = new Date(selectedDate.valueOf())
let previous = new Date(selectedDate.valueOf())

When you update state with React, you should always create new state objects, and not only mutate the existing state in place.

  const incrementDate = () => {
    let next = new Date(selectedDate.valueOf())
    next.setDate(next.getDate() + 1)
    setSelectedDate(next)
  }

  const decrementDate = () => {
    let previous = new Date(selectedDate.valueOf())
    previous.setDate(previous.getDate() - 1)
    setSelectedDate(previous)
  }

With React there's various optimizations so that child components only rerender if the state has changed. Many javascript methods such as Date.setDate() will mutate the original object in place. Simply assigning a new name with let previous = selectedDate will not create a new Date object. To create a new Date, you have to use new Date() somewhere in the updater function.

The child component is not rendering because you forgot to add useEffect hook.

 import React,{useEffect} from 'react'

    const Child = ({ selectedDate, setSelectedDate, decrementDate, incrementDate }) => {
     useEffect(()=>{},[selectedDate]);
      return (
        <div className='datepicker-wrapper'>
          <ArrowLeft className='date-arrow' onClick={decrementDate} />
            <DatePicker
              selected={selectedDate}
              onChange={(date) => setSelectedDate(date)}
            />
          <ArrowRight className='date-arrow' onClick={incrementDate} />
        </div>
      )
    }

I had same issue, figured it with an extra function that get's the value from the child and than updated the state with it, and also it is easy to keep track of it with console.log. You can think it as a middleware. try it:

 function App() { const [selectedDate, setSelectedDate] = useState(new Date()) const incrementDate = () => { let next = selectedDate next.setDate(next.getDate() + 1) setSelectedDate(next) } const onDateChane = (date) => { console.log(date) setSelectedDate(date) } const decrementDate = () => { let previous = selectedDate previous.setDate(previous.getDate() - 1) setSelectedDate(previous) } return ( <div className="App"> <Child selectedDate={selectedDate} setSelectedDate={setSelectedDate} decrementDate={decrementDate} incrementDate={incrementDate} /> </div> ) }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM