简体   繁体   中英

React TS - Passing props up the component tree

I have created form elements that I can configure in different ways to create forms.

Here's an example of that:

<form>
  <Label htmlFor="name" name="Enter name:" />
  <InputWrapper>
    <Input id="name" name="name" />
  </InputWrapper>
  <CharacterLimit />
</form>

What I would like to do is set a maxLength & required prop on my Input component and it will cause my Label component to then have a red asterisk( * ) and my CharacterLimit component to display the maxLength set on my Input component.

Here's what my Label component looks like:

interface ILabel {
  htmlFor: string;
  name: string;
  required?: boolean;
}

export const Label: React.FC<ILabel> = ({ htmlFor, name, required }) => {
  return (
    <StyledLabel htmlFor={htmlFor}>
      {name} {required && <StyledRequired>*</StyledRequired>}
    </StyledLabel>
  );
};

const StyledLabel = styled.label`
  font-weight: 600;
`;
const StyledRequired = styled.span`
  color: red;
`;

And here's what my CharacterLimit components look like:

interface ICharacterLimit {
  maxLength?: number;
}

export const CharacterLimit: React.FC<ICharacterLimit> = ({ maxLength }) => {
  return (
    <>
      {maxLength && (
        <StyledCharacterLimit>0 / {maxLength} Characters</StyledCharacterLimit>
      )}
    </>
  );
};

Now you're probably wondering why I don't just put the Label & CharacterLimit components inside of my Input component and conditionally render them that way.

Well, I have another component as you can see called InputWrapper , this is used to style the "container" of the input , the reason I wanted to make this styling separate, is so then I could put an input and a button inside of the container for example.

Here's an illustration to example better what I mean:

在此处输入图片说明

How can I get the props passed from my Input component to the Label and CharacterLimit components? Or is there another approach to achieve them the same layouts in my illustration?

I have put together a demo on CodeSandBox

This is not necessarily an answer, but too long for comment

Something like this:

const FormModel = () => {
  const [formModel, setFormModel] = useState();
  const updateFormModel = name => value => setFormModel({
    ...formModel,
    { [name]: value }
  });
  return (
    <form>
      <InputWrapper onChange={updateForm("something")} isValid={validate(formModel)} />
    <form>
  );
};

const InputWrapper = ({ onChange, isValid }) => {
  // returns appropriate stuff, including 
  // <input onChange={e => onChange(e.currentTarget.value)} />
  // styled based on isValid prop. May also want to debounce
  // input, but whateves.
}

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