简体   繁体   中英

How do I refresh a react component by clicking on a button outside the component?

I'm new to web development and decided to learn ReactJs. I am trying to create a random quote generator as a part of freecodecamp's frontend libraries project. Problem: I have a react component that fetches the quotes from a website and then displays a random quote on the screen. I also have a button outside of the component whose sole purpose is to get a new code and display it onscreen. How do I refresh the react component whenever I click the button? Any help is appreciated::D Here's my component:

 class MyComponent extends React.Component { constructor(props) { super(props); this.state = { quote: '' }; } componentDidMount() { fetch("https://type.fit/api/quotes").then(res => res.json()).then( (result) => { this.setState({ quote: result[Math.floor(Math.random() * result.length)] }); }, ) } render() { return ( <p id = 'reactQuote'>{this.state.quote.text}< /p> ); } } ReactDOM.render( MyComponent />, document.getElementById('text'))
 <div id="text"></div> <button id='new-quote'>New Quote</button>

create a component that would incapsulate both the button and your component, have the quote as state in the upper component and pass it down as props to your component, now when you press the button it will change the state in the upper component and it will be passed down to your component forcing it to refresh and display the new quote.

You can call a function on your button whenever you click on it. That function can be passed down to your button component as a prop.

function fetchData(){
     fetch("https://type.fit/api/quotes")
        .then(res => res.json())
        .then(
          (result) => {
            this.setState({
              quote: result[Math.floor(Math.random() * result.length)]
          });
        },
      )
}

<button id='new-quote' onClick={fetchData}>New Quote</button>

The component will automatically refresh when its state changes but the button and the text should be part of the component itself (or children of the component). An example (using a single component) would be:

 // your component class RandomQuoteMachine extends React.Component { constructor() { super(); this.state = { quotes: [], // here you store an array of quote objects currentQuote: null // here you store the quote object that is currently displayed }; this.getRandomQuote = this.getRandomQuote.bind(this) } // when the component mounts, fetch the quotes from the API componentDidMount() { fetch("https://type.fit/api/quotes") // fetch the entire list of quotes from the API.then(response => response.json()) // turn the response into a Javascript object.then(result => { // update the state this.setState({ quotes: result, currentQuote: result[Math.floor(Math.random() * result.length)] || null }); }); } getRandomQuote() { // randomly select a quote from the state const newQuote = this.state.quotes[Math.floor(Math.random() * this.state.quotes.length)] || null; // update the state with the new current quote this.setState({ currentQuote: newQuote }); } render() { return ( <div> <blockquote>{ this.state.currentQuote && this.state.currentQuote.text || '' }</blockquote> <p className = "author">{ this.state.currentQuote && this.state.currentQuote.author || 'unknown' }</p> <button onClick = { () => this.getRandomQuote() }>get a new quote from the list</button> </div> ); } } // mounting the component in the page ReactDOM.render( < RandomQuoteMachine / >, document.getElementById('app'))
 /* A bit of styling, just for presentation sake */ * { font-family: sans-serif; } blockquote { font-size: 2rem; font-style: italic; margin: 0; padding: 0.5rem 0.5rem 0.5rem 3rem; border-left: 3px solid #ccc; }.author { font-size: 1.2rem; padding-right: 0.5rem; text-align: right; }.author::before { content: "("; }.author::after { content: ")"; }
 <:-- Importing React and ReactDOM --> <script crossorigin src="https.//unpkg.com/react@17/umd/react.production.min:js"></script> <script crossorigin src="https.//unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script> <!-- This is where your component will be mounted --> <div id="app"> </div>

Or, if you prefer functional components and hooks:

 const RandomQuoteMachine = () => { const [quotes, setQuotes] = React.useState([]); const [currentQuote, setCurrentQuote] = React.useState(null); React.useEffect(() => { fetch("https://type.fit/api/quotes").then(response => response.json()).then(result => { setQuotes(result); setCurrentQuote(result[Math.floor(Math.random() * result.length)] || null); }) }, [setQuotes, setCurrentQuote]); const getRandomQuote = React.useCallback(() => { const newQuote = quotes[Math.floor(Math.random() * quotes.length)] || null; setCurrentQuote(newQuote) }, [quotes, setCurrentQuote]); return ( <div> <blockquote> { currentQuote && currentQuote.text || '' } </blockquote> <p className = "author"> { currentQuote && currentQuote.author || 'unknown' }</p> <button onClick = { () => getRandomQuote() }> get a new quote from the list </button> </div> ); } ReactDOM.render(<RandomQuoteMachine />, document.getElementById('app'));
 * { font-family: sans-serif; } blockquote { font-size: 2rem; font-style: italic; }.author { font-size: 1rem; text-align: right; }.author::before { content: "("; }.author::after { content: ")"; }
 <script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script> <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script> <div id="app"> </div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM