Search code examples
javascriptreactjsaxiosreact-hooksreact-component

How to reload a component without refreshing the entire page?


Any help would be greatly appreciated, I've built out a simple quote generator project in React and would like the new quote to load without rendering the entire page. Currently, im using hooks and the quotes state resides in one component is it possible to reload/refresh state from another component using a click handler?

Project link: https://codesandbox.io/s/quote-generator-czffn?file=/src/components/buttons/Buttons.js

How it's currently reloading, using a refreshPage function. Thanks!

import React from 'react';

const Buttons = ({ quotes, getNewQuote }) => {
  const twitterUrl = `https://twitter.com/intent/tweet?text=${quotes.joke}`;
  //   console.log(twitterUrl);

  function refreshPage() {
    window.location.reload(false);
  }

  return (
    <div className='button-container'>
      <button
        onClick={() => window.open(twitterUrl, '_blank')}
        className='twitter-button'
        id='twitter'
        tittle='Tweet This!'
      >
        <i className='fab fa-twitter'></i>
      </button>
      <button id='new-quote' onClick={refreshPage}>
        New Quote
      </button>
    </div>
  );
};

export default Buttons;

Solution

  • If the quote is to show a new quote without refreshing the entire page, remove the axios request from the hook and put it in its own function.

      const getQuotes = () => {
        axios
          .get("https://geek-jokes.sameerkumar.website/api?format=json")
          .then(res => {
            setQuotes(res.data);
            // console.log(res.data);
          })
          .catch(err => console.log(err));
      }
    
    // ...
    
    <Buttons onClick={getQuotes} quotes={quotes} />
    

    Then adjust the button to get use this function when it's clicked:

    const Buttons = ({ quotes, getNewQuote, onClick }) => {
    
    // ...
    
    <button id="new-quote" onClick={onClick}>
      New Quote
    </button>
    

    You might want to add an animation while it's retrieving things as well with a useState for loading, but this should be a good start.

    ======= UPDATE =======

    Here's also an example code to see how it could work. Click Run code snippet to see it working.

    const { useState, useEffect } = React;
    
    const Quote = props => {
      return <section>
        <blockquote>
          {JSON.stringify(props.quote)}
        </blockquote>
        <button onClick={props.onClick}>Get Quote</button>
      </section>
    }
    
    const App = () => {
      const [quotes, setQuotes] = useState(null);
      const [loading, setLoading] = useState(true);
      
      const getQuotes = () => {
        setLoading(true);
        axios
          .get("https://geek-jokes.sameerkumar.website/api?format=json")
          .then(res => {
            if (res.data && res.data.joke) {
              setQuotes(res.data.joke);
            }
            setLoading(false);
          })
          .catch(err => {
            console.log(err);
            setLoading(false);
          });
      }
      
      useEffect(() => {
        getQuotes();
      }, []);
    
      return loading ? <p>Loading...</p> : <Quote quote={quotes} onClick={getQuotes} />
    }
    
    
    ReactDOM.render(<App />, document.querySelector('#root'));
    body {
      background: #efefef;
      font-family: Arial, sans-serif;
      padding: 20px;
      margin: 0;
      display: flex;
      justify-content: center;
      align-items: center;
    }
    
    section {
       background: white;
       border-radius: 6px;
       display: block;
       padding: 10px;
    }
    
    blockquote {
      padding: 10px;
      margin: 0 0 10px 0; 
      border-bottom: 1px solid #efefef;
      font-size: 21px;
    }
    
    button {
    border-radius: 4px;
    background: blue;
    color: white;
    border: none;
    height: 40px;
    padding: 0 12px;
    font-size: 14px;
    }
    
    p {
      display: block;
      max-width: 80px;
      background: white;
      border-radius: 6px;
      padding: 20px;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
    <script src="https://unpkg.com/[email protected]/dist/axios.min.js"></script>
    
    <div id="root"></div>