Как сделать поле ввода предварительно заполненным данными и редактировать его при загрузке страницы? - PullRequest
4 голосов
/ 03 ноября 2019

У меня проблемы с получением одного из полей для предварительного заполнения информацией и возможности редактирования. Я пытался перемещаться по коду, где он устанавливает поле с данными, и оно либо пустое и редактируемое, либо показывает предварительно заполненные данные, но пользовательский интерфейс не позволяет мне их редактировать.

У меня проблема с полем bar. Помещение в конструктор предварительно заполняет поле информацией, но пользовательский интерфейс не позволяет мне его редактировать. Почему? Где должно быть установлено это поле или как я могу это исправить? Нужно ли указывать, где этот объект заполняется перед переходом на эту страницу, чтобы он заполнялся во время инициализации конструктора или ...?

Вот фрагмент кода класса:

export class FooBarBazComponent extends Component{
    constructor(props){

        super(props);

        state = {
            foo: "",
            bar: ""
        };

        const fooDetails = this.props.navigation.state.params.fooDetails;
        this.state.foo   = fooDetails.foo; 

    }

    render(){
        const disabled = this.state.foo.length !== 5 || this.state.bar.length < 5;

        //I didn't put this code in the constructor because this object is undefined in the constructor
        if(this.props.objResponse) {  
            this.state.bar = this.props.objResponse.bar; 
        }

        return(
            <View style={Styles.inputRow}>
                <View style={Styles.inlineInput}>
                    <FormLabel labelStyle={Styles.label}>FOO</FormLabel>
                    <TextInputMask
                      onChangeText={foo => this.setState({ foo })}
                      value={this.state.foo}
                    />
                </View>
                <View style={Styles.inlineInput}>
                    <FormLabel labelStyle={Styles.label}>BAR</FormLabel>
                    <TextInputMask
                        onChangeText={bar => this.setState({ bar })}
                        value={this.state.bar}
                    />
                </View> 
            </View>
        );
    }
}

Ответы [ 5 ]

2 голосов
/ 13 ноября 2019

Я думаю, что лучший подход здесь - сделать его функциональным компонентом. Вы можете использовать React Hooks для логики с сохранением состояния и для того, чтобы ваш код был более чистым.

Я бы деструктурировал реквизиты и установил бы их прямо в исходное состояние. Затем я добавил бы некоторую условную логику для рендеринга полей ввода только при установленном начальном состоянии. Готово!

Если вы хотите изменить состояние, просто используйте функцию установки!

import React, { useState } from 'react';

export default function FooBarBazComponent({ navigation, objResponse }) {
  // Initiate the state directly with the props
  const [foo, setFoo] = useState(navigation.state.params.fooDetails);
  const [bar, setBar] = useState(objResponse.bar);

  const disabled = foo.length !== 5 || bar.length < 5;

  return (
    <View style={styles.inputRow} >
      {/* Only render next block if foo is not null */}
      {foo && (
        <View style={styles.inlineInput}>
          <FormLabel labelStyle={Styles.label}>FOO</FormLabel>
          <TextInputMask
            onChangeText={foo => setFoo(foo)}
            value={foo}
          />
        </View>
      )}
      {/* Only render next block if objResponse.bar is not null */}
      {objResponse.bar && (
        <View style={styles.inlineInput}>
          <FormLabel labelStyle={Styles.label}>BAR</FormLabel>
          <TextInputMask
            onChangeText={bar => setBar(bar)}
            value={bar}
          />
        </View>
      )}
    </View>
  );
}
1 голос
/ 14 ноября 2019

Я вижу несколько проблем в коде.

state = {
  foo: "",
  bar: ""
};

Выше необходимо изменить, как это

this.state = {
   foo: "",
   bar: ""
};

Или поместить ваш код за пределы конструктора.

Затем из этого,

const fooDetails = this.props.navigation.state.params.fooDetails;
this.state.foo = fooDetails.foo; 

до

this.state = {
   foo: props.navigation.state.params.fooDetails,
   bar: ""
};

Потому что вы не должны напрямую изменять состояние. и у вас уже есть реквизиты в конструкторе.

Затем из этого,

if(this.props.objResponse) {  
   this.state.bar = this.props.objResponse.bar; 
  }
}

переместите это в componentDidMount или куда вы делаете свой вызов API. Вы не должны изменять состояние и не должны обновлять состояние в методе рендеринга, который создаст цикл.

А также обновите состояние с помощью метода this.setState.

