facebook / react

The library for web and native user interfaces.
https://react.dev
MIT License
228.61k stars 46.8k forks source link

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

Closed silviuaavram closed 6 months ago

silviuaavram commented 11 months ago

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 commented 11 months ago

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
  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 commented 11 months ago

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

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 commented 11 months ago

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

silviuaavram commented 11 months ago

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

Jyotiprakash-Redapple commented 11 months ago

hello @silviuaavram

silviuaavram commented 11 months ago

Check the description

On Thu, 9 Nov 2023 at 14:29, Jyotiprakash-Redapple @.***> wrote:

hello @silviuaavram https://github.com/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 ?

— Reply to this email directly, view it on GitHub https://github.com/facebook/react/issues/27666#issuecomment-1803938514, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACWAZACCS3EVNZYOYHST6UTYDTSEZAVCNFSM6AAAAAA7CW5NNSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQMBTHEZTQNJRGQ . You are receiving this because you were mentioned.Message ID: @.***>

Jyotiprakash-Redapple commented 11 months ago

hello @silviuaavram

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

  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 commented 11 months ago

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 commented 11 months ago

yes @silviuaavram it is unexpected behavior React.js 18

Jyotiprakash-Redapple commented 11 months ago

yes @silviuaavram it is unexpected behavior React.js 18

github-actions[bot] commented 6 months ago

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[bot] commented 6 months ago

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!