n4kz / react-native-material-textfield

Material textfield
Other
901 stars 831 forks source link

Can not change text dynamically #184

Closed whalemare closed 5 years ago

whalemare commented 5 years ago

For some cases, I need behavior for dynamically change text inside TextField.

User want to change his birthday. User click on TextField and see DatePicker Use select date with DatePicker I format this date and put inside TextField into value property.

  render() {
    const birthdayFormatted = TimeHelper.format(this.state.birthday, TimeHelper.PATTERN_MONTH_DAY_YEAR)
    return (
      <ClickableView onPress={() => this.setState({ showDatePicker: true })}>
        <Text>{birthdayFormatted}</Text> {/* in this line text rendered correctly*/}
        <TextField value={birthdayFormatted} editable={false} /> {/* in this line text render only initial value*/}
      </ClickableView>
    )
  }

In 12.0 this behavior is working corectly, but in 13.0 it is broken. I see in changes that you change logic of value handling. For now, how can I deal with it?

n4kz commented 5 years ago

Thanks for question. Before 0.13.0 component behavior was unpredictable in some cases. Now TextField is fully uncontrolled component with instance method setValue for external updates. value prop retained, but now it works like initial value. For masked or formatted content I'm planning to release additional helper in upcoming release (next week).

Uncontrolled behavior was chosen over controlled to reduce animation complexity and improve performance.

n4kz commented 5 years ago

Done with formatText prop and now input masking is supported. And for your question I can suggest the following:

  inputRef = React.createRef();

  componentDidUpdate(prevProps, prevState) {
    let { birthday } = this.state;

    if (birthday !== prevState.birthday) {
      let birthdayFormatted = TimeHelper.format(birthday, TimeHelper.PATTERN_MONTH_DAY_YEAR)
      this.inputRef.current.setValue(birthdayFormatted);
    }
  }

  render() {
    return (
      <ClickableView onPress={() => this.setState({ showDatePicker: true })}>
        <TextField editable={false} ref={this.inputRef} />
      </ClickableView>
    )
  }

Another option would be using defaultValue instead of value as TextField keeps updating it until it receives focus for the first time. And this will never happen while it's not editable.

syky27 commented 5 years ago

Hi @n4kz Sorry for jumping this issue, but when I use defaultValue, The text gets updated with update to variable, but the text is gray, the same was as if the TextField is empty, once clicked, the text changes to black. Is this an issue, or am I missing something?

EDIT: I have created and issue #191

Thanks

haseebeqx commented 5 years ago

Here is a wrapper I created as I used this in a large project and had to make it compatible with minimal changes. We use callback refs, you may need to make some changes if you use regular ref

import React, { useEffect, useRef } from "react";
import { TextField } from "react-native-material-textfield";

const InputField = React.forwardRef(({ value, ...props }, ref) => {
  const rref = useRef(null);

  function setReference(reference) {
    ref(reference);
    rref.current = reference;
  }

  useEffect(() => {
    rref.current.setValue(value);
  }, [value]);

  return (
    <TextField
      ref={setReference}
      tintColor={styles.colorOfSuccess}
      errorColor={styles.colorOfDanger}
      {...props}
    />
  );
});

export default InputField;

and

Also if you use accessory you may need renderRightAccessory={renderAccessory} as it is also became incompatible

rdgomt commented 4 years ago

When I try to set ref I am getting this message: "Functional components cannot be given refs." What can I do, please?

leemcmullen commented 4 years ago

@haseebeqx Thanks for your useful snippet (https://github.com/n4kz/react-native-material-textfield/issues/184#issuecomment-552079946).

Can I just ask, what was the first line within the setReference method supposed to do i.e. the call to a ref function: ref(reference);?

I can't see where that ref function is defined or required?

ZaidSA commented 4 years ago

v0.16.3: Using createRef, worked well for me.

anchi20 commented 3 years ago

@leemcmullen It is one of the arguments in React.forwardRef callback function.

const InputField = React.forwardRef(({ value, ...props }, ref) => {

azhararmar commented 3 years ago

I am using Formik and resetForm() was not clearing the value of text input. Thanks to the solution from @haseebeqx it works now.