react-select icon indicating copy to clipboard operation
react-select copied to clipboard

react18 support

Open bturner1273 opened this issue 1 year ago • 29 comments

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 avatar Nov 02 '22 15:11 bturner1273

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?

lukebennett88 avatar Nov 02 '22 21:11 lukebennett88

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

ci7lus avatar Nov 07 '22 11:11 ci7lus

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: https://github.com/remix-run/examples/pull/35 Hope that helps.

lukebennett88 avatar Nov 07 '22 22:11 lukebennett88

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).

transitive-bullshit avatar Nov 11 '22 22:11 transitive-bullshit

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.

RaphaelEscrig avatar Mar 07 '23 16:03 RaphaelEscrig

Having the same issue with Next 13

kingsleykbc avatar May 29 '23 11:05 kingsleykbc

Same issue with NextJS 13.4!

usmonzo avatar Jun 02 '23 11:06 usmonzo

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}
              />

usmonzo avatar Jun 02 '23 19:06 usmonzo

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 <Select/> Component renders once in the client side.

PranuPranav97 avatar Oct 01 '23 19:10 PranuPranav97

In my case, i solved using

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

ats1999 avatar Oct 11 '23 04:10 ats1999

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

barrynorman avatar Nov 10 '23 10:11 barrynorman

Same problem over here...

gh-johnny avatar Nov 16 '23 01:11 gh-johnny

Same problem

michael-ravelhq avatar Nov 20 '23 09:11 michael-ravelhq

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

idilTugba avatar Nov 20 '23 23:11 idilTugba

idk is someone still having the same problem. im find something and this fix the message console

<Select instanceId={'wsad123wqwe'} />

codegeekery avatar Dec 12 '23 01:12 codegeekery

For Nextjs import with next dynamic. It worked for me

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

Loading...

, })

atihar avatar Dec 23 '23 21:12 atihar

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.

anuparashar0507 avatar Dec 28 '23 17:12 anuparashar0507

"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.

WinnieS0728 avatar Dec 29 '23 08:12 WinnieS0728

@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} />
        ),
      }}
    />

everythinginjs avatar Jan 03 '24 08:01 everythinginjs

@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} />
      )}
    </>
  );
}

WinnieS0728 avatar Jan 05 '24 02:01 WinnieS0728

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

mhgamboa avatar Jan 24 '24 16:01 mhgamboa

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 ?

stychu avatar Feb 07 '24 14:02 stychu

I have same issue. +1

lyonsun avatar Mar 04 '24 14:03 lyonsun

Thank you @WinnieS0728

zwhitchcox avatar Mar 08 '24 15:03 zwhitchcox

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()}
/>

TonniPaul avatar Mar 09 '24 21:03 TonniPaul

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

patidarumesh avatar Mar 23 '24 18:03 patidarumesh

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!

dondxniel avatar Apr 04 '24 13:04 dondxniel

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.

patidarumesh avatar Apr 04 '24 14:04 patidarumesh

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.

dammyammy avatar Apr 16 '24 13:04 dammyammy

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

are u fix that ??

Buongws avatar May 01 '24 12:05 Buongws