2
votes

I'm trying to get redux-form to work with TypeScript and styled-components. In the following code example, why doesn't it work with the styled input component? The input renders, but focus is lost on each keypress. It also takes two clicks to focus element. It seems like redux-form is trying to control the wrapped element returned from styled-components? Both redux-form and styled-components use HOC - higher order components to pass props to underlying element.

export interface ITxtProps extends WrappedFieldProps {
  label?: string;
}

export const FieldHack = class extends Field<any> {};

const renderTxt = (props: ITxtProps & GenericFieldHTMLAttributes) => {
  const StyledInput = styled.input`
    background-color: deeppink;
  `;
  const notWorking = <StyledInput {...props.input} />;
  const worksPerfectly = <input {...props.input} />;
  return (
  <div>
    <div>{props.label}</div>
    {notWorking}
  </div>
);
}

const NormalLoginComponent = (props: {
  handleSubmit?: SubmitHandler<{}, {}>;
}) => {
  const { handleSubmit } = props;
  return (
    <form onSubmit={handleSubmit}>
      {/* this does not work when using styled components: */}
      <Field name={'email'} component={renderTxt}  />

      {/* this gives an error, property label does not exist on type... */}
      {/*<Field name={'email'} component={renderTxt} label="email" />*/}

      {/* this works, but no intellisense/static types */}
      <FieldHack name={'email2'} component={renderTxt} label="email" />

      <Field name={'password'} component={'input'} type="password" />
      <Button text={'log in'} onClick={handleSubmit} />
    </form>
  );
};

export interface ILoginForm {
  email: string;
  password: string;
}

const LoginForm = reduxForm<Readonly<ILoginForm>, {}>({
  form: 'loginNormal',
})(NormalLoginComponent);
1
I have the same problem. @Tomas did you got any result? - Ahmad Behzadi

1 Answers

1
votes

Yes, I finally figured it out.. I did a mistake, and that was to create my styled-component wrapper inside the render method:

const StyledInput = styled.input`
  background-color: deeppink;
;

Apparently it's not safe to apply a HOC - higher order component inside render(). So it should work when moving the HOC outside render:

export interface ITxtProps extends WrappedFieldProps {
  label?: string;
}

export const FieldHack = class extends Field<any> {};

// wrap you HOC outside render:
const StyledInput = styled.input`
    background-color: deeppink;
  `;

const renderTxt = (props: ITxtProps & GenericFieldHTMLAttributes) => {
  // works now :)
  const notWorking = <StyledInput {...props.input} />;
  const worksPerfectly = <input {...props.input} />;
  return (
  <div>
    <div>{props.label}</div>
    {notWorking}
  </div>
);
}

I was reading the docs on another HOC library when figuring this out, here is a link that explains where it's safe to apply (any) HOC: redux-auth-wrapper documentation on HOCs