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

react18 support #5459

Open
bturner1273 opened this issue Nov 2, 2022 · 47 comments
Open

react18 support #5459

bturner1273 opened this issue Nov 2, 2022 · 47 comments
Labels
issue/bug-unconfirmed Issues that describe a bug that hasn't been confirmed by a maintainer yet

Comments

@bturner1273
Copy link

it seems as though the advanced sortable multi-select example is not compatible with react-18. I have a project where it works as intended using react-16 then react-18 it bugs out on drag

@bturner1273 bturner1273 added the issue/bug-unconfirmed Issues that describe a bug that hasn't been confirmed by a maintainer yet label Nov 2, 2022
@lukebennett88
Copy link
Collaborator

Hi @bturner1273,
I've just taken the example from the website and updated to React 18 and it seems to be working (see CodeSandbox).

Are you able to reproduce the issue so we can look into it further?

@ci7lus
Copy link

ci7lus commented Nov 7, 2022

Here's a slightly bigger reproduction. This is simply an app that converts tweets to images, but it isn't working correctly in v18.
However, it is working correctly in the development environment, and this is what happens when I deploy it.
For your reference.

An error occurred in development env:

Warning: Prop `id` did not match. Server: "react-select-6-live-region" Client: "react-select-2-live-region"
    at span
    at http://localhost:3000/build/routes/index-WS3DWJYT.js:2726:28
    at A11yText2
    at LiveRegion2 (http://localhost:3000/build/routes/index-WS3DWJYT.js:6911:29)
    at div
    at http://localhost:3000/build/routes/index-WS3DWJYT.js:2726:28
    at SelectContainer2 (http://localhost:3000/build/routes/index-WS3DWJYT.js:6251:24)
    at Select2 (http://localhost:3000/build/routes/index-WS3DWJYT.js:7804:5)
...

app: https://tweet2image-6b8636qux-anzu.vercel.app/
code: https://github.com/ci7lus/tweet2image/tree/repro/react-select-broken-on-18/app/components/Form

@lukebennett88
Copy link
Collaborator

Hi @ci7lus, it's a bit hard to tell from that example if it's an issue with React 18, or an issue with Remix. I know there is a bit of extra work involved with getting Remix to play nicely with Emotion (which React Select uses for styling).
This PR might be worth taking a look at:
remix-run/examples#35
Hope that helps.

@transitive-bullshit
Copy link

transitive-bullshit commented Nov 11, 2022

I'm getting the same Prop id did not match hydration error using Next.js 13's new appDir with react-select being used in a client component.

If I add a unique instanceId to the Select props, the hydration errors appear to go away (testing in dev right now).

@RaphaelEscrig
Copy link

Hi, I had the same problem with next (13.2.1) and I found a workaround:

const MySelect = ({
	placeholder,
	options,
}: ProjectEditionSelectProps) => {
	const id = Date.now().toString();
	const [isMounted, setIsMounted] = useState(false);

	// Must be deleted once
	// https://github.com/JedWatson/react-select/issues/5459 is fixed.
	useEffect(() => setIsMounted(true), []);

	return isMounted ? (
		<Select
			id={id}
			options={options}
			placeholder={placeholder}
			className="project-edition-select-container"
			classNamePrefix="project-edition-select"
		/>
	) : null;
};

export default MySelect;

My workaround is to display the <Select /> component only in client side. UseEffect() is only triggered client-side so the isMounted is always false on server side.

If you use the experimental version of Next 13, you may use use-client directive.

I'm not particularly happy with this "fix" but it leaves my console in peace.

@kingsleykbc
Copy link

Having the same issue with Next 13

@usmonzo
Copy link

usmonzo commented Jun 2, 2023

Same issue with NextJS 13.4!

@usmonzo
Copy link

usmonzo commented Jun 2, 2023

Fix it, by adding interface :

'use client'

interface ISelectProps {
  data: boolean;
  isDisabled: boolean;
  isFocused: boolean;
  isSelected: boolean;
  id?: number;
}

Then make props look like this:

option: (styles: any, props: ISelectProps) => { ...

Finally put it in Select from react-select...

              <Select 
                 instanceId={useId()}
               {...elseProps}
              />

@PranuPranav97
Copy link

Hi, I had the same problem with next (13.2.1) and I found a workaround:

const MySelect = ({
	placeholder,
	options,
}: ProjectEditionSelectProps) => {
	const id = Date.now().toString();
	const [isMounted, setIsMounted] = useState(false);

	// Must be deleted once
	// https://github.com/JedWatson/react-select/issues/5459 is fixed.
	useEffect(() => setIsMounted(true), []);

	return isMounted ? (
		<Select
			id={id}
			options={options}
			placeholder={placeholder}
			className="project-edition-select-container"
			classNamePrefix="project-edition-select"
		/>
	) : null;
};

export default MySelect;

My workaround is to display the <Select /> component only in client side. UseEffect() is only triggered client-side so the isMounted is always false on server side.

If you use the experimental version of Next 13, you may use use-client directive.

I'm not particularly happy with this "fix" but it leaves my console in peace.

Hey thanks for the solution. This works as the Component renders once in the client side.

@ats1999
Copy link

ats1999 commented Oct 11, 2023

In my case, i solved using

const AsyncSelect = dynamic(() => import("react-select/async"), { ssr: false });

@barrynorman
Copy link

Same issue on my side as well.
Not sure why this happens. IMHO does not make sense.

@gh-johnny
Copy link

Same problem over here...

@michael-ravelhq
Copy link

Same problem

@idilTugba
Copy link

idilTugba commented Nov 20, 2023

Hi, I had the same problem with next (13.2.1) and I found a workaround:

const MySelect = ({
	placeholder,
	options,
}: ProjectEditionSelectProps) => {
	const id = Date.now().toString();
	const [isMounted, setIsMounted] = useState(false);

	// Must be deleted once
	// https://github.com/JedWatson/react-select/issues/5459 is fixed.
	useEffect(() => setIsMounted(true), []);

	return isMounted ? (
		<Select
			id={id}
			options={options}
			placeholder={placeholder}
			className="project-edition-select-container"
			classNamePrefix="project-edition-select"
		/>
	) : null;
};

export default MySelect;

My workaround is to display the <Select /> component only in client side. UseEffect() is only triggered client-side so the isMounted is always false on server side.

If you use the experimental version of Next 13, you may use use-client directive.

I'm not particularly happy with this "fix" but it leaves my console in peace.

Thanks for the solution, it is work for me, too but can u explain to me that what exactly u did here? I'm using "use server" also in the page. why we are check the ssr

@codegeekery
Copy link

codegeekery commented Dec 12, 2023

"I don’t know if anyone is still having the same problem. I found something that fixes the message console issue

<Select
instanceId={'wsad123wqwe'}
/>

@atihar
Copy link

atihar commented Dec 23, 2023

For Nextjs import with next dynamic. It worked for me

import dynamic from 'next/dynamic'
const CreatableSelect = dynamic(() => import('react-select/creatable'), {
loading: () =>

Loading...

,
})

@anuparashar0507
Copy link

For the Nextjs 14 with Pages Router this is the fix

import dynamic from "next/dynamic";
const Select = dynamic(() => import("react-select"), { ssr: false });

It'll render the Select Component on the client side.

@WinnieS0728
Copy link

WinnieS0728 commented Dec 29, 2023

"next": "^14.0.4", // app router
"react-select": "^5.8.0",

same error here,
but I got another error

  • Extra attributes from the server: aria-activedescendant
image

I use dynamic import and instanceId and useEffect way to prevent error and it's work, but when I put MySelect component into another component like

export function MyForm (){
  return <form>
    <MySelect />
  </form>
}

the error show again, seems like I have to use dynamic import on top level import my MyForm component, after dynamic import, error will gone

const MyForm = dynamic(()=>import('./myForm'), {ssr: false})

export function Page (){
  return <>
    <MySelect />  // this one not show error
    <MyForm />  // this one show error if I don't use dynamic import MyForm
  </>
}

I think this not make sense, if I have heavy nesting component, I have to use dynamic import everywhere.

  • aria-activedescendant error doesn't broke anything in my app, but this error always show is annoying, maybe is there any way to block this error will be fine.

@everythinginjs
Copy link

@WinnieS0728 you can add Input property in components and make aria-activedescendant undefined or whatever you like it. like below:

<Select
      components={{
        Input: (props) => (
            <components.Input {...props} aria-activedescendant={undefined} />
        ),
      }}
    />

@WinnieS0728
Copy link

@everythinginjs
wow it's working. thank you so much.
I forgot I can customize my own component.

before this I even create a fake select component to prevent the flash before isClient useEffect work lol.
and I think useClient is better than dynamic import, because can have same props with the real component like className and placeholder.
now I remove useClient useEffect and everything is working fine. maybe this is the best answer in my project.

here I share my code to anyone use nextJS and have server issue

  • now code
export function ReactSelect({ className, name, ...props }: Parameters<Select>[0]) {
  return (
    <>
      <Select
        {...props}
        instanceId={`react-select-${props.name}`}
        className={cn("w-full", className)}
        closeMenuOnSelect={props.isMulti ? false : true}
        menuPlacement="auto"
        components={{
          Input: (props) => (
            <components.Input {...props} aria-activedescendant={undefined} />
          ),
        }}
      />
    </>
  );
}
  • origin code ( with fake component and useClient hook ) * not the best answer
function FakeReactSelect({
  placeholder = "Select...",
  ...props
}: Parameters<Select>[0] | Parameters<AsyncSelect>[0]) {
  return (
    <>
      <div
        className={cn(
          "flex h-[38px] w-full rounded-[4px] border-[1px] border-[#cccccc] bg-white",
          props.className,
        )}
      >
        <p className="flex w-full items-center overflow-x-clip px-[10px] py-[2px] text-[#808080]">
          {placeholder}
        </p>
        <div className="my-2 w-[1px] bg-[#cccccc]"></div>
        <div className="flex aspect-square items-center justify-center p-2">
          <svg viewBox="0 0 20 20" aria-hidden="true" focusable="false">
            <path
              fill="#cccccc"
              d="M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z"
            ></path>
          </svg>
        </div>
      </div>
    </>
  );
}

function useClient() {
  const [isClient, setClient] = useState<boolean>(false);
  useEffect(() => {
    setClient(true);
  }, []);
  return isClient;
}

export function ReactSelect(props: Parameters<Select>[0]) {
  const isClient = useClient();

  return (
    <>
      {isClient ? (
        <Select
          {...props}
          instanceId={`react-select-${props.name}`}
          className={cn("w-full", props.className)}
          closeMenuOnSelect={props.isMulti ? false : true}
          menuPlacement="auto"
        />
      ) : (
        <FakeReactSelect {...props} />
      )}
    </>
  );
}

@mhgamboa
Copy link

For the Nextjs 14 with Pages Router this is the fix

import dynamic from "next/dynamic"; const Select = dynamic(() => import("react-select"), { ssr: false });

It'll render the Select Component on the client side.

This worked for me in the app router with "use client"; as well

@stychu
Copy link

stychu commented Feb 7, 2024

This is so bad that I have to wait for render to see the input when doing
import dynamic from "next/dynamic"; const Select = dynamic(() => import("react-select"), { ssr: false });

Really, there is still no proper fix for this ?

@lyonsun
Copy link

lyonsun commented Mar 4, 2024

I have same issue. +1

@zwhitchcox
Copy link

Thank you @WinnieS0728

@TonniPaul
Copy link

I have same issue. +1

Just add the instanceId prop to the Select component.

You can achieve this by using the useId hook provided by React or you can just input a random id yourself.

import { useId } from 'react';

<Select
  {...props}
  instanceId={useId()}
/>

@patidarumesh
Copy link

app-index.js:33 Warning: Prop className did not match. Server: "__className_aaf875 vsc-initialized" Client: "__className_aaf875"

@dondxniel
Copy link

dondxniel commented Apr 4, 2024

Warning: Prop id did not match. Server: "react-select-6-live-region" Client: "react-select-2-live-region"

Works for app folder as well, thanks!

@patidarumesh
Copy link

Warning: Prop id did not match. Server: "react-select-6-live-region" Client: "react-select-2-live-region"

Works for app folder as well, thanks!

Sorry! How worked for you? How can i remove that warning.

@dammyammy
Copy link

dammyammy commented Apr 16, 2024

I ran into the same issue; my solution was a combination of using dynamic ssr false and combining the idea of a fake select on loading, as suggested by @WinnieS0728.

const Select = dynamic(() => import('react-select/async'), {
  ssr: false,
  loading: () => <FakeReactSelect placeholder="Select..." />,
});


function FakeReactSelect({
  placeholder = 'Select Job Roles...',
  className,
}: {
  placeholder: string;
  className?: string;
}) {
  return (
    <>
      <div
        className={cn(
          'flex h-[38px] w-full rounded-[4px] border-[1px] border-[#cccccc] bg-white text-sm',
          className
        )}>
        <p className="flex w-full items-center overflow-x-clip px-[10px] py-[2px] text-[#808080]">
          {placeholder}
        </p>
        <div className="my-2 w-[1px] bg-[#cccccc]"></div>
        <div className="flex aspect-square items-center justify-center p-2">
          <svg viewBox="0 0 20 20" aria-hidden="true" focusable="false">
            <path
              fill="#cccccc"
              d="M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z"></path>
          </svg>
        </div>
      </div>
    </>
  );
}

this renders a fake select while the original select loads on client, giving an illusion of responsiveness.

@Buongws
Copy link

Buongws commented May 1, 2024

app-index.js:33 Warning: Prop className did not match. Server: "__className_aaf875 vsc-initialized" Client: "__className_aaf875"

are u fix that ??

@patidarumesh
Copy link

app-index.js:33 Warning: Prop className did not match. Server: "__className_aaf875 vsc-initialized" Client: "__className_aaf875"

are u fix that ??

No

@oskarhertzman
Copy link

oskarhertzman commented May 3, 2024

for anyone using Next.JS, we did this:

const ValueContainer = dynamic(
  () => import("react-select").then((mod) => mod.components.ValueContainer),
  {
    ssr: process.env.NODE_ENV === "production",
  },
);

return (
 <ReactSelect
            ...
            components={{
              ValueContainer: (props) => (
                <ValueContainer {...props} aria-activedescendant={undefined} />
              ),
            }}
           ...
          />
)

Client side render the ValueContainer component on development to get rid of the warning / error

@jnovak-SM2Dev
Copy link

Is there a reason a fix for this isn't built into the library yet? This seems to be a large issue.

@majames
Copy link

majames commented Jun 23, 2024

Chiming in, during development:

  1. I initially started seeing Prop 'id' did not match SSR vs CSR error in the console, this was resolved by setting instanceId={uuid} (as suggested above)
  2. I then started getting the aria-activedescendant error -- unfortunately this wasn't resolved for me when setting aria-activedescendant={undefined} on both the Input and MultiValueContainer components 🤷

I also do notice a small rendering flicker/change difference between what is rendered server side vs client side in dev

yarn why next
└─ xtalk-pages@workspace:projects/xtalk-pages
   └─ next@npm:14.1.0 [12c32] (via npm:14.1.0 [12c32])
yarn why react-select
└─ xtalk-pages@workspace:projects/xtalk-pages
   └─ react-select@npm:5.8.0 [12c32] (via npm:^5.8.0 [12c32])

@albert-anthony6
Copy link

I also ran into this issue. I'm on reactv18 and I only see the issue when on production and in the Safari browser. All other browsers work well on production. The issue is affecting my multi-select dropdown and my custom single-select dropdown

@albert-anthony6
Copy link

I figured out that my issue is caused by my csp security. It prevents the inline styles from being added so the dropdowns look broken without the styles in place. I tried using nonce to resolve it but haven't been able to get the inline styles to be added with what I've tried so far.

@nburt
Copy link

nburt commented Jun 24, 2024

Chiming in, during development:

  1. I initially started seeing Prop 'id' did not match SSR vs CSR error in the console, this was resolved by setting instanceId={uuid} (as suggested above)
  2. I then started getting the aria-activedescendant error -- unfortunately this wasn't resolved for me when setting aria-activedescendant={undefined} on both the Input and MultiValueContainer components 🤷

I also do notice a small rendering flicker/change difference between what is rendered server side vs client side in dev

yarn why next
└─ xtalk-pages@workspace:projects/xtalk-pages
   └─ next@npm:14.1.0 [12c32] (via npm:14.1.0 [12c32])
yarn why react-select
└─ xtalk-pages@workspace:projects/xtalk-pages
   └─ react-select@npm:5.8.0 [12c32] (via npm:^5.8.0 [12c32])

I had the same issue w/ nextjs 14.2.4 and react-select 5.8.0. I ended up setting the instanceId and downgrading to 5.7.7 to remove the aria-active-descendent warning.

@majames
Copy link

majames commented Jul 4, 2024

Thanks! I can confirm that downgrading react-select to 5.7.7 also removed the console.error on my end

@marcelo-leite
Copy link

Hi, I had the same problem with next (13.2.1) and I found a workaround:

const MySelect = ({
	placeholder,
	options,
}: ProjectEditionSelectProps) => {
	const id = Date.now().toString();
	const [isMounted, setIsMounted] = useState(false);

	// Must be deleted once
	// https://github.com/JedWatson/react-select/issues/5459 is fixed.
	useEffect(() => setIsMounted(true), []);

	return isMounted ? (
		<Select
			id={id}
			options={options}
			placeholder={placeholder}
			className="project-edition-select-container"
			classNamePrefix="project-edition-select"
		/>
	) : null;
};

export default MySelect;

My workaround is to display the <Select /> component only in client side. UseEffect() is only triggered client-side so the isMounted is always false on server side.

If you use the experimental version of Next 13, you may use use-client directive.

I'm not particularly happy with this "fix" but it leaves my console in peace.

A cleaner solution would be to use lazy load (dynamic) with ssr false.

rxchna added a commit to rxchna/weather-forecast that referenced this issue Jul 30, 2024
@ChuckmonsterXlx
Copy link

To resolve the error "Extra attributes from the server: aria-activedescendant Error Component Stack" when using react-select, I downgrade to version 5.7.7 of react-select, as mentioned @nburt and @majames

@mdmahendri
Copy link

mdmahendri commented Oct 27, 2024

I'm getting the same Prop id did not match hydration error using Next.js 13's new appDir with react-select being used in a client component.

If I add a unique instanceId to the Select props, the hydration errors appear to go away (testing in dev right now).

well i googled and find this issue here which is similar to mine. I am using <Select> but without instanceId. this fix the bug, thank you

i am using react 18.3.1, next 15, react-select 5.8.2 and here are the error log

Hydration failed because the server rendered HTML didn't match the client. As a result this tree will be regenerated on the client. This can happen if a SSR-ed Client Component used

+id="react-select-3-live-region"
-id="react-select-2-live-region"
+id="react-select-3-placeholder"
-id="react-select-2-placeholder"
+Select...
+id="react-select-3-input"
-id="react-select-2-input"
+aria-describedby="react-select-3-placeholder"
-aria-describedby="react-select-2-placeholder"

@jeongwoo903
Copy link

I tried useId but the error didn't fundamentally fixed.

If you get the error warning: extra attributes from the server: aria-activedescendant error component stack, try downgrade to version 5.7.7.

Also, this code helped me solve the problem.
But if you need to use SSR, I don't recommend it.

const Select = dynamic(() => import('react-select'), { ssr: false });

@dominikzogg
Copy link

Still an issue with react 19.

@rodgarcialima
Copy link

@everythinginjs and @transitive-bullshit solutions together is working fine, even for React 19, but remember this:

When defining replacement components, it is important to do so outside the scope of rendering the Select. Defining a replacement component directly in the components prop can cause issues.

I was getting a focus issue and moving out the Input solved my problem.

@dominikzogg
Copy link

dominikzogg commented Dec 17, 2024

@rodgarcialima i got the problem using next 15 and react 19 even when there is no override and a static option list as an array.

this is as minimal i can make it, and the ssr code still differs from client.

import Select from 'react-select';

outside of the component:

const languageOptions: Array<Option> = [
  { label: 'label1', value: 'value1' },
  { label: 'label2', value: 'value2' },
  { label: 'label3', value: 'value3' },
  { label: 'label4', value: 'value4' },
  { label: 'label5', value: 'value5' },
  { label: 'label6', value: 'value6' },
  { label: 'label7', value: 'value7' },
  { label: 'label8', value: 'value8' },
  { label: 'label9', value: 'value9' },
  { label: 'label10', value: 'value10' },
];

within the component:

           <Select
        aria-label="change language"
        options={languageOptions}
      />
Hydration failed because the server rendered HTML didn't match the client. As a result this tree will be regenerated on the client. This can happen if a SSR-ed Client Component used

+ id="react-select-3-live-region"
- id="react-select-2-live-region"
+ id="react-select-3-placeholder"
- id="react-select-2-placeholder"
+ Select...
+ id="react-select-3-input"
- id="react-select-2-input"
+ aria-describedby="react-select-3-placeholder"
- aria-describedby="react-select-2-placeholder"
+ id="react-select-5-live-region"
- id="react-select-3-live-region"
+ id="react-select-5-placeholder"
- id="react-select-3-placeholder"
+ Select...
+ id="react-select-5-input"
- id="react-select-3-input"
+ aria-describedby="react-select-5-placeholder"
- aria-describedby="react-select-3-placeholder"

@rahmanusta
Copy link

Any solution ?

@rodgarcialima
Copy link

@rodgarcialima i got the problem using next 15 and react 19 even when there is no override and a static option list as an array.

this is as minimal i can make it, and the ssr code still differs from client.

import Select from 'react-select';

outside of the component:

const languageOptions: Array<Option> = [
  { label: 'label1', value: 'value1' },
  { label: 'label2', value: 'value2' },
  { label: 'label3', value: 'value3' },
  { label: 'label4', value: 'value4' },
  { label: 'label5', value: 'value5' },
  { label: 'label6', value: 'value6' },
  { label: 'label7', value: 'value7' },
  { label: 'label8', value: 'value8' },
  { label: 'label9', value: 'value9' },
  { label: 'label10', value: 'value10' },
];

within the component:

           <Select
        aria-label="change language"
        options={languageOptions}
      />
Hydration failed because the server rendered HTML didn't match the client. As a result this tree will be regenerated on the client. This can happen if a SSR-ed Client Component used

+ id="react-select-3-live-region"
- id="react-select-2-live-region"
+ id="react-select-3-placeholder"
- id="react-select-2-placeholder"
+ Select...
+ id="react-select-3-input"
- id="react-select-2-input"
+ aria-describedby="react-select-3-placeholder"
- aria-describedby="react-select-2-placeholder"
+ id="react-select-5-live-region"
- id="react-select-3-live-region"
+ id="react-select-5-placeholder"
- id="react-select-3-placeholder"
+ Select...
+ id="react-select-5-input"
- id="react-select-3-input"
+ aria-describedby="react-select-5-placeholder"
- aria-describedby="react-select-3-placeholder"

Yes, after these changes, it is still happening when we use macos.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
issue/bug-unconfirmed Issues that describe a bug that hasn't been confirmed by a maintainer yet
Projects
None yet
Development

No branches or pull requests