Как перерисовать DOM после изменения состояния компонента? - PullRequest
2 голосов
/ 04 ноября 2019

Я делаю запрос к axios и получаю некоторые данные, которые затем устанавливаю в состояние моего компонента:

  componentDidMount() {
    instance
      .get("https://bartering-application.firebaseio.com/myitems.json")
      .then(response => {
        var obj = Object.values(response.data);
        console.log("parsed", obj);
        this.setState({ addedItem: obj });
      })
      .catch(error => {
        console.log(error);
      });
  }

Таким образом, мое состояние, в котором было свойство addItem, теперь получает значение objs. Затем в моем методе render() я рендерил дочерний компонент, который получает реквизиты из моего состояния (свойства которого обновлены через componentDidMount):

  render() {
    const items = this.state.addedItem.map(item => {
      return (
        <MyItem
          title={item.Title}
          description={item.Description}
          condition={item.Condition}
          url={item.URL}
        />
      )
    })
  }

Это работает нормально, однако я вижу результат дочернего процессакомпонент отображается, только если я перезагрузить браузер. Как сделать так, чтобы приложение автоматически перезагружалось при изменении свойства состояния (в моем случае добавленного элемента)? Какой метод жизненного цикла я должен использовать для немедленной перерисовки DOM при изменении свойства состояния?

Полный код компонента приведен ниже:

class MyItems extends Component {
  constructor(props) {
    super(props);

    const initial_state = {
      image: null,
      url: "",
      uploadStatus: false,
      itemTitle: "",
      itemDescription: "",
      barteringCondition: "",
      addedItem: []
    };

    this.state = initial_state;

    this.handleChange = this.handleChange.bind(this);
    this.handleUpload = this.handleUpload.bind(this);
  }

  componentDidMount() {
    instance
      .get("https://bartering-application.firebaseio.com/myitems.json")
      .then(response => {
        var obj = Object.values(response.data);
        console.log("parsed", obj);
        this.setState({ addedItem: obj });
      })
      .catch(error => {
        console.log(error);
      });
  }

  // componentDidUpdate(prevState){
  //     if (prevState !== this.state){
  //         window.location.reload();
  //     }
  // }

  handleChange = e => {
    if (e.target.files[0]) {
      const image = e.target.files[0];
      this.setState(
        () => ({ image, uploadStatus: true }),
        () => console.log(this.state.image.name)
      );
    }
  };

  handleUpload = () => {
    if (!this.state.uploadStatus) {
      alert("No item image was uploaded.");
      return null;
    }
    const { image } = this.state;
    const uploadTask = storage.ref(`images/${image.name}`).put(image);
    uploadTask.on(
      "state_changed",
      snapshot => {
        // demonstrate the image upload progress
      },
      error => {
        // error function
        console.log(error);
      },
      () => {
        //complete function
        storage
          .ref(`images`)
          .child(image.name)
          .getDownloadURL()
          .then(url => {
            console.log(url);
            alert("uploaded!");
            this.setState({ url });
            // When uploadded image url is received, collect all item data into myNewItem object and post this record to Firebase Database

            const myNewItem = {
              Title: this.state.itemTitle,
              Description: this.state.itemDescription,
              URL: this.state.url,
              Condition: this.state.barteringCondition
            };

            instance.post("/myitems.json", myNewItem).then(error => {
              console.log(error);
            });
          });
      }
    );
  };

  titleChangeHandler = event => {
    this.setState({ itemTitle: event.target.value });
  };

  descriptionChangeHandler = event => {
    this.setState({ itemDescription: event.target.value });
  };

  render() {
    const items = this.state.addedItem.map(item => {
      return (
        <MyItem
          title={item.Title}
          description={item.Description}
          condition={item.Condition}
          url={item.URL}
        />
      );
    });

    return (
      <Auxiliary>
        <div className={classes.MyItems}>
          <div className={classes.container}>
            <div className={classes.MyItems__left__container}>
              <div className={classes.Items__Upload}>
                {" "}
                <p>Upload your barter item picture below:</p>
                <br />
                <input type="file" onChange={this.handleChange} />
                <br />
                <p style={{ padding: "0px", margin: "10px" }}>
                  Title of the item:
                </p>
                <input type="text" onChange={this.titleChangeHandler} />
              </div>
              <div className={classes.Items__Info}>
                <div className={classes.Items_Description}>
                  <p>Describe your item:</p>
                  <textarea
                    rows="15"
                    cols="30"
                    onChange={this.descriptionChangeHandler}
                  />
                </div>
                <div className={classes.Items_Bartering__Condition}>
                  <p>Bartering condition:</p>
                  <br />
                  <div className={classes.Items__Bartering_Condition_Options}>
                    <fieldset id="barter-options">
                      <input type="radio" name="with-similar" />
                      With a similar item <br />
                      <input type="radio" name="with-similar-with-extra" />
                      With a similar item with extra payment <br />
                      <input type="radio" name="with" />
                      With
                      <input
                        style={{ height: "11px", maxWidth: "240px" }}
                        type="text"
                        name="special-item"
                        placeholder="e.g. Rolex Watch model 16233"
                      />
                      <br />
                      <input type="radio" name="as-gift" />I give this item as
                      gift! <br />
                      <input type="radio" name="as-gift" />I give this item as
                      gift to
                      <input
                        style={{ height: "11px", maxWidth: "120px" }}
                        type="text"
                        placeholder="e.g. students"
                      />
                      <br />
                    </fieldset>
                    <div className={classes.Items_addButton}>
                      <button onClick={this.handleUpload}>+ADD</button>
                    </div>
                  </div>
                </div>
              </div>
            </div>
            <div className={classes.MyItems__right__container}>
              <div className={classes.MyItems__right__container__header}>
                <p>My items</p>
              </div>
              <div className={classes.MyItems__right__container__block}>
                {/* <MyItem title={this.state.itemTitle} description={this.state.itemDescription} condition={this.state.barteringCondition} url={this.state.url} /> */}
                {items}
              </div>
            </div>
          </div>
        </div>
      </Auxiliary>
    );
  }
}

export default MyItems;

дочерний компонент MyItem:

import React, { useEffect } from "react";
import Auxiliary from "../hoc/Auxiliary";
import { storage } from "../Firebase/Fire";
import classes from "../MyItem/MyItem.module.css";

const MyItem = props => {
  return (
    <Auxiliary>
      <div className={classes.MyItem}>
        <h4>Item: {props.title}</h4>
        <img
          src={props.url || "https://via.placeholder.com/140x100"}
          height="100"
          width="140"
        />
        <p>Description: {props.description}</p>
        <p>Bartering condition: {props.condition}</p>
      </div>
    </Auxiliary>
  );
};

export default MyItem;

Ответы [ 2 ]

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

Я решил эту проблему, добавив метод window.location.reload (), который запускает повторную визуализацию DOM сразу после успешной загрузки образа пользователя в базу данных FIrebase. Итак, вот код:

instance.post('/myitems.json', myNewItem)
                        .then(response => {window.location.reload();} )
                        .then(error => {
                            console.log(error);
                        })
0 голосов
/ 04 ноября 2019

Firebase даст вам ответ в виде объекта. Нам нужно преобразовать это в массив и использовать его. Попробуйте приведенную ниже логику в начале вашей функции рендеринга, она может вам помочь.

const fetchedItems = [];
for(let key in this.state.addedItem) {
  fetchedItems.push({
     ...this.state.addedItem[key],
     id: key
  });
}

const items = fetchedItems.map(item => {
  return (
    <MyItem
       title={item.Title}
       description={item.Description}
       condition={item.Condition}
       url={item.URL}
     />
  );
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...