How to display nothing if nothing loads up

Viewed 118

I'm setting user_id from my Context.Provider and album_id from my data from my database. If these two variables are set and equal each other I'm adding two buttons (Edit and Delete) and setting a loading spinner if the values aren't set yet.

Here I'm grabbing the data from the database and setting it to author_id as well as grabbing the Context.Provider from another component to set to user_id.

this.state = {
      loading: false,
    };

    componentDidMount() {
      const { match: { params} } = this.props;
      console.log('COMPONENT HAS MOUNTED');

      this.setState({ loading : true });
      fetch(`http://localhost:8000/albums/${params.albumId}`)
        .then((response) =>
          response.json())
        .then((data) => {
              this.setState({ albums : data });
            }).then(()=> {
            this.setState({ loading : false });
           }).catch((error) => {
                console.log("Error " + error)
              })
    }

render() {
    const user_id = this.context.user ? this.context.user.sub : null;
    const author_id = this.state.albums[0] ? this.state.albums[0].author : null;
    const shouldRenderButton = user_id && author_id && user_id === author_id;

Album.contextType = Auth0Context;

If both these variables are both set and equal each other I'm rendering two buttons (Edit and Delete):

<div>
    {shouldRenderButton ?
    <Container>
    <Row xs="2">
    <Col><Button color="primary" size="sm">Edit</Button></Col>
    <Col><Button color="danger" size="sm">Delete</Button></Col>
    </Row>
    </Container> : <Spinner size="sm" color="secondary" />
    }
 </div>

While I'm waiting for the data to get added I have a spinner. What I want to do is if the album_id doesn't equal the user_id I would like to display nothing and stop the spinner. As you can see I have loading set to false at first, set to true before the data is fetched and false once the data is fetched but I'm not sure how to use that in my code.

4 Answers

You should be able to use .finally() as cited in this here. Basically, you are saying, whether 200 or error (4XX and so on) you need to stop the spinner.

(NEWLY UPDATED)

const shouldRenderButton = user_id && author_id && user_id === author_id;

can be converted to

const shouldRenderButton = !this.state.loading && (user_id && author_id && user_id === author_id);

the .then()s can be changed to

.then((data) => {
          this.setState({ 
              albums : data, 
              loading : false 
          });
        })
.catch((error) => {
          this.setState({ loading : false });
          console.log("Error " + error)
          })

(/NEWLY UPDATED)

let me know if that works.

If I understand correctly, you can use loading along with shouldRenderButton, something like:

<div>
  {
    loading ?
      <Spinner size="sm" color="secondary" />
    :
      shouldRenderButton ?
        <Container>
          <Row xs="2">
            <Col><Button color="primary" size="sm">Edit</Button></Col>
            <Col><Button color="danger" size="sm">Delete</Button></Col>
          </Row>
        </Container>
      :
        <div></div>
  }
</div>

Update

After a rewrite, this should work with the code above:

componentDidMount() {
  const { match: { params} } = this.props;
  console.log('COMPONENT HAS MOUNTED');
  this.setState({ loading: true });

  fetch(`http://localhost:8000/albums/${params.albumId}`)
    .then((response) => response.json())
    .then((data) => this.setState({ albums: data, loading: false }) )
    .catch((error) => {
      this.setState({ loading : false });
      console.log("Error " + error);
    });
}

render() {
  let { loading } = this.state
  const user_id = this.context.user ? this.context.user.sub : null;
  const author_id = this.state.albums[0] ? this.state.albums[0].author : null;
  const shouldRenderButton = user_id && author_id && user_id === author_id;

Ok based on your code you should do something like this in your render:

if (loading) return <Spinner />
return (
  shouldRenderButton ? <YourJsxFragment /> : null
)

IMO using nested ternaries makes code unreadable so I like to use if statements to return things instead of wrapping everything inside just one return statement.

You can return null if you don't want to show anything.

This will make sure loading sets to false after albums gets updated.

  componentDidMount() {
    const { match: { params} } = this.props;
    this.setState({ loading: true });
    fetch(`http://localhost:8000/albums/${params.albumId}`)
      .then((response) => response.json())
      .then((data) => this.setState({
        albums: data
      }, () => {
        this.setState({ loading: false }); // here
      }))
      .catch((error) => {
        this.setState({ loading : false });
      });
  }

Now, Based on your requirements, hopefully, this will get your job done and display nothing & stop the spinner.

render() {
    const { loading } = this.state;
    const user_id = this.context.user ? this.context.user.sub : null;
    const author_id = this.state.albums[0] ? this.state.albums[0].author : null;
    const shouldRenderButton = user_id && author_id && user_id === author_id;
    return (
      <>
        {loading && <Spinner size="sm" color="secondary" />}
        {shouldRenderButton && !loading && (
        <Container>
          <Row xs="2">
            <Col><Button color="primary" size="sm">Edit</Button></Col>
            <Col><Button color="danger" size="sm">Delete</Button></Col>
          </Row>
        </Container>
        )}
      </>
    )
    }
  }
Related