组件状态更改后如何重新呈现DOM?

时间:2019-11-04 09:37:44

标签: reactjs axios react-lifecycle

我正在向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}
        />
      )
    })
  }

这正常工作,但是只有重新加载浏览器后,我才能看到显示的子组件的结果。每当状态属性(在我的情况下,为addItem)更改时,如何使应用自动重新加载?当state属性更改时,应立即使用哪种生命周期方法立即重新渲染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 :(得分:0)

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}
     />
  );
});

答案 1 :(得分:0)

我通过添加window.location.reload()方法解决了此问题,该方法在用户图像成功上传到FIrebase数据库后立即触发DOM的重新呈现。所以这是代码:

instance.post('/myitems.json', myNewItem)
                        .then(response => {window.location.reload();} )
                        .then(error => {
                            console.log(error);
                        })