Alex Aymkin
Alex Aymkin

Reputation: 518

Change in the order of Hooks called by <Component>

I am getting the warning about React has detected a change in the order of Hooks called by Checkout

I did read https://reactjs.org/docs/hooks-rules.html and looks like my code meets the requirements

The warning: screenshot from debbuger

Fragment of file with hooks:

  if (!token) {
    navigate.push(routes.login)
    return <Text>Redirect</Text>
  }

  const maximumDate = moment().add(1, 'year')
  const minimumDate = moment()
  const formattedToday = minimumDate.format('YYYY-MM-DD')

  const [paymentMethod, setPaymentMethod] = useState(paymentOptions[0].key)
  const [totalAmount, setTotalAmount] = useState(totalCartAmount)
  const [deliveryTime, setDeliveryTime] = useState(0)
  const [date, setDate] = useState(minimumDate)
  const [show, setShow] = useState(false)

  const validationSchema = yup.object().shape({
    couponCode: yup.string(),
    comments: yup.string(),
  })

  useEffect(() => {
    if (deliverySlots.length > 0) {
      setDeliveryTime(deliverySlots[0].id)
    }
  }, [deliverySlots])

  useEffect(() => {
    getDeliveryTimeSlots(country.id, formattedToday, error => {
      if (error) {
        console.log(error)
      }
    })
  }, [])

Full component code: https://codesandbox.io/s/modest-lewin-4x9ss

Upvotes: 1

Views: 9070

Answers (4)

Mohammad Tbeishat
Mohammad Tbeishat

Reputation: 1066

On my situation I had a simple line on the top of my component like:

if (isLoading) return <dev>Loading..</dev>

And the error has disappeared after I moved this line to the end where returns should normally be, after declaring constants and variables..

Upvotes: 1

Shamxeed
Shamxeed

Reputation: 422

I got the same error on React Native though...

After paying close attention to the error message, I realized that: I'm deleting data in my redux state from a child screen which a parent screen depends on.

e.g: ProfileScreen => SettingScreen

in the above example, SettingScreen is the child screen of ProfileScreen. So when you delete data in your redux state that ProfileScreen is referencing, from your SettingScreen, you'll get the same error because ProfileScreen useContext is undefined from redux.

How I solved:

from:

const someTask = () => {
   ....
   dispatch(deleteData(dataId))
   navigation.navigate('HomeScreen')
}

To:

const someTask = () => {
   ....
   navigation.navigate('HomeScreen')
   dispatch(deleteData(dataId)) //deleting the Data should be the last thing to do to safely navigate away..
}

Upvotes: 3

Gennady Dogaev
Gennady Dogaev

Reputation: 5991

If you have hooks in your component, you must ensure that all hooks called on every render and in the same order. This code should be placed after all hooks (because of return):

if (!token) {
  navigate.push(routes.login)
  return <Text>Redirect</Text>
}

Upvotes: 3

Johan
Johan

Reputation: 8276

As you already listed the rules of hooks, you must have missed the important section of `Only Call Hooks at the Top Level"

It states:

Don’t call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function

Simply put, either move your hooks above the condition, or extract the condition to the parent function/component.

Upvotes: 1

Related Questions