简体   繁体   中英

What is the proper way of implementing form input validation with stateless components

So I've recently started working with react-native and I would obviously like to use best practices to work on my apps. That's why I decided to use redux and follow the advice to write stateless, functional components.

Once I got used to it and established some standards it worked great for a while: I write a functional component, map state and dispatch to its props and have a store that keeps track of how things are and gets injected by Provider .

Things got complicated once I got into making validation for my form input component. Say I want to have a component that can validate its input and display error if there is a problem. I can obviously add some state to my global store for this, but I don't want to have a place in my global store for each input that I use in my app. This might be in contrast to what is taught about using redux, but I have a feeling what I want is not that impractical.

So to give an example of what I want:

const Input = ({ error }) => {
  let style = styles.input;
  const onChange = (val) => {
    // change the error here, say
    if(val === 'test') error = null;
    else error = 'must be test';
  };
  if (error) {
    style = styles.inputError;
  }
  return (
    <TextInput
      style={style}
      onChangeText={onChange}
    />
  );
};

But I wouldn't like to have to connect error to a global state.

Is this too much to ask, or have I overlooked the way to make Input refresh itself (I can't get this in it at all)?

I get that this is a more of a philosophical question, as there is an obvious solution of creating ES6 class for your component and using setState . I'm mostly interested in hearing about some approaches to solving this problem and if there is a problem at all, or I'm just being too stubborn. :)

OK, I mentioned this was pretty much a meta question, but for me was a significant one, as I learned a lot while fiddling with it.

Hopefully what I learned will help someone running into same issue and save him time needed to research this topic with so little online resources:

  1. You can't and probably shouldn't be able to access your pure control from inside of it.
  2. If you do have to create your control as ES6 class and access this , even your linter won't complain anymore because that is fine use case, so there are a couple of cases where it's OK to extend Component .

Example of the control that uses these two conclusions looks like this:

class Input extends Component {
  render() {
    let style = styles.input;
    const error = this.state && this.state.error;
    const onChange = (val) => {
      if (val === 'test') this.setState({ error: null });
      else this.setState({ error: 'test required' });
    };
    if (error) {
      style = styles.inputError;
    }
    return (
      <TextInput
        style={style}
        onChangeText={onChange}
      />
    );
  }
}

Now, since I am stubborn I learned one more thing: it's possible to make it with just pure components. Like I stated in the comments somewhere, it is possible to make a local store, wrap your component in Provider and connect to it the same way you are used to while using functional components. I am not sure how useful will it be, but I will provide the example:

const localStore = createStore(
  (state = [], obj) => (obj ? { errorMessage: obj.error } : state),
  { errorMessage: null },
);

const inputWithStore = ({ error }) => {
  let style = styles.input;
  const onChange = (val) => {
    if (val === 'test') localStore.dispatch({ type: 'unused', error: null });
    else localStore.dispatch({ type: 'unused', error: 'test required' });
  };
  if (error) {
    style = styles.inputError;
  }
  return (
    <TextInput
      style={style}
      onChangeText={onChange}
    />
  );
};

const mapStateToProps = (state) => ({ error: state.errorMessage });

const InputWithStore = connect(mapStateToProps)(inputWithStore);

const Input = () =>
(
  <Provider store={localStore}>
    <InputWithStore />
  </Provider>
);

I will still appreciate hearing about other approaches and comments about these. Thanks.

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