facebook / react-native

A framework for building native applications using React
https://reactnative.dev
MIT License
118.37k stars 24.25k forks source link

TextInput text mismatch component state #20930

Closed bhrott closed 5 years ago

bhrott commented 6 years ago

Environment

React Native Environment Info: System: OS: macOS High Sierra 10.13.6 CPU: x64 Intel(R) Core(TM) i7-4770HQ CPU @ 2.20GHz Memory: 21.04 MB / 16.00 GB Shell: 3.2.57 - /bin/bash Binaries: Node: 10.8.0 - ~/.nvm/versions/node/v10.8.0/bin/node Yarn: 1.9.2 - /usr/local/bin/yarn npm: 6.2.0 - ~/.nvm/versions/node/v10.8.0/bin/npm Watchman: 4.7.0 - /usr/local/bin/watchman SDKs: iOS SDK: Platforms: iOS 11.4, macOS 10.13, tvOS 11.4, watchOS 4.3 Android SDK: Build Tools: 23.0.1, 23.0.2, 23.0.3, 25.0.0, 25.0.2, 26.0.0, 26.0.2, 26.0.3, 27.0.1, 27.0.3 API Levels: 21, 23, 26, 27 IDEs: Android Studio: 3.1 AI-173.4720617 Xcode: 9.4.1/9F2000 - /usr/bin/xcodebuild npmPackages: react: 16.4.1 => 16.4.1 react-native: 0.56.0 => 0.56.0 npmGlobalPackages: react-native-cli: 2.0.1

Description

When text input change, if we intermediate the value, change it and then set the state, the text input ignores the state and keep the character user inputs:

image

Reproducible Demo

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow
 */

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

function getDefaultTranslator() {
    return {
        A: char => /[A-Za-z]/.test(char),
        '0': char => /[0-9]/.test(char),
        '@': char => /[A-Za-z0-9]/.test(char),
        '*': () => true
    }
}

function applyMask(mask, value, translator = getDefaultTranslator()) {
    let result = ''

    let maskCharIndex = 0
    let valueCharIndex = 0

    while (true) {
        // if mask is ended, break.
        if (maskCharIndex == mask.length) {
            break
        }

        // if value is ended, break.
        if (valueCharIndex == value.length) {
            break
        }

        let maskChar = mask[maskCharIndex]
        let valueChar = value[valueCharIndex]

        // value equals mask, just set
        if (maskChar == valueChar) {
            result += maskChar
            valueCharIndex += 1
            maskCharIndex += 1
            continue
        }

        // apply translator if match
        const translatorKey = translator[maskChar]
        if (translatorKey) {
            if (translatorKey(valueChar)) {
                result += valueChar
                maskCharIndex += 1
            }

            valueCharIndex += 1
            continue
        }

        // not masked value, fixed char on mask
        result += maskChar
        maskCharIndex += 1
        continue
    }

    return result
}
export default class App extends Component {
    state = {
        text: ''
    }
    render() {
        return (
            <View style={styles.container}>
                <TextInput
                    style={{
                        width: '80%',
                        height: 50,
                        borderWidth: 1,
                        borderColor: 'red'
                    }}
                    value={this.state.text}
                    onChangeText={text => {
                        const masked = applyMask('000 000 000', text)
                        console.log(masked)
                        this.setState({ text: masked })
                    }}
                />
            </View>
        )
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#F5FCFF'
    },
    welcome: {
        fontSize: 20,
        textAlign: 'center',
        margin: 10
    },
    instructions: {
        textAlign: 'center',
        color: '#333333',
        marginBottom: 5
    }
})
burabure commented 5 years ago

this is so annoying, any workarounds?

bhrott commented 5 years ago

@burabure Already have a PR to solve this. If you are working with expo, sorry, nothing to do unless you eject. If you are working with normal RN project, follow this guide

lxcid commented 5 years ago

Can I know which PR?

elicwhite commented 5 years ago

Hello there 👋 this issue seems to have been inactive for the past few weeks. Because of this, it's likely that the issue is not a high priority anymore or it has been solved by OP; for these reasons, we'll close it. But please, if it's actually still an issue with 0.59 please comment below and we can reopen it or please send us a Pull Request with a fix 😊