JedWatson / react-select

The Select Component for React.js
https://react-select.com/
MIT License
27.54k stars 4.12k forks source link

react18 support #5459

Open bturner1273 opened 1 year ago

bturner1273 commented 1 year ago

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

lukebennett88 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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.

transitive-bullshit commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

Having the same issue with Next 13

usmonzo commented 1 year ago

Same issue with NextJS 13.4!

usmonzo commented 1 year ago

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

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 [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 commented 8 months ago

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

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

I have same issue. +1

zwhitchcox commented 6 months ago

Thank you @WinnieS0728

TonniPaul commented 6 months ago

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

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

dondxniel commented 5 months ago

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

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

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

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

are u fix that ??

patidarumesh commented 4 months ago

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

are u fix that ??

No

oskarhertzman commented 4 months ago

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

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

majames commented 3 months ago

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

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

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

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

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

marcelo-leite commented 2 months ago

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.