配套影片教程
影片載入中。。。
專案程式碼結構
前言
React 框架的優雅不言而喻,元件化的程式設計思想使得React框架開發的專案程式碼簡潔,易懂,但早期 React 類元件的寫法略顯繁瑣。React Hooks 是 React 16。8 釋出以來最吸引人的特性之一,它簡化了原有程式碼的編寫,是未來 React 應用的主流寫法。
本文透過一個實戰小專案,手把手從零開始帶領大家快速入門React Hooks。本專案線上演示地址:
在本專案中,會用到以下知識點:
React 元件化設計思想
React State 和 Props
React 函式式元件的使用
React Hooks useState 的使用
React Hooks useEffect 的使用
React 使用 Axios 請求遠端介面獲取問題及答案
React 使用Bootstrap美化介面
Hello React
(1)安裝node。js 官網連結
(2)安裝vscode 官網連結
(3)安裝 creat-react-app 功能元件,該元件可以用來初始化一個專案, 即按照一定的目錄結構,生成一個新專案。 開啟cmd 視窗 輸入:
npm install ——g create-react-app npm install ——g yarn
(-g 代表全域性安裝)
如果安裝失敗或較慢。需要換源,可以使用淘寶NPM映象,設定方法為:
npm config set registry https://registry。npm。taobao。org
設定完成後,重新執行
npm install ——g create-react-appnpm install ——g yarn
(4)在你想建立專案的目錄下 例如 D:/project/ 開啟cmd命令 輸入
create-react-app react-exam
去使用creat-react-app命令建立名字是react-exam的專案
安裝完成後,移至新建立的目錄並啟動專案
cd react-examyarn start
一旦執行此命令,localhost:3000新的React應用程式將彈出一個新視窗。
專案目錄結構
右鍵react-exam目錄,使用vscode開啟該目錄。 react-exam專案目錄中有一個/public和/src目錄,以及node_modules,。gitignore,README。md,和package。json。
在目錄/public中,重要檔案是index。html,其中一行程式碼最重要
該div作為我們整個應用的掛載點
/src目錄將包含我們所有的React程式碼。
要檢視環境如何自動編譯和更新您的React程式碼,請找到檔案/src/App。js: 將其中的
修改為
儲存檔案後,您會注意到localhost:3000編譯並重新整理了新資料。
React-Exam專案實戰
1。 首頁製作
1。安裝專案依賴,在package。json中新增:
“dependencies”: { “@testing-library/jest-dom”: “^4。2。4”, “@testing-library/react”: “^9。3。2”, “@testing-library/user-event”: “^7。1。2”, “react”: “^16。13。1”, “react-dom”: “^16。13。1”, “react-scripts”: “3。4。1”, “axios”: “^0。19。2”, “bootstrap”: “^4。5。0”, “he”: “^1。2。0”, “react-loading”: “^2。0。3”, “reactstrap”: “^8。4。1” },
執行命令:
yarn install
修改index。js,匯入bootstrap樣式
import “bootstrap/dist/css/bootstrap。min。css”;
修改App。css程式碼
html { width: 80%; margin-left: 10%; margin-top: 2%;}。ansButton { margin-right: 4%; margin-top: 4%;}
修改App。js,引入Quiz元件
import React from ‘react’;import ‘。/App。css’import { Quiz } from ‘。/Exam/Quiz’;function App() { return (
在專案src目錄下新增Exam目錄,Exam目錄中新建Quiz。js
Quiz元件的定義如下: Quiz。js,引入開始頁面元件Toggle。
import React, { useState } from “react”;import { Toggle } from “。/Toggle”;export const Quiz = () => { const [questionData, setQuestionData] = useState([]); const questions = questionData。map(({ question }) => [question]); const answers = questionData。map(({ incorrect_answers, correct_answer }) => [correct_answer, incorrect_answers]。flat() ); return ( <>
Toggle。js,點選開始按鈕,透過axios訪問遠端介面,獲得題目及答案。
import React from “react”;import axios from “axios”;import ToggleHeader from “。/ToggleHeader”;import { Button, Form,} from “reactstrap”;export const Toggle = ({ setQuestionData,}) => { const getData = async () => { try { const incomingData = await axios。get( `https://opentdb。com/api。php?amount=10&category=18&difficulty=easy&type=multiple` ); setQuestionData(incomingData。data。results); } catch (err) { console。error(err); } }; return ( <>
ToggleHeader。js
import React from “react”;import { Jumbotron, Container} from “reactstrap”;export default function ToggleHeader() { return ( 計算機知識小測驗
https://opentdb。com/api。php介面返回的json資料格式為
{ “response_code”: 0, “results”: [{ “category”: “Science: Computers”, “type”: “multiple”, “difficulty”: “easy”, “question”: “The numbering system with a radix of 16 is more commonly referred to as ”, “correct_answer”: “Hexidecimal”, “incorrect_answers”: [“Binary”, “Duodecimal”, “Octal”] }, { “category”: “Science: Computers”, “type”: “multiple”, “difficulty”: “easy”, “question”: “This mobile OS held the largest market share in 2012。”, “correct_answer”: “iOS”, “incorrect_answers”: [“Android”, “BlackBerry”, “Symbian”] }, { “category”: “Science: Computers”, “type”: “multiple”, “difficulty”: “easy”, “question”: “How many values can a single byte represent?”, “correct_answer”: “256”, “incorrect_answers”: [“8”, “1”, “1024”] }, { “category”: “Science: Computers”, “type”: “multiple”, “difficulty”: “easy”, “question”: “In computing, what does MIDI stand for?”, “correct_answer”: “Musical Instrument Digital Interface”, “incorrect_answers”: [“Musical Interface of Digital Instruments”, “Modular Interface of Digital Instruments”, “Musical Instrument Data Interface”] }, { “category”: “Science: Computers”, “type”: “multiple”, “difficulty”: “easy”, “question”: “In computing, what does LAN stand for?”, “correct_answer”: “Local Area Network”, “incorrect_answers”: [“Long Antenna Node”, “Light Access Node”, “Land Address Navigation”] }]}
程式執行效果:
當前專案目錄結構為:
2。 問題展示頁面
Quiz。js,新增toggleView變數用來切換檢視。
const [toggleView, setToggleView] = useState(true);
Quiz。js,其中Question和QuestionHeader 元件,參見後面。
import { Question } from “。/Question”;import { Jumbotron } from “reactstrap”;import QuestionHeader from “。/QuestionHeader”;。。。export const Quiz = () => { var [index, setIndex] = useState(0); const [questionData, setQuestionData] = useState([]);。。。 return ( <> {toggleView && (
使用index控制題目索引
var [index, setIndex] = useState(0);
修改Toggle。js 獲取完遠端資料,透過setToggleView(false);切換檢視。
export const Toggle = ({ setQuestionData, setToggleView, setIndex,}) => { 。。。 return ( <>
QuestionHeader。js程式碼: 同樣的,點選 返回首頁按鈕 setToggleView(true),切換檢視。
import React from “react”;import { Button } from “reactstrap”;export default function QuestionHeader({ setToggleView, category }) { return ( <> > );}
Question。js程式碼 接受父元件傳過來的question物件,並顯示。 其中he。decode是對字串中的特殊字元進行轉義。
import React from “react”;import he from “he”;export const Question = ({ question }) => { // he is a oddly named library that decodes html into string values var decode = he。decode(String(question)); return (
{decode}
程式執行效果: 首頁
點選開始後,顯示問題:
當前專案目錄結構為:
3。 載入等待動畫
新增LoadingSpin。js
import React from “react”;import { Spinner } from “reactstrap”;export default function LoadingSpin() { return ( <>
修改Quiz。js
import LoadingSpin from “。/LoadingSpin”;export const Quiz = () => { const [isLoading, setLoading] = useState(false); return ( <> {toggleView && (
修改Toggle。js
export const Toggle = ({。。。 setLoading,}) => { const getData = async () => { try { setLoading(true); const incomingData = await axios。get( `https://opentdb。com/api。php?amount=10&category=18&difficulty=easy&type=multiple` ); setQuestionData(incomingData。data。results); setLoading(false); } catch (err) { console。error(err); } }; 。。。};
執行效果:
目前程式碼結構:
4。 實現下一題功能
新增Answer。js,使用者點選下一題按鈕,修改index,觸發主介面重新整理,顯示下一題:
import React from “react”;import { Button } from “reactstrap”;export const Answer = ({ setIndex, index }) => { function answerResult() { setIndex(index + 1); } return ( );};
修改Quiz。js,新增Answer元件:
import { Answer } from “。/Answer”;。。。 {!toggleView && (isLoading ? (
執行效果:
點選下一題:
5。 實現選項展示
新增AnswerList。js。 透過屬性answers傳進來的選項列表,需要被打亂順序(shuffle )
import React from “react”;import { Answer } from “。/Answer”;export const AnswerList = ({ answers, index, setIndex }) => { if (answers) var correctAns = answers[0]; const shuffle = (array) => { return array。sort(() => Math。random() - 0。5); }; const arrayCheck = (arg) => { return Array。isArray(arg) ? arg : []; }; return ( <> {shuffle(arrayCheck(answers))。map((text,ind) => (
修改Answer。js
import React from “react”;import he from “he”;import { Button } from “reactstrap”;export const Answer = ({ text, correct, setIndex, index }) => { function answerResult() { setIndex(index + 1); } var decode = he。decode(String(text)); return ( );};
修改Quiz。js
// import { Answer } from “。/Answer”;import { AnswerList } from “。/AnswerList”;export const Quiz = () => {。。。 return ( <> 。。。 {!toggleView && (isLoading ? (
執行效果:
專案結構:
6。 記錄使用者成績
修改quiz。js,新增setResult,並傳遞給AnswerList
export const Quiz = () => { var [result, setResult] = useState(null);。。。 return ( <> 。。。 {!toggleView && (isLoading ? (
修改AnswerList。js,傳遞setResult
import React from “react”;import { Answer } from “。/Answer”;export const AnswerList = ({ answers, index,setResult, setIndex }) => {。。。 return ( <> {shuffle(arrayCheck(answers))。map((text,ind) => (
修改Answer。js,使用者點選選項,回撥setResult,通知Quiz元件,本次選擇是對是錯。
import React from “react”;import { Button } from “reactstrap”;import he from ‘he’export const Answer = ({ text, correct, setResult,setIndex, index }) => { function answerResult() { setIndex(index + 1); correct === text ? setResult(true) : setResult(false); } var decode = he。decode(String(text)); return ( );};
修改Quiz。js,放一個隱藏的GameOver元件,每當index發生變化的時候,觸發GameOver中的useEffect程式碼,累計使用者答對題目的數目(setRight)
import GameOver from “。/GameOver”;export const Quiz = () => { const [right, setRight] = useState(0); const [gameIsOver, setGameOver] = useState(false); return ( <> {toggleView && (
新增GameOver。js元件,當index === quizLength && index時,setGameOver(true)設定遊戲結束,顯示使用者得分。
import React, { useEffect } from “react”;export default function GameOver({ right, setRight, setGameOver, index, quizLength, result,}) { useEffect(() => { if (result === true) { setRight(right + 1); } if (index === quizLength && index) { setGameOver(true); } }, [index]); return
;}7。 遊戲結束,展示使用者得分
新增ScoreBoard。js
import React from “react”;export const ScoreBoard = ({ finalScore, right }) => { // if index === 0 then right === 0 ——> this way when index is reset in toggle so is right answers const scoreFormatted = score => { if (score === 1) { return 100; } else if (score === 0) { return 0; } else { return score。toFixed(2) * 100; } } return ( <> <>
Correct Answers: {right}
Final Score: %{scoreFormatted(finalScore)}
>
謝謝使用
> );};ScoreHeader。js
import React from “react”;import { Button } from “reactstrap”;export default function ScoreHeader({ setGameOver, setToggleView }) { return ( );}
修改Quiz。js,當gameIsOver 變數為true時,顯示得分頁面。
import { ScoreBoard } from “。/ScoreBoard”;import ScoreHeader from “。/ScoreHeader”;export const Quiz = () => {。。。 return ( <> {!toggleView && !gameIsOver && (isLoading ? (