2

I am making a request to axios and receiving some data, which then I setState to my component's state:

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

So my state, which had state property addedItem now gets objs as value. Then, in my render() method I am rendering a child component, which receives props from my state(whose properties updated through componentDidMount):

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

This works fine, however I can see the result of child component displayed, only if I reload the browser. How can I make the app reload automatically whenever a state property (in my case addedItem) changes ? Which lifecycle method should I use to rerender the DOM immidiately when the state property changes ?

The full component code is below:

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;

the child MyItem component:

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;
SuleymanSah
  • 17,153
  • 5
  • 33
  • 54

2 Answers2

0

Firebase will gives you the response in the form of object. We need to convert this to array and use it. Try the below logic at the start of your render function:

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}
     />
  );
});
halfer
  • 19,824
  • 17
  • 99
  • 186
Gangadhar Gandi
  • 2,162
  • 12
  • 19
  • Thanks for helping. I have solved this in the following way : just added window.location.reload() method in order rerender the dom after image upload to FIre Storage was done. – Murad Eminov Nov 04 '19 at 10:14
0

I solved this by adding window.location.reload() method, which triggers the rerendering of DOM immediately after the user image was successfully uploaded to the FIrebase Database. So here is the code:

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