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:
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.