Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: useReducer triggers reducer one more time in React 18 Responsive Mode #27666

Closed
silviuaavram opened this issue Nov 8, 2023 · 12 comments
Closed
Labels
Resolution: Stale Automatically closed due to inactivity Status: Unconfirmed A potential issue that we haven't yet confirmed as a bug

Comments

@silviuaavram
Copy link

silviuaavram commented Nov 8, 2023

React version: 18.x.x

Steps To Reproduce

import { useReducer } from "react";

function reducer(state, action) {
  console.log(action.type);
}

const initialState = { name: "Taylor", age: 42 };

export default function Form() {
  const [state, dispatch] = useReducer(reducer, initialState);

  function handleClick() {
    dispatch({ type: "click" });
  }

  function handleMouseMove() {
    dispatch({ type: "move" });
  }

  return (
    <button onClick={handleClick} onMouseMove={handleMouseMove}>
      Click Me in Responsive Mode
    </button>
  );
}
  1. Run the code above. It has a button with handlers for click and mouse move, each triggering a dispatch.
  2. Switch to Responsive mode via dev tools, so you can use Touch event.
  3. Press the button.
  4. You will get in console: click, move, click.
  5. In React <=17, the order would have been: move, click. The first click would not have happened, which actually is what I would expect.

Repro Sandbox: https://codesandbox.io/s/rough-water-w3fh5k?file=/App.js

This extra click seems to happen only when the element also has an onMouseMove handler attached to it, and which in turn triggers a dispatch.

Our problem in downshift comes from the fact that we are adding both click and mouse move handlers to an element, both which can trigger state updates. This issue impacts our users that want to migrate to React18 and expose their Selects / Comboboxes for mobiles.

@Jyotiprakash-Redapple
Copy link

Jyotiprakash-Redapple commented Nov 9, 2023

ISSUE SOLVE @silviuaavram #27666

============================

React 17, one dispatch call per event: https://codesandbox.io/s/unruffled-volhard-x92hq6?file=/index.js
React 18, two dispatch calls: https://codesandbox.io/s/hrzt3k?file=/App.js&utm_medium=sandpack

  1. Both of those version not produce bug in dispatch
  2. Some bug exist on React 17 But it solve in React 18

- What is Strictmode in react
Ans : Strict mode rander two times react app in developement mode
such as :

  1. lagacy context api
  2. reusable state
  3. any unexpected behaiviour in sideeffect
  4. Identifying component life cycle
  5. Other kind of issue
  • Why the issue linked with Strict mode

Ans :

  1. In React.js 17 in Strict mode the app rander only one time . but it not solve this type of problem .
  2. But React.js 18 Solve the Issue and In Strict Mode The app rander two times always in developement
    but not in production . it not effect in production not add any extra UI in Dom tree
  3. You just Go to this link

CODE

=================================


root.render(
  <StrictMode>
    <App />
  </StrictMode>
);

**after this code check devtool console **
Screenshot Capture - 2023-11-09 - 12-59-45

root.render(

<App />

);

