简体   繁体   中英

Argument of type null is not assignable to parameter of type RadioGroupState

I'm trying to build a design-system in Typescript using React-Aria and I am having some trouble with the Radio component.

I tried to follow the example as much as I could but I ended up with: Argument of type 'null' is not assignable to parameter of type 'RadioGroupState'. And I don't understand how to solve this issue, does someone have some advice for me?

Here's my code:

import { VisuallyHidden } from '@react-aria/visually-hidden';
import { useFocusRing } from '@react-aria/focus';
import { useRadioGroup, useRadio } from '@react-aria/radio';
import { useRadioGroupState } from '@react-stately/radio';
import { AriaRadioGroupProps } from '@react-types/radio';
import { AriaRadioProps } from '@react-types/radio';

let RadioContext = React.createContext(null);

interface RadioGroupProps extends AriaRadioGroupProps {
  children: React.ReactNode;
}

interface RadioProps extends AriaRadioProps {
  children: React.ReactNode;
}

function RadioGroup(props: RadioGroupProps) {
  let { children, label, isDisabled, defaultValue } = props;
  let state = useRadioGroupState(props);
  let { radioGroupProps, labelProps } = useRadioGroup(props, state);

  return (
    <div {...radioGroupProps}>
      <span {...labelProps}>{label}</span>
      <RadioContext.Provider value={state}>{children}</RadioContext.Provider>
    </div>
  );
}

function Radio(props: RadioProps) {
  let { children } = props;
  let state = React.useContext(RadioContext);
  let ref = React.useRef(null);

  let { inputProps } = useRadio(props, state, ref);
  let { isFocusVisible, focusProps } = useFocusRing();

  let isSelected = state.selectedValue === props.value;
  let strokeWidth = isSelected ? 2 : 2;

  return (
    <label
      className={`${state.isDisabled ? 'cursor-not-allowed' : ''}`}
      style={{ display: 'flex', alignItems: 'center' }}
    >
      <VisuallyHidden>
        <input {...inputProps} {...focusProps} ref={ref} />
      </VisuallyHidden>
      <svg width={24} height={24} aria-hidden="true" style={{ marginRight: 4 }}>
        <circle
          cx={12}
          cy={12}
          r={8 - strokeWidth / 2}
          fill="none"
          stroke={isSelected ? 'red' : '#BBBBBB'}
          strokeWidth={strokeWidth}
        />
        {isSelected && (
          <path transform="translate(5.5 5)" d={`M 4 3 A 1 1 0 0 0 9 11 A 1 1 0 0 0 4 3`} fill="#F70000" />
        )}
      </svg>
      <div className={`${state.isDisabled ? 'text-grey-disabled cursor-not-allowed' : ''}`}>{children}</div>
    </label>
  );
}

export { Radio, RadioGroup };

I solved the problem this way:

  1. Imported RadioGroupState from @react-stately/radio .
  2. Assigned the context component with the type:
    let RadioContext = createContext<RadioGroupState | null>(null);
  3. Assigned the context variable with null possibility:
    let stateOrNull = useContext(RadioContext);
  4. Assigned the state variable and casted it to the RadioGroupState type:
    let state = stateOrNull as RadioGroupState;

CodeSandbox

import { createContext, useContext, useRef } from "react";
import { VisuallyHidden } from "@react-aria/visually-hidden";
import { useFocusRing } from "@react-aria/focus";
import { useRadioGroup, useRadio } from "@react-aria/radio";
import { RadioGroupState, useRadioGroupState } from "@react-stately/radio";
import { AriaRadioGroupProps, AriaRadioProps } from "@react-types/radio";

let RadioContext = createContext<RadioGroupState | null>(null);

interface RadioGroupProps extends AriaRadioGroupProps {
  children: React.ReactNode;
}

interface RadioProps extends AriaRadioProps {
  children: React.ReactNode;
}

function RadioGroup(props: RadioGroupProps) {
  let { children, label } = props;
  let state = useRadioGroupState(props);
  let { radioGroupProps, labelProps } = useRadioGroup(props, state);

  return (
    <div {...radioGroupProps}>
      <span {...labelProps}>{label}</span>
      <RadioContext.Provider value={state}>{children}</RadioContext.Provider>
    </div>
  );
}

function Radio(props: RadioProps) {
  let { children } = props;
  let stateOrNull = useContext(RadioContext);
  let state = stateOrNull as RadioGroupState;
  let ref = useRef(null);

  let { inputProps } = useRadio(props, state, ref);
  let { focusProps } = useFocusRing();

  let isSelected = state.selectedValue === props.value;
  let strokeWidth = isSelected ? 2 : 2;

  return (
    <label
      className={`${state.isDisabled ? "cursor-not-allowed" : ""}`}
      style={{ display: "flex", alignItems: "center" }}
    >
      <VisuallyHidden>
        <input {...inputProps} {...focusProps} ref={ref} />
      </VisuallyHidden>
      <svg width={24} height={24} aria-hidden="true" style={{ marginRight: 4 }}>
        <circle
          cx={12}
          cy={12}
          r={8 - strokeWidth / 2}
          fill="none"
          stroke={isSelected ? "red" : "#BBBBBB"}
          strokeWidth={strokeWidth}
        />
        {isSelected && (
          <path
            transform="translate(5.5 5)"
            d={`M 4 3 A 1 1 0 0 0 9 11 A 1 1 0 0 0 4 3`}
            fill="#F70000"
          />
        )}
      </svg>
      <div
        className={`${
          state.isDisabled ? "text-grey-disabled cursor-not-allowed" : ""
        }`}
      >
        {children}
      </div>
    </label>
  );
}

export { Radio, RadioGroup };

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM