JedWatson / JedWatson/react-select
Styles not Loading in Remix
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 28k
- Forks
- 4.1k
- PR merge metrics
- No merged PRs in 30d
Description
Hi There - I'm sorry, I'm not sure how to replicate this in your code sandbox. I have a suspicion that this somehow relates to Remix and SSR, but can't get to the root of it.
Basically, the form, doesn't display properly. If you change something in code, and dev mode reloads the page, then everything shows correctly. If you do an actual browser load or refresh, the form styles don't load correctly.
Based on my research, I have tried waiting for hydration, and I've tried using a useEffect to make sure it only loads in the client to separate from SSR, but neither works.
This is the controlled form field that I'm rendering:
import { useQuery } from '@apollo/client'
import { Control, Controller, FieldValues } from 'react-hook-form'
import AsyncSelect from 'react-select/async'
import { CSSObjectWithLabel, GroupBase, OptionsOrGroups } from 'react-select'
interface OptionType {
label: string
value: string
}
interface OptionItem {
id: string
name?: string
firstName?: string
lastName?: string
}
interface RelationSelectProps {
field: {
key: string
options: {
document?: any // Specify the GraphQL document type if available
dataType?: string
filter?: (items: OptionItem[]) => OptionItem[]
selectOptionsFunction?: (items: OptionItem[]) => OptionType[]
multi?: boolean
}
}
control: Control<FieldValues, unknown>
}
function label(item: { id: string; name?: string; firstName?: string; lastName?: string }): string {
if (item?.name) {
return item.name
}
if (item?.firstName && item?.lastName) {
return `${item.firstName} ${item.lastName}`
}
if (item?.firstName && !item?.lastName) {
return item.firstName
}
return item.id
}
function defaultOptionsMap(items: OptionItem[]): OptionType[] {
return items?.map?.((option) => ({ value: `${option.id}`, label: label(option) }))
}
export function RelationSelect({ field, control }: Readonly<RelationSelectProps>) {
const { data, loading, refetch } = useQuery(field.options.document)
let dataList: OptionItem[] =
field.options.dataType && !loading ? data?.[field.options.dataType] : [{ value: '', label: 'Loading...' }]
if (field.options.filter && !loading) {
dataList = field.options.filter(dataList)
}
function getDefaultOptions(
dataList: any[],
options: { selectOptionsFunction?: (data: any[]) => OptionType[] },
): OptionType[] {
if (dataList && dataList.length > 0) {
if (options.selectOptionsFunction) {
return options.selectOptionsFunction(dataList)
} else {
return defaultOptionsMap(dataList)
}
} else {
return [{ value: '', label: 'No Matching Data Found' }]
}
}
async function getStorageOptions(inputText: string): Promise<OptionsOrGroups<OptionType, GroupBase<OptionType>>> {
const res = await refetch({ input: { search: inputText } })
const data = field.options.dataType ? res.data[field.options.dataType] : null
return getOptions(data)
}
function getOptions(data: any): OptionType[] | OptionsOrGroups<OptionType, GroupBase<OptionType>> {
if (data) {
if (field.options.selectOptionsFunction) {
return field.options.selectOptionsFunction(data)
} else {
return defaultOptionsMap(data)
}
} else {
return [{ value: '', label: 'No Matching Data Found' }]
}
}
const customStyles = {
control: (provided: CSSObjectWithLabel) => ({
...provided,
backgroundColor: 'white',
fontSize: '14px',
}),
singleValue: (provided: CSSObjectWithLabel) => ({
...provided,
fontSize: '14px',
color: '#64748b',
}),
option: (provided: CSSObjectWithLabel) => ({
...provided,
fontSize: '14px',
color: '#64748b',
}),
}
return (
<Controller
control={control}
name={field.key}
render={({ field: { onChange, value } }) => (
<AsyncSelect
name={field.key}
instanceId={field.key}
value={value}
key={field.key}
defaultOptions={getDefaultOptions(dataList, field.options)}
loadOptions={getStorageOptions}
onChange={onChange}
isLoading={loading}
isMulti={field.options.multi}
classNamePrefix="rs"
styles={customStyles}
/>
)}
/>
)
}
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the provided RelationSelect component and reproduce the difference between a full browser refresh and a development reload in a Remix SSR setup. Inspect how AsyncSelect, classNamePrefix, and styles behave during the initial load; done means the form styles render correctly after a full refresh as well as after hot reload.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react, typescript
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 20/100