Closed DevNeves closed 1 year ago
Olá @DevNeves!
Passando para dizer que a issue foi visualizada e em até 10 dias úteis a análise será feita =)
Olá, @DevNeves.
Parabéns pelo esforço em construir a primeira aplicação do treinamento =)
troquei apenas a cor do layout (porque eu tentei fazer um layout do zero mas não consegui, pra mim ainda é dificil usar as classes do bootstrap)
Em relação à estilização, o uso do Bootstrap (ou qualquer lib CSS) é opcional.
Veja o que fica mais confortável pra você.
Só tenho duvida enquanto ao refatoramento que fiz, não sei se ficou da melhor maneira possivel
O mais importante vc já fez, que é fazer funcionar =)
Não se preocupe muito com refatoração agora. Refatoração é uma habilidade que é elevada com a prática.
Conforme vc praticar, vc vai percebendo aos poucos o que pode ser melhorado.
E você ainda irá praticar bastante no decorrer do treinamento =)
Vou deixar abaixo algumas observações sobre sua aplicação.
Uma boa decisão que você tomou foi a de deixar o input dentro da label. Isso faz com que o usuário não precise posicionar o mouse e clicar exatamente no input type radio. Basta clicar no texto da alternativa =)
Você entendeu que não era necessário manipular DOM dentro do forEach (um erro comum que algumas pessoas cometem). A ideia do forEach ali naquele momento era apenas calcular os pontos, exatamente como vc fez =)
Você inseriu uma barra com a pontuação total na mensagem dos pontos. Isso é bom porque traz mais clareza do progresso do usuário no quiz em relação a pontuação máxima.
Recomendo que ao invés de 4 espaços para indentação, use 2. E isso vale para qualquer linguagem (HTML, CSS, JS, etc).
Se um dia vc quiser enviar alguma sugestão ou modificação de artigo pro MDN, por exemplo, seu código terá que seguir o code-guideline deles:
E não só o MDN, mas muitas outras fontes recomendam que o código tenha 2 espaços ao invés de 4.
Seu olho irá cansar menos, pq suas linhas de código serão menos extensas, o que impacta na legibilidade e carga cognitiva na leitura.
À partir daqui, os exemplos do seu código que postarei abaixo já estarão formatados com 2 espaços, ao invés de 4.
Para configurar espaços no VSCode, dá uma olhada aqui:
Vc verá que nesse parágrafo, há um link para o get started de Settings do VSCode. Recomendo dar uma lida, mas não invista muito tempo nisso =)
Antes do usuário selecionar as alternativas, é bom que a primeira alternativa de cada pergunta esteja marcada por padrão. Para fazer isso, basta inserir o atributo checked no input type radio a ser marcado por padrão.
Isso é mais uma preferência pessoal, mas acho que incentiva o usuário a marcar a resposta que ele realmente acredita que seja a verdadeira.
Ao longo do código, há uma única inconsistência em relação ao espaçamento dentro do parenteses da função asnwers
:
// antes
const asnwers = ( ) => {
// ...
}
Todo o resto do código não há esse espaçamento adicional, a ideia aqui é considerar que é uma boa prática manter um padrão na maneira que você escreve o código. Uma sugestão é que você escolha uma das formas e seja consistente com essa escolha no decorrer do código. Por exemplo:
// depois
const asnwers = () => {
// ...
}
Futuramente, você pode usar uma ferramenta automatizada de formatação de código, mas nesse momento da sua jornada, eu recomendo que vc formate manualmente.
Isso vai "forçar" vc a adotar um estilo de escrita de código e ser consistente com esse estilo ao implementar suas aplicações.
Há um pequeno erro ortográfico na palavra asnwers
na sua aplicação, nada muito prejudicial, mas acredito que vale a pena mencionar, pois um nome ortograficamente correto pode facilitar no entendimento e integridade da aplicação. O nome após a correção será answers
e ela será ajustada nas seguintes ocasiões:
// antes
const correctAsnwers = ['B', 'A', 'B', 'A', 'A']
const asnwers = ( ) => {
const userAsnwers = [
//...
]
return userAsnwers
}
const userCorrectAsnwers = event => {
// ...
const isACorrectAsnwers = (asnwer, i) => {
if (asnwer === correctAsnwers[i]){
// ...
}
}
asnwers().forEach(isACorrectAsnwers)
// ...
}
form.addEventListener('submit', userCorrectAsnwers)
// depois
const correctAnswers = ['B', 'A', 'B', 'A', 'A']
const answers = ( ) => {
const userAnswers = [
//...
]
return userAnswers
}
const userCorrectAnswers = event => {
// ...
const isACorrectAnswers = (answer, i) => {
if (answer === correctAnswers[i]){
// ...
}
}
answers().forEach(isACorrectAnswers)
// ...
}
form.addEventListener('submit', userCorrectAnswers)
Se fizer sentido para você, a função insertPoints
não precisa existir no código. A ideia aqui é que você pode economizar algumas linhas de código e simplificá-lo ao todo se você optar por fazer com que showPoints.textContent
receba o conteúdo correspondente para cada situação, sem necessitar de uma função para ser invocada e que esse conteúdo seja passado como parâmetro dessa função. Ficaria assim:
// antes
const insertPoints = (text) => {
showPoints.textContent = `${text}`
}
const userCorrectAsnwers = event => {
// ...
insertPoints(`Você acertou ${points}/5 perguntas!`)
if (points === 0) {
insertPoints(`Você acertou nenhuma das 5 perguntas )=`)
}
}
// depois
const userCorrectAsnwers = event => {
// ...
showPoints.textContent = `Você acertou ${points}/5 perguntas!`
if (points === 0) {
showPoints.textContent = `Você acertou nenhuma das 5 perguntas )=`
}
}
Nessa função, há algumas observações que podem ser feitas. De início, a const userAnswers
, que está sendo usada para armazenar as alternativas que o usuário escolher na aplicação, não necessariamente precisa ficar dentro de uma função, se você achar interessante, você pode mover a const userAnswers
para dentro da função userCorrectAnswers
e remover essa função answers
. A vantagem aqui é justamente economizar algumas linhas de código e deixá-lo mais simples de entender, mesmo com uma função a menos, o funcionamento do código se aprimora. Ficaria assim:
// antes
const answers = () => {
const userAnswers = [
form.inputQuestion1.value,
form.inputQuestion2.value,
form.inputQuestion3.value,
form.inputQuestion4.value,
form.inputQuestion5.value,
]
return userAnswers
}
// depois
const userCorrectAnswers = event => {
event.preventDefault()
// ...
const userAsnwers = [
form.inputQuestion1.value,
form.inputQuestion2.value,
form.inputQuestion3.value,
form.inputQuestion4.value,
form.inputQuestion5.value,
]
userAsnwers.forEach(isACorrectAsnwers)
// ...
}
Um princípio que gosto de seguir ao nomear é:
getName
, setName
, incrementCounter
;user
, score
, color
. is
, has
ou should
. isOdd
, hasSevenItems
, shouldUpdate
.Considerando isso...
Se fizer sentido para você, a let points
, a função isACorrectAnswers
e a função userCorrectAnswers
que você usou no código podem ter seus nomes substituidos por score
, isCorrectAnswer
e handleFormSubmit
respectivamente. O intuito aqui é fazer com que os nomes diminuam de comprimento e ao mesmo tempo mantenham o sentido original e mais próximo em relação a seu papel no código. Ficaria assim:
// antes
const userCorrectAnswers = event => {
event.preventDefault()
let points = 0
const userAnswers = [
// ...
]
const isACorrectAsnwers = (answer, i) => {
if (answer === correctAsnwers[i]){
points += 1
}
}
userAnswers.forEach(isACorrectAnswers)
showPoints.textContent = `Você acertou ${points}/5 perguntas!`
if (points === 0) {
// ...
}
}
// depois
const handleFormSubmit = event => {
event.preventDefault()
let score = 0
const userAnswers = [
// ...
]
const isCorrectAnswer = (answer, i) => {
if (answer === correctAnswers[i]){
score += 1
}
}
userAnswers.forEach(isCorrectAnswer)
showPoints.textContent = `Você acertou ${score}/5 perguntas!`
if (score === 0) {
// ...
}
}
Feito esses ajustes, vou te mostrar duas abordagens de refactoring envolvendo a criação de algumas funções para deixarmos o código mais conciso em relação a cada trecho de seu funcionamento. O que quero que você entenda, nesse primeiro momento, é o conceito por trás delas. Sabendo disso, observe o código abaixo:
let score = 0
const isCorrectAnswer = (answer, i) => {
if (answer === correctAnswers[i]){
score += 1
}
}
userAnswers.forEach(isCorrectAnswer)
No código acima, está a lógica que você usou para calcular a pontuação. A sugestão aqui, é criarmos uma nova função específica para lidar com a pontuação, como vai ser uma função para obter a pontuação, um nome interessante para ela seria algo como getUserScore
. Nessa nova função, podemos simplificar a lógica de obter os pontos ao declarar score
dentro dessa função e fazer com que a função retorne score
. Ficaria assim:
const getUserScore = userAnswers => {
let score = 0
userAnswers.forEach((answer, i) => {
if (answer === correctAnswers[i]) {
score += 1
}
})
return score
}
Sendo assim, você pode invocar a função getUserScore()
dentro da função que ela estava anteriormente, ou seja, em handleFormSubmit
recebendo o array armazenado por userAnswers
como argumento. Ficaria assim:
const handleFormSubmit = event => {
// ...
const score = getUserScore(userAnswers)
// ...
}
A segunda abordagem é a seguinte. Vamos criar uma função especificamente para obter a resposta do usuário. Essa função pode se chamar getUserAnswers
, nela podemos criar uma const userAnswer
que vai receber uma expressão que pega o valor de cada inputQuestion do form. userAnswers
vai receber um array vazio que será preenchido após percorrermos cada item dentro do array correctAnswers
por meio do método forEach, e por fim, esse valor que contém as respostas do usuário e que foi armazenado em userAnswers
vai ser retornado. Ficaria assim:
const getUserAnswers = () => {
const userAnswers = []
correctAnswers.forEach((_, index) => {
const userAnswer = form[`inputQuestion${index + 1}`].value
userAnswers.push(userAnswer)
})
return userAnswers
}
Por fim, você também pode invocar essa função dentro da função handleFormSubmit
que o código funcionará normalmente =)
const handleFormSubmit = event => {
event.preventDefault()
const userAnswers = getUserAnswers()
const score = getUserScore(userAnswers)
// ...
}
Agora, a sugestão aqui é criarmos uma nova função responsável unicamente pela manipulação de DOM e invocarmos ela nessa função também. Atualmente, a função handleFormSubmit
também é responsável pelas linhas de manipulação de DOM, e para deixar mais claro o papel de apenas passar informações para a frente, podemos criar uma função showScore
que vai ser unicamente responsável pela manipulação de DOM e invocar essa função em handleFormSubmit
. Assim, além de facilitar o fluxo de leitura, você separa mais as responsabilidades, agora que não tem manipulação de DOM em handleFormSubmit
, essa função agora é apenas responsável por passar informações para frente, para que outras partes da aplicação executem o que precisa ser executado, como por exemplo, exibir a pontuação. Ficaria assim:
const showScore = score => {
showPoints.textContent = `Você acertou ${score}/5 perguntas!`
if (score === 0) {
showPoints.textContent = `Você acertou nenhuma das 5 perguntas )=`
}
}
const handleFormSubmit = event => {
event.preventDefault()
const userAnswers = getUserAnswers()
const score = getUserScore(userAnswers)
showScore(score)
}
Nas aulas seguintes, você verá outras formas de refatorar o código dessa aplicação.
Mais uma vez, parabéns pelo esforço =)
As observações fizeram sentido?
Muito obrigado aprendi bastante (=
Só não consegui entender essa parte
const getUserAnswers = () => {
const userAnswers = []
correctAnswers.forEach((_, index) => {
const userAnswer = form[`inputQuestion${index + 1}`].value
userAnswers.push(userAnswer)
})
return userAnswers
}
Essa const userAnswer, de onde vem esse 'inputQuestion' e porque ele recebe um index + 1 ?
Olá @DevNeves
const getUserAnswers = () => {
const userAnswers = []
correctAnswers.forEach((_, index) => {
const userAnswer = form[`inputQuestion${index + 1}`].value
userAnswers.push(userAnswer)
})
return userAnswers
}
Certo, vamos detalhar o que está acontecendo nessa função passo por passo então. Primeiramente a ideia é criar uma função para obter as respostas marcadas pelo usuário do quiz, dessa forma, você não vai mais precisar da const userAnswers
armazenando cada resposta de forma enumerada, pois a função fará o papel dele e de forma dinâmica. Observe abaixo como é obtido o valor de cada input do usuário:
const userAnswers = [
form.inputQuestion1.value, // <-- Cada valor é obtido por meio da notação de ponto, e ela segue um padrão 1...2...3...4
form.inputQuestion2.value,
form.inputQuestion3.value,
form.inputQuestion4.value,
]
Sabendo disso, criaremos uma função getUserAnswers
que não precisa receber nenhum parâmetro, pois o que ela vai usar ou está dentro de seu escopo, ou vai estar num escopo global, como correctAnswers
, por exemplo. Depois, podemos criar uma const userAnswers
que vai armazenar um array vazio, de início, a função seria concebida da seguinte forma.
const getUserAnswers = () => {
const userAnswers = []
}
Agora, vamos pegar a const correctAnswers
que armazena as respostas corretas para cada pergunta, essa const foi declarada no início do código, ou seja, no escopo global, e com ela, nós vamos encadeá-la num forEach
, você já viu anteriormente que o forEach pode receber três parametros sendo eles o primeiro, o item atual da iteração, o segundo, o index que corresponde ao item e o ultimo o array inteiro que está sendo iterado, mas nessa situação em específico, nós queremos apenas o segundo parâmetro, o index. Tendo em vista que não vamos usar o primeiro parâmetro, basta colocar um _
na posição que estaria o primeiro parâmetro e colocar o index
(que é o segundo parâmetro) logo em seguida, ficaria assim:
correctAnswers.forEach((_, index) => {
// ...
})
Dessa forma, vamos declarar uma const userAnswers
que vai pegar cada resposta do usuário de forma dinâmica, lembra que eu mostrei logo no início aqui desse comentário que cada alternativa estava sendo selecionada por meio da notação de ponto? Então, se você observar o trecho abaixo, verá que o que estava acontecendo nas quatro linhas de cada input, também está acontecendo dinamicamente em uma única linha de código. A ideia aqui, é que userAnswer
vai armazenar um form que na notação de colchetes vai pegar o inputQuestion
, passar pelo seu index
e pegar o valor (que é a resposta marcada pelo usuário para aquele input), logo, por estar num método forEach, o javascript vai fazer a mesma coisa para cada um dos inputs, mas dessa vez, será o segundo input devido ao incremento de index + 1 para cada vez. E assim por diante, na terceira vez, ele pegará o valor do terceiro input e por fim, o último.
const userAnswer = form[`inputQuestion${index + 1}`].value // Nesse trecho, o valor de cada resposta do usuário do quiz é armazenada em userAnswer
Após isso, por meio do método push, a const userAnswers
que foi declarada vazia, terá seu array preenchido com os inputs obtidos no trecho de código acima, e por fim, esse valor que contém as respostas do usuário e que foi armazenado em userAnswers
vai ser retornado. Se você quiser observar isso sendo feito na prática, você pode executar um console.log(userAnswers)
da seguinte forma:
const getUserAnswers = () => {
const userAnswers = []
correctAnswers.forEach((_, index) => {
const userAnswer = form[`inputQuestion${index + 1}`].value
userAnswers.push(userAnswer)
})
console.log(userAnswers) // Respostas marcadas no quiz aparecerão no console
return userAnswers
}
Consegui esclarecer a sua dúvida? Se ainda assim não tiver entendido, sinta-se livre para comentar logo abaixo aqui na issue que estarei disposto a te ajudar!
Valeu pela ajuda.
No momento que eu fiz o comentario eu não tinha entendido direito como funcionava, mas depois fiquei vendo e revendo e conseguir compreender. Mas agora com a sua resposta me esclareceu mais ainda muito obrigado.
Ok! Vou fechar a issue aqui, qualquer coisa, sinta-se livre para abrir uma nova.
As cores da sua versão da aplicação são diferentes das cores da aplicação mostrada na aula?
Sim
Sua aplicação contém funcionalidades que não foram mostradas nas aulas da aplicação?
Sim
Sua aplicação contém funcionalidades da linguagem que não foram mostradas no CJRM até aqui?
Não
Link do repositório da aplicação (ou pasta pública no Google Drive)
https://github.com/DevNeves/Quiz-Interativo
Maiores dificuldades durante a implementação
troquei apenas a cor do layout (porque eu tentei fazer um layout do zero mas não consegui, pra mim ainda é dificil usar as classes do bootstrap) e inplementei a pontuação, eu ja tinha visto o video em que o roger mostra como checar as respostas mas, no dia seguinte eu fiz sozinho sem consultar em nada.
OBS: Ainda não vi o resto dos videos sobre esse quiz. Então não sei a maneira que o Roger aplicou a pontuação. Vou esperar a análise para dar andamento no resto do quiz (com o setTimeout setInterval que são conteudos que ainda não vi)
Só tenho duvida enquanto ao refatoramento que fiz, não sei se ficou da melhor maneira possivel
Menores dificuldades durante a implementação
adição dos eventos, forEach, referenciando elementos