Как я могу смонтировать или отключить компонент в зависимости от метода onClick в React? - PullRequest
0 голосов
/ 02 февраля 2020

У меня есть компонент (PropertiesList.tsx), который показывает список свойств, поступающих из магазина (приставка), затем я хочу реализовать кнопку с функцией удаления, которая при нажатии удаляет это свойство из базы данных (эта часть работает) и из хранилища, поэтому он автоматически исчезает из представления без перезагрузки, проблема в том, что дочерний компонент (OnePropertyDetails.tsx), который отображается при щелчке по любому компоненту из списка, пытается выполнить рендеринг и, поскольку он был удален с помощью редуктора он выдает ошибку, так как не может ее найти. У меня в родительском состоянии есть состояние showdetails, и когда я go для функции удаления, я устанавливаю showdetails в false, так что компонент исчезает, так как он не должен отображать его, проблем не должно быть, но, видимо, this.setState({detailsVisible:false}) в строке 61 PropertiesList.tsx ничего не делает или иным образом я не знаю, что не так, поскольку у дочернего компонента есть условие, такое как detailsVisible ? OnePropertyDetals : null, и это работало для меня до

, это PropertiesList .tsx:

import React, { PureComponent, Component } from "react";
import "./style.css";
import {} from "reactstrap";

import { connect } from "react-redux";
import { IStore } from "../../interfaces/IStore";
import { IProperty, IProperties } from "../../interfaces/IProperties";
import { setPropertiesAction, deletePropertyAction } from "../../Redux/actions";
import { getProperties, deleteProperty } from "../../utils/API";
import { IProfile } from "../../interfaces/IProfile";
import OnePropertyDetails from "../OnePropertyDetails/OnePropertyDetails";

//own props
interface IProps {}

//props coming from the store
interface IGlobalProps {
  //para coger el token me lo traigo de props
  userProfile: IProfile;
  //properties esta en el store y se lo pasamos al componente por props
  properties: IProperties;
  //el action hay que pasarlo por props(le paso como argumento lo mismo que he definido en el action)
  setProperties(propertiesList: IProperty[]): void;
  deletePropertyAct(id: number): void;
}

type TProps = IProps & IGlobalProps; //conjunto de las props propias y las que vienen del store

interface IState {
  detailsVisible: boolean;
  selectedIdProperty: number;
}

class PropertiesLlist extends Component<TProps, IState> {
  constructor(props: TProps) {
    super(props);

    this.state = {
      detailsVisible: false,
      selectedIdProperty: null
    };

    this.showProperty = this.showProperty.bind(this);
    this.deleteOneProperty = this.deleteOneProperty.bind(this);
  }

  componentDidMount() {
    (async () => {
      const token = localStorage.getItem("token");
      const response = await getProperties(token);
      this.props.setProperties(response);
    })();
  }

  showProperty(id: number): any {
    this.setState({ selectedIdProperty: id, detailsVisible: true });
  }

  //TODO borrar si funciona desde el hijo
  deleteOneProperty(id: number) {
    this.setState({ detailsVisible: false });
    console.log(this.state.detailsVisible);
    const token = localStorage.getItem("token");
    deleteProperty(token, id); //fetch
    this.props.deletePropertyAct(id); //action
  }

  render() {
    const { byId } = this.props.properties;
    const { detailsVisible } = this.state;
    const properties = Object.values(byId); // it creates an array out of the object(byId)

    return (
      <div>
        <div
          style={{ display: "flex", flexDirection: "row", flexWrap: "wrap" }}
        >
          {properties.map(property => (
            <div
              key={property.id_property}
              className="card border-light mb-3 ml-2 "
              style={{ maxWidth: "14rem", cursor: "pointer" }}
              onClick={() => this.showProperty(property.id_property)}
            >
              <img
                src="https://images.adsttc.com/media/images/5d34/e507/284d/d109/5600/0240/newsletter/_FI.jpg?1563747560"
                className="card-img-top"
                alt="..."
              ></img>
              <div className="card-header">
                <div className="card-body">
                  <p style={{ fontSize: 14 }} className="card-title">
                    {property.address_line1}
                  </p>
                </div>
                <button
                  onClick={() => this.deleteOneProperty(property.id_property)}
                >
                  Eliminar
                </button>
              </div>
            </div>
          ))}
        </div>
        <div className="offset-3 col-md-6">
          {" "}
          {detailsVisible ? (
            <OnePropertyDetails id={this.state.selectedIdProperty} />
          ) : null}
        </div>
      </div>
    );
  }
}

//states we are gonna take from the IStore
const mapStateToProps = (store: IStore) => ({
  userProfile: store.userProfile,
  properties: store.properties
});

// we send actions to the reducer(only to save states) and the reducer save what we send in the action
const mapDispatchToProps = {
  setProperties: setPropertiesAction,
  deletePropertyAct: deletePropertyAction
};

export default connect(mapStateToProps, mapDispatchToProps)(PropertiesLlist);

Это дочерний компонент OnePropertyDetails.tsx:

import React, { PureComponent } from "react";

import {} from "reactstrap";
import { IStore } from "../../interfaces/IStore";
import { connect } from "react-redux";
import { IProperties, IProperty } from "../../interfaces/IProperties";
import UpdateProperty from "../UpdateProperty/UpdateProperty";
import { deletePropertyAction, setPropertiesAction } from "../../Redux/actions";
import { deleteProperty, getProperties } from "../../utils/API";

//own props
interface IProps {
  id: number;
}
//stor props
interface IGlobalProps {
  properties: IProperties;
  // deletePropertyAct(id: number): void;
}

type TProps = IProps & IGlobalProps;

interface IState {
  formVisible: boolean;
}