Если вы все еще сталкиваетесь с какой-либо проблемой, вам необходимо проверить ваш TextInputMask компонент после выполнения вышеупомянутых действий.

0 голосов
/ 15 ноября 2019

Попробуйте setState() в componentDidMount(), как показано ниже

 componentDidMount() {
    if (this.props.isFromHome) {
      this.setState({ isFromHome: true });
    } else {
      this.setState({ isFromHome: false });
    }
  }

, когда вы вызываете setState (), он будет перерисовывать компонент.

0 голосов
/ 13 ноября 2019

Сначала мы сохраним текущий реквизит как prevProps в состоянии вашего компонента. Затем мы будем использовать метод класса статических компонентов getDerivedStateFromProps, чтобы обновлять ваше состояние в зависимости от ваших реквизитов. Он вызывается так же, как componentDidUpdate, и возвращаемое значение будет вашим новым состоянием компонента.

Исходя из вашего кода, я предполагаю, что ваш this.props.objResponse.bar исходит из ответа API, как видно из вашего комментария

Я не помещал этот код в конструктор, потому что этот объект не определен в конструкторе

Если возможно, лучше использовать функциональный компонент с перехватчиками React вместо использованиякласс в будущем.

Вот несколько чистых примеров кода для справки.

<code>import React from "react";
import ReactDOM from "react-dom";

import "./styles.css";

class FooBarBazComponent extends React.Component {
  constructor(props) {
    super(props);
    const { foo, bar } = props;
    this.state = {
      // save previous props value into state for comparison later
      prevProps: { foo, bar },
      foo,
      bar,
    }
  }

  static getDerivedStateFromProps(props, state) {
    const { prevProps } = state;
    // Compare the incoming prop to previous prop
    const { foo, bar } = props;
    return {
      // Store the previous props in state
      prevProps: { foo, bar },
      foo: prevProps.foo !== foo ? foo : state.foo,
      bar: prevProps.bar !== bar ? bar : state.bar,
    };
  }

  handleOnChange = (e) => {
    this.setState({ [e.target.name]: e.target.value });
  }

  renderInput = (name) => (
    <div>
      <label>
        {`${name}:`}
        <input onChange={this.handleOnChange} type="text" name={name} value={this.state[name]} />
      </label>
    </div>
  )

  render() {
    const { prevProps, ...rest } = this.state;
    return (
      <section>
        {this.renderInput('foo')}
        {this.renderInput('bar')}
        <div>
          <pre>FooBarBazComponent State :
            {JSON.stringify(rest, 4, '')}
          
);}} класс App extends React.Component {// Это будет имитировать вызов API mockAPICall = () => new Promise ((res) => setTimeout (() => res ('bar'), 1000));state = {bar: ''} async componentDidMount () {const bar = await this.mockAPICall ();this.setState ({bar});} render () {const {bar} = this.state;вернуть ()}} const rootElement = document.getElementById ("root");ReactDOM.render (, rootElement);

Надеюсь, это даст вам общее представление о том, как это сделать.

Рабочий пример: https://codesandbox.io/s/react-reactive-state-demo-2j31u?fontsize=14

0 голосов
/ 03 ноября 2019

Вы никогда не должны назначать реквизиты государству напрямую. Это абсолютное нет-нет. Также, если возможно, попробуйте перейти к реагированию на крючки, это намного проще и чище, чем этот подход.

export class FooBarBazComponent extends Component {

constructor(props)
{
    state = {
        foo: "",
        bar: ""
    };

    const fooDetails = this.props.navigation.state.params.fooDetails;
    this.state.foo = fooDetails.foo; 

}

static getDerivedStateFromProps(props, state) {
  if (props.objResponse && props.objResponse.bar !== state.bar) {
   return {
    ...state,
    bar: props.objResponse.bar
   }
  }
  return null;
}


render() {
    const disabled =
      this.state.foo.length !== 5 || this.state.bar.length < 5;

    return (

          <View style={styles.inputRow}>
            <View style={styles.inlineInput}>
              <FormLabel labelStyle={Styles.label}>FOO</FormLabel>
              <TextInputMask
                onChangeText={foo => this.setState({ foo })}
                value={this.state.foo}
              />
            </View>
            <View style={styles.inlineInput}>
              <FormLabel labelStyle={Styles.label}>BAR</FormLabel>
              <TextInputMask
                onChangeText={bar => this.setState({ bar })}
                value={this.state.bar}
              />
            </View> 
          </View>
    );
  }
}
...