web-dev-qa-db-fra.com

Sauvegarde automatique des champs de formulaire dans les réactions et redux

J'ai un composant parent qui est une forme et il est connecté au magasin via redux en procédant ainsi: 

// FormComponent
export default connect(mapStateToProps, mapDispatchToProps)(FormComponent);

À l'intérieur de ce formulaire, j'ai une liste d'attributs d'entrée qui sont des composants enfants d'un formulaire: 

  • Composant de forme
    • Prénom Composant 
    • Nom du composant 
    • Composant d'adresse

J'ai l'obligation de sauvegarder les modifications de n'importe quel champ sur le serveur en effectuant un appel d'API de mise à jour en transmettant un objet JSON contenant tous les attributs dès que l'entrée perd le focus. 

l'appel de l'API serait quelque chose comme: 

updatePersonInfo({firstname: 'new name', lastname: 'new name', address: 'new address' });

Mon idée est de passer l'objet PersonInfo en tant qu'accessoires du composant Form à tous les composants enfants. Chaque composant enfant mettra à jour un attribut à partir des accessoires PersonInfo et enverra une action UPDATE_PERSONINFO avec un objet PersonInfo mis à jour . Mais pour ce faire, je dois connecter tous les composants enfants afin de stocker également: 

// FirstNameComponent
export default connect(mapStateToProps, mapDispatchToProps(FirstNameComponent);

// LastNameComponent
export default connect(mapStateToProps, mapDispatchToProps)(LastNameComponent);

// AddressComponent
export default connect(mapStateToProps, mapDispatchToProps)(AddressComponent);

Mais je pense que nous devrions éviter d’utiliser Connect pour des raisons de performances. De plus, je ne suis pas convaincu qu'il me faut 4 connecteurs pour appeler une action. 

Quelle serait la meilleure option pour gérer ce scénario?

6
Mhd

Pour ce problème, je peux vous proposer un bon truc que j'ai appris il y a quelque temps. Dans ces situations, nous devrions utiliser l'état du composant conteneur pour créer un composant de formulaire contrôlé et le mettre à jour à chaque changement de formulaire. Vous pourrez ainsi toujours accéder à vos données de formulaire depuis. état du composant conteneur. (Par exemple: en raison de la mise en œuvre du composant contrôlé, nous pouvons toujours envoyer les données de formulaire disponibles pour nous, de l'état du composant conteneur à Redux, via un bouton de sauvegarde ou dans des situations telles que votre cas Se concentrer sur un autre champ).

Alors, commençons:

(1) vous devez utiliser un attribut name et un onChange pour chaque entrée, comme suit:

<input 
  type='text'
  name={name}
  className='form-control'
  value={value}
  onChange={onChange}/>

(2) la fonction onChange est placée dans votre composant conteneur et est transmise via les accessoires à votre composant d'entrée. Elle ressemble à ceci:

  updateCourseState(e) {
    const field = e.target.name
    const _formData = {...this.state.formData}
    _formData[field] = e.target.value // (*)
    return this.setState({ formData: _formData}) // <= then update the state on every change
  }

Dans here (*) en utilisant des noms de variables dynamiques précalculés, nous créons une propriété pour chaque champ d'entrée dans notre objet temp _formData et lui affectons la valeur cible de l'événement qui lui a été transmis, puis nous mettons à jour l'état.

(3) et enfin, vous pouvez maintenant passer l'état à redux quand vous le souhaitez, et au fur et à mesure que je lis votre question, vous pouvez utiliser Refs() pour que le suivi de l'utilisation se concentre sur un autre champ, vous pouvez vérifier ce tutoriel sur YouTube pour cela et lorsque vous modifiez le focus, voici l'endroit où vous souhaitez envoyer vos données à Redux.

1
a_m_dev

Vous pouvez effectuer l'appel API directement dans chacun des composants pour ne mettre à jour que l'attribut correspondant, afin d'éviter Redux.
Par exemple. updatePersonInfo({ firstname: 'new name' })

Votre point de terminaison API doit être une méthode PATCH qui met à jour uniquement les champs figurant dans la charge utile (dans l'exemple ci-dessus, il ne doit modifier que le champ correspondant à firstname).

1
riwu

Je ne sais pas vraiment à quoi ressemblent vos sous-composants (par exemple, FirstNameComponent ...)

Premièrement, vous n'avez pas vraiment besoin de les connecter au magasin car vous avez le composant principal.

class FormComponent extends Component {

    changed(data, item) {
       const updatedData = {...this.props.data, item: data};
       this.props.updateData(updatedData);
    }

    render() {
        return (
            <div>
                <FirstNameComponent onChange={this.props.update} name={this.props.data.firstname} />
                <LastNameComponent onChange={this.props.update} name={this.props.data.lastname} />
                <AddressComponent onChange={this.props.update} name={this.props.data.address} />
            </div>
        );
    }

Comme vous pouvez le voir ici, nous avons le composant "principal" qui sera connecté à redux . Il obtiendra les valeurs du magasin et la méthode à appeler pour mettre à jour les données principales.

Les "sous-composants" sont "stupides" car ils obtiennent simplement des données et appellent une méthode à partir de leurs accessoires quand une entrée était floue.

0
Tzook Bar Noy

Je pense que vous pouvez utiliser store.subscribe(listener) pour comparer les modifications et appeler l'API pour enregistrer les données. https://redux.js.org/api-reference/store#subscribe

J'utilise ceci pour une fonctionnalité similaire, j'enregistre toutes les données de mon magasin dans le stockage local du navigateur. 

Voici comment j'utilise

    import { loadState, saveState, loadLanguage } from "./common/localStorage";



    class Main extends React.Component {

    ..........

    store.subscribe(() => {
       saveState(store.getState()); // Some DOM api calls.
    });

    ..........

   }

Mon fichier localStorage.js

    export const loadState = () => {
    try {
        const serializedState = localStorage.getItem('state');

        if (serializedState === null) {
            return undefined;
        }

        return JSON.parse(serializedState);

    } catch (err) {
        return undefined;
    }
};

export const saveState = (state) => {
    try {
        const serializedState = JSON.stringify(state);
        localStorage.setItem('state', serializedState);
    } catch (err) {
        // die
    }
};


export const saveLanguage = (code) => {
    try {
        localStorage.setItem('languageCode', code);
    } catch (err) {
        // die
    }
};

export const loadLanguage = () => {
    try {
        const languageCode = localStorage.getItem('languageCode');

        if (languageCode === null) {
            return "pt-br";
        }

        return languageCode;

    } catch (err) {
        return "pt-br";
    }
};
0

Avez-vous vraiment besoin de redux (ou redux-form) pour cela? 

Essayez Formik. Je l’ai trouvé très flexible, vous pouvez utiliser des gestionnaires de flou ou valider (envoyer uniquement valide?) Pour passer des appels api.

0
xadm