Mam formularz w aplikacji React / Redux, który służy do aktualizacji informacji - stąd wymagać wstępnie wypełnionych danych z bieżącymi danymi.

Przed zamontowaniem składnika dane formularza już siedzi w stanie Redux.

Obecnie w componentDidMount() Lifecycle można wysyłać żądanie Axios, aby ponownie pobrać informacje z bazy danych i ładować go do stanu Redux.

Ta metoda działa dobrze, jednak chciałbym uniknąć dodatkowej / zbędnej prośby, ponieważ informacje są już w stanie Redux.

Jak prześledzić stan Redux do stanu komponentu, gdy ładuje się, dzięki czemu pola wejściowe są zaludnione (bez konieczności popełnienia żądania)?

Kod komponentu jest poniżej.

import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';

import Navbar from '../components/layout/Navbar';
import Sidebar from '../components/layout/Sidebar';
import Breadcrumbs from '../components/layout/Breadcrumbs';
import TextFieldGroup from '../components/form-components/TextFieldGroup';

import { getPatientById } from '../redux/actions/patient.actions';

class PatientEdit extends Component {
  constructor() {
    super();
    this.state = {
      firstName: '',
      lastName: '',
      errors: {}
    };
  }

  componentDidMount = () => {
    if (this.props.match.params.patient_id) {
      this.props.getPatientById(this.props.match.params.patient_id);
    }
  };

  componentWillReceiveProps = nextProps => {
    if (nextProps.errors) {
      this.setState({ errors: nextProps.errors });
    }

    if (nextProps.patients.patient) {
      const patient = nextProps.patients.patient;
      this.setState({
        firstName: patient.firstName.patients,
        lastName: patient.lastName.patients
      });
    }
  };

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

  onSubmit = (e, patient_id) => {
    e.preventDefault();
    // boring script to handle form submission...
  };

  render() {
    const { errors } = this.state;
    const { patient } = this.props.patients;

    return (
      <>
        <Navbar />
        <div className="app-body">
          <Sidebar />
          <main className="main">
            <div className="container">
              <form onSubmit={e => this.onSubmit(e, patient._id)}>
                <div>
                  <input
                    type="text"
                    name="firstName"
                    value={this.state.firstName}
                    onChange={this.onChange}
                  />
                  <input
                    type="text"
                    name="lastName"
                    value={this.state.lastName}
                    onChange={this.onChange}
                  />
                </div>
                <div>
                  <Link to="/patients" className="btn btn-light mr-2">
                    Cancel
                  </Link>
                  <button type="submit" className="btn btn-primary">
                    Submit
                  </button>
                </div>
              </form>
            </div>
          </main>
        </div>
      </>
    );
  }
}

PatientEdit.propTypes = {
  getPatientById: PropTypes.func.isRequired,
  patients: PropTypes.object.isRequired,
  errors: PropTypes.object.isRequired
};

const mapStateToProps = state => ({
  patients: state.patients,
  errors: state.errors
});

export default connect(
  mapStateToProps,
  { getPatientById }
)(PatientEdit);

getpatientbyd działanie

export const getPatientById = id => dispatch => {
  dispatch(setPatientLoading());
  axios
    .get(`/api/patients/${id}`)
    .then(res => {
      dispatch({
        type: GET_PATIENTS_SINGLE,
        payload: res.data
      });
    })
    .catch(err => {
      dispatch({
        type: GET_ERRORS,
        payload: err.response.data
      });
    });
};
3
Braden 24 luty 2019, 11:41

2 odpowiedzi

Najlepsza odpowiedź

Wygląda na to, że kopiujesz dane z Redux do lokalnego stanu. Może być potrzebne, czy nie. Jeśli chodzi o swój cel, dlaczego nie bezpośrednio renderowania danych otrzymanych z Redux (bez kopiowania ich do stanu)? W takim przypadku możesz pominąć połączenie AXIOS w componentDidMount.

Jeśli chcesz mieć dane z Redux w stanie w stanie, możesz skopiować je do stanu w konstruktorze lub w componentDidMount. To sprawia, że kopia tylko raz. Jeśli będziesz musiał zachować dane z Redux i Stan w synchronizacji, musisz zapewnić to w componentWillReceiveProps.

Wierzę, że problem, który napotkałeś z aktualną konfiguracją, jest to, że componentWillReceiveProps nie jest wezwany do pierwszego renderowania, dlatego nic nie zostało skopiowane do twojego stanu.

1
gmoniava 24 luty 2019, 09:11

Na odwrocie, nie mógłbyś zdać stanu Redux i użyć tego do logiki sterującej? Zakładam, że pochodzi z patients Redux State, gdy używasz go w metodzie componentWillReceiveProps, więc jeśli tak jest, nie możesz zrobić:

// rest of code emitted for brevity
componentDidMount = () => {
    // assuming init state for patients.patient is null
    if (!this.patients.patient && this.props.match.params.patient_id) {
      this.props.getPatientById(this.props.match.params.patient_id);
    }
  };

Zakłada się, że stan początkowym this.props.patients.patient jest null z reduktora. Jeśli this.props.patients jest null zamiast tego zmień kod logiki sterowania, aby być !this.props.patients && this.props.match.params.patient_id.

Logika sterująca mówi tutaj "Jeśli pacjenci są null, a mamy identyfikator paramiczny, a następnie sprawić, aby API otrzymasz połączenie". Jeśli już masz pacjenta, to nie przeszkadza.

0
Dennis O'Keeffe 24 luty 2019, 09:04