4
votes

I learn in the same time ReactJS and React Native. I saw in an udemy tutorial something very beautiful, that the professor putt it just one onChange method, for all inputs and taking advantage of the "name" attribute, he could do this:

const onChange = event =>
    setFormData({ ...formData, [event.target.name]: event.target.value });

So he said, instead of having for each onChange, inside of each input, a different method, we can have only one.

This is the code that I'm talking about:

const Register = props => {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    password: '',
    password2: ''
  });

  const { name, email, password, password2 } = formData;
  const onChange = event =>
    setFormData({ ...formData, [event.target.name]: event.target.value });

  const onSubmit = async event => {
    event.preventDefault();
    if (password !== password2) {
      props.setAlert('Passwords do not match', 'danger', 5000);
    } else {
      props.registerUser({ name, email, password });
    }
  };


  if (props.isAuthenticated) {
    return <Redirect to="/dashboard" />;
  }
  return (
    <Fragment>
      <h1 className="large text-primary">Sign Up</h1>
      <p className="lead">
        <i className="fas fa-user" /> Create Your Account
      </p>
      <form className="form" onSubmit={event => onSubmit(event)}>
        <div className="form-group">
          <input
            type="text"
            placeholder="Name"
            name="name"
            value={name}
            onChange={event => onChange(event)}
          />
        </div>
        <div className="form-group">
          <input
            type="email"
            placeholder="Email Address"
            name="email"
            value={email}
            onChange={event => onChange(event)}
          />
          <small className="form-text">
            This site uses Gravatar so if you want a profile image, use a
            Gravatar email
          </small>
        </div>
        <div className="form-group">
          <input
            type="password"
            placeholder="Password"
            name="password"
            // minLength="6"
            value={password}
            onChange={event => onChange(event)}
          />
        </div>
        <div className="form-group">
          <input
            type="password"
            placeholder="Confirm Password"
            name="password2"
            value={password2}
            onChange={event => onChange(event)}
          />
        </div>
        <input type="submit" className="btn btn-primary" value="Register" />
      </form>
      <p className="my-1">
        Already have an account? <Link to="/login">Sign In</Link>
      </p>
    </Fragment>
  );
};

In React Native, that is with a different professor, I tried to think how to do this. I tried a few days the offered props from the TextInput but non of then, in my opinion, can be used how we can use the "name" attribute in ReactJS.

This is the code for the React Native app:

import React, { Component } from 'react';
import {
  StyleSheet,
  View,
  Button,
  TextInput,
} from 'react-native';

class PlaceInput extends Component {
  state = {
    userName: '',
    placeName: ''
  }

  userNameChangeHandler = (value) => {
    this.setState({ userName: value })
  }

  placeNameChangeHandler = (value) => {
    this.setState({ placeName: value })
  }

  placeSubmitHandler = () => {
    if (this.state.placeName.trim() === '') {
      return;
    }

    this.props.onPlaceAdded(this.state.placeName)
  }

  render() {
    return (
      <View style={styles.inputContainer}>
        <TextInput
          style={styles.placeInput}
          value={this.state.userName}
          onChangeText={this.userNameChangeHandler}
          placeholder='User Name' />
        <TextInput
          style={styles.placeInput}
          value={this.state.placeName}
          onChangeText={this.placeNameChangeHandler}
          placeholder='Beautiful place' />
        <Button title='Add' style={styles.placeButton} onPress={this.placeSubmitHandler} />
      </View>
    );
  }
};

Please someone help me to understand: it is possible to have one onChangeText method in React Native, like the professor from ReactJS did with onChange?

2

2 Answers

3
votes

Try passing input "name" as a value to the handler function. Like so:

import React, { Component } from 'react';
import {
  StyleSheet, View, TextInput,
} from 'react-native';

class PlaceInput extends Component {
  state = {
    userName: '',
    placeName: ''
  }

  handleInputChange = (inputName, inputValue) => {
    this.setState(state => ({ 
      ...state,
      [inputName]: inputValue // <-- Put square brackets
    }))
  }

  render () {
    return (
      <View style={styles.inputContainer}>
        <TextInput
          style={styles.placeInput}
          value={this.state.userName}
          onChangeText={value => this.handleInputChange('userName', value)}
          placeholder='User Name' />
        <TextInput
          style={styles.placeInput}
          value={this.state.placeName}
          onChangeText={value => this.handleInputChange('placeName', value)}
          placeholder='Beautiful place' />
      </View>
    );
  }
};
1
votes

For that type of a function you are using the wrong prop. While onChangeText is all fine, it takes as its parameter a function with a single parameter: the changed text. Because of that you cannot do it with the onChangeText.

However, there exists another prop called onChange. This one supplies the following object as the parameter per the documentation: { nativeEvent: { eventCount, target, text} }. Target here, while could be used, is going to be just a number.

What would I suggest?

Instead of trying to handle it through the event.target.name change your function to take a second argument: name. After that you should call your functions as follows;

onChangeText={text => this.inputChangeHandler(text, 'name')}

This will create a function whose sole purpose is to supply the second parameter, allowing you to use just one function for all your text changes.