class OnePropertyDetails extends PureComponent<TProps, IState> {
  constructor(props: TProps) {
    super(props);

    this.state = {
      formVisible: false
    };
    this.showUpdateForm = this.showUpdateForm.bind(this);
    // this.deleteOneProperty = this.deleteOneProperty.bind(this);
  }

  // deleteOneProperty() {
  //   (async () => {
  //     try {
  //       const token = localStorage.getItem("token");
  //       await deleteProperty(token, this.props.id); //fetch
  //       this.props.deletePropertyAct(this.props.id); //action 
  //       console.log(this.props.properties)
  //     } catch (error) {
  //       console.log(error)
  //     }
  //   })();
  // }

  showUpdateForm() {
    console.log(this.state.formVisible); //TODO mirar con esther
    if (this.state.formVisible === false) {
      this.setState({
        formVisible: true
      });
    } else {
      this.setState({
        formVisible: false
      });
    }
    console.log(this.state.formVisible);
  }

  render() {
    //TODO mostrar las incidencias de cada componente
    const { id } = this.props;
    const property = this.props.properties.byId[id];
    return (
      <div>
        <div
          className="card border-light mb-3"
          style={{ maxWidth: "20rem", cursor: "pointer" }}
        >
          <img src="..." className="card-img-top" alt="..."></img>
          <div className="card-header">
            <div className="card-body">
              <h5 className="card-title">{property.address_line1}</h5>
              <h6 className="card-title">{property.address_line2}</h6>
              <p style={{ marginLeft: "25%" }} className="card-text">
                {property.locality}
              </p>
              <p style={{ marginLeft: "15%" }}>
                {property.region}-- {property.postcode}
              </p>
            </div>
          </div>
          <button
            style={{ marginLeft: "5%" }}
            type="submit"
            className="btn btn-sm btn-outline-secondary mt-4"
            data-target="#updateProperty"
            data-toggle="modal"
            onClick={this.showUpdateForm}
          >
            Editar
          </button>

          <button
            style={{ marginLeft: "5%" }}
            type="submit"
            className="btn btn-sm btn-outline-secondary mt-4"
            // data-target="#updateProperty"
            // data-toggle="modal"
            // onClick={this.deleteOneProperty}
          >
            Eliminar
          </button>
        </div>
        <div
          className="modal fade"
          id="updateProperty"
          role="dialog"
          aria-labelledby="exampleModalLabel"
          aria-hidden="true"
        >
          <div className="modal-dialog" role="document">
            <div className="modal-content">
              <div className="modal-header">
                <h5 className="modal-title" id="exampleModalLabel">
                  Actualizar Propiedad {id}
                </h5>
                <button
                  type="button"
                  className="close"
                  data-dismiss="modal"
                  aria-label="Close"
                >
                  <span aria-hidden="true">&times;</span>
                </button>
              </div>
              {this.state.formVisible ? ( 
                <div className="modal-body">
                  <UpdateProperty
                    propertyId={id}
                    desmontar={this.showUpdateForm}
                  />
                </div>
              ) : null}
              <div className="modal-footer"></div>
            </div>
          </div>
        </div>
      </div>
    );
  }
}

const mapStateToProps = (store: IStore) => ({
  properties: store.properties
});

const mapDispatchToProps = {
  // deletePropertyAct: deletePropertyAction,

};

export default connect(mapStateToProps, mapDispatchToProps)(OnePropertyDetails);

редуктор:

import { IPropertyForm } from "./../../interfaces/IPropertyForm";
import { TAction } from "../types";

import produce from "immer";
import { IProperties } from "../../interfaces/IProperties";

const initialState: IProperties = {
  byId: {},
  order: []
};

export default (state: IProperties = initialState, action: TAction) =>
  produce(state, draftState => {
    switch (action.type) {
      case "SET_PROPERTIES":
        const properties = action.payload;
        draftState.byId = {}; // inic para no duplicar, ojo si quieres mantener algún dato
        draftState.order = [];
        properties.forEach(property => {
          draftState.byId[property.id_property] = property;
          draftState.order.push(property.id_property);
        });
        break;
      case "UPDATE_PROPERTY":
        draftState.byId[action.payload.id_property] = action.payload;
        break;
      case "DELETE_PROPERTY":
        console.log("entro al reducer",action.payload);
        delete draftState.byId[action.payload];
        const pos = draftState.order.indexOf(action.payload);
        draftState.order.splice(pos, 1);
        console.log("acaba el reducer");
        break;
      case "SET_LOGOUT":
        return (state = initialState);
      default:
        return state;
    }
  });

и вывод:

OnePropertyDetails.tsx:78 Uncaught TypeError: Cannot read property 'address_line1' of undefined
    at OnePropertyDetails.render (OnePropertyDetails.tsx:78)
    at finishClassComponent (react-dom.development.js:18470)
    at updateClassComponent (react-dom.development.js:18423)
    at beginWork$1 (react-dom.development.js:20186)
    at HTMLUnknownElement.callCallback (react-dom.development.js:336)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:385)
    at invokeGuardedCallback (react-dom.development.js:440)
    at beginWork$$1 (react-dom.development.js:25780)
    at performUnitOfWork (react-dom.development.js:24695)
    at workLoopSync (react-dom.development.js:24671)
    at performSyncWorkOnRoot (react-dom.development.js:24270)
    at react-dom.development.js:12199
    at unstable_runWithPriority (scheduler.development.js:697)
    at runWithPriority$2 (react-dom.development.js:12149)
    at flushSyncCallbackQueueImpl (react-dom.development.js:12194)
    at flushSyncCallbackQueue (react-dom.development.js:12182)
    at discreteUpdates$1 (react-dom.development.js:24423)
    at discreteUpdates (react-dom.development.js:1438)
    at dispatchDiscreteEvent (react-dom.development.js:5881)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...