First of all we have to understand that JS is single threaded. Just one thread processes the code of your program. It can run only one piece of the code (lets say function) at a time. So keeping this fact in mind lets try to find out whats going on in your code.
async fetchNewJokes() {
let newJokes = [];
while (newJokes.length < 10) {
/*1*/ const {data} = await axios.get('https://icanhazdadjoke.com/', {
headers: {Accept: 'application/json'}});
/*2*/newJokes.push(data.joke);
this.setState({jokes: newJokes});
}
}
JS performs this function until it meets await on line \*1*\. Then it executes axios.get() and returns to the main code without waiting of result of axios.get().
Further it continues working with other code doing other useful things like rendering, processing user input and so on. At time to time it checks whether axios.get() finished or not.
When axios.get() finished it assign result to data value and continues performing this function from line \*2*\. On the next iteration of while loop it meets await again and repeat actions described above. And the same happens for every step of while loop.
Now lets look at the second code snippet.
fetchNewJokes() {
let newJokes = [];
while (newJokes.length < 10) {
axios.get('https://icanhazdadjoke.com/', {
headers: {Accept: 'application/json'}}).then(()=>{
newJokes.push(data.joke);
this.setState({jokes: newJokes});
});
}
}
JS performs this function and executes axios.get(). Now to execute .then() JS has to check at time to time whether axios.get() finished or not. But it can not!
JS thread is busy by performing while loop. You don't give it a time to do anything else. It continues to call axios.get() again and again without any possibility to check result. Furthermore since JS busy by doing the loop it doesn't have time for rendering. Loop consumes more and more resources. That's why browser freezes.
So what a solution? @gdh already gave you one of them. But if you need to make less changes to your code, just don't rely on result of Promise in the condition of the loop.
fetchNewJokes() {
for (let i=0; i<10; i++) {
axios.get('https://icanhazdadjoke.com/', {
headers: {Accept: 'application/json'}}).then(()=>{
this.setState({jokes: this.state.jokes.concat(data.joke)});
});
}
}
In this case the function executes axios.get() ten times and returns control to the main code.