**after this code check devtool console **
![Screenshot Capture - 2023-11-09 - 13-00-14](https://github.com/facebook/react/assets/139202727/7c180008-315e-463a-bc4c-cbe09870c7e3)





@Jyotiprakash-Redapple
Copy link

Jyotiprakash-Redapple commented Nov 9, 2023

Your Componenet RELATED ISUUE SOLVE @silviuaavram #27666 #bug

=====================================
Before This Issue Appear I want talk you friend Actually why use useReducer And How to actually this hook use

Why use useReducer

  • in simple word useReducer just like useState , but advantage we can manage multiple state and add complex logic that not good to stay with useState hook

How Use This Hook

  1. this hook pass two argument fast argumet is a function techWord called Reducer fn and second argument is initial state .
  2. it return a array where fast index is the current state and second index is a function by help we can change state value .
Ex: 
const initialState = {};
const [evect, dispatch] = React.useReducer(reducer, initialState);
  1. BUT BUT BUT, as we chnage normal state value we can not change state value directly use of this function, then how change ............

  2. State value change only use reducer function that pass fast argument to the useReducer hook .

  3. yes, we can pass special type of object where must contain a property name TYPE that defined what type of action .

Ex:
dispatch({type: "INCREMENT"})
  1. When we call this function it directly call the reducer function .
  2. In reducer function fast argument is initial state value and second argument what type of action
    what value return in this reducer function that is current initial state value
Ex: 
function reducer(state, action) {
  switch (action.type) {
    case "CLICK": {
      console.log("Click Event Called");
      break;
    }
    case "MOVE": {
      console.log("move Event Called");
      break;
    }
  }
}

FULL CODE

===============================

import React from "react";
const initialState = {};
function reducer(state, action) {
  switch (action.type) {
    case "CLICK": {
      console.log("Click Event Called");
      break;
    }
    case "MOVE": {
      console.log("move Event Called");
      break;
    }
  }
}
function Button() {
  const [evect, dispatch] = React.useReducer(reducer, initialState);

  return (
    <button
      onClick={() => dispatch({ type: "CLICK" })}
      onMouseMove={() => dispatch({ type: "MOVE" })}
    >
      Touch me
    </button>
  );
}
export default function App() {
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <Button />
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

@silviuaavram
Copy link
Author

I must have missed the StrictMode, thanks for pointing in out! Will continue the investigation on my end.

@silviuaavram
Copy link
Author

Re-did the repro. Will update the description and reopen the ticked.

@silviuaavram silviuaavram changed the title Bug: useReducer dispatch different in React 18 for touch event Bug: reducer function called one extra time when dispatched from element with both onClick and onMouseMove Nov 9, 2023
@silviuaavram silviuaavram changed the title Bug: reducer function called one extra time when dispatched from element with both onClick and onMouseMove Bug: useReducer triggers reducer one more time in React 18 Responsive Mode Nov 9, 2023
@silviuaavram silviuaavram reopened this Nov 9, 2023
@Jyotiprakash-Redapple
Copy link

hello @silviuaavram

  • The Reducer function triggers only when call the dispatch function if you not call the dispatch function then not trigger the reducer function.
  • could you give code suggestion on how this type of scenario happen ?

@silviuaavram
Copy link
Author

silviuaavram commented Nov 9, 2023 via email

@Jyotiprakash-Redapple
Copy link

Jyotiprakash-Redapple commented Nov 9, 2023

hello @silviuaavram

Solve : useReducer triggers reducer one more time in React 18 Responsive Mode #27666

  • finally, I found not a solution but it is not a bug it is actually how react works and re-render components and re-print UI

  • React.js Work in Two phase one is rendering and 2nd is comit to dom .

  • The render phase determines what changes need to be made to e.g. the DOM. During this phase, React calls render and then compares the result to the previous render.

  • The commit phase is when React applies any changes. (In the case of React DOM, this is when React inserts, updates, and removes DOM nodes.) React also calls lifecycles like componentDidMount and componentDidUpdate during this phase.
    -In the future, we’d like to add a feature that allows React to add and remove sections of the UI while preserving state. For example, when a user tabs away from a screen and back, React should be able to immediately show the previous screen. To do this, React will support remounting trees using the same component state used before unmounting.

  • This feature will give React better performance out-of-the-box but requires components to be resilient to effects being mounted and destroyed multiple times. Most effects will work without any changes.

  • To help surface these issues, React 18 introduces a new development-only check to Strict Mode. This new check will automatically unmount and remount every component, whenever a component mounts for the first time, restoring the previous state on the second mount.

  • If you not add Strict mode also it render multiple time

  1. Conclusion is this Reducer hook is a state updater it, so sometimes it behaves like this.
  2. Reducer is a pure function it can not affect your UI

A function must pass two tests to be considered “pure”:

  1. Same inputs always return same outputs
  2. No side-effects

@silviuaavram
Copy link
Author

silviuaavram commented Nov 10, 2023

Thanks, @Jyotiprakash-Redapple. It may not be a bug, but it's a different behaviour between 17 and 18 and I need to understand how to address it, as it affects a lot of my users. Updated the code with the type in order to follow the API, but the issue still stands.

@Jyotiprakash-Redapple
Copy link

yes @silviuaavram it is unexpected behavior React.js 18

1 similar comment
@Jyotiprakash-Redapple
Copy link

yes @silviuaavram it is unexpected behavior React.js 18

Copy link

github-actions bot commented Apr 5, 2024

This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!

@github-actions github-actions bot added the Resolution: Stale Automatically closed due to inactivity label Apr 5, 2024
Copy link

Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please create a new issue with up-to-date information. Thank you!

@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Apr 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Resolution: Stale Automatically closed due to inactivity Status: Unconfirmed A potential issue that we haven't yet confirmed as a bug
Projects
None yet
Development

No branches or pull requests

2 participants