Next. jsのApp routerで、useReducerを使ってコンポーネント間でpropsを受け渡したい
これはNext.jsで実装した簡単な英語クイズアプリです。
10問解くと、リザルト画面に自分の回答が表示されます。
question/page.jsx
で生成した'addAnswers'をresult/page.jsx
で表示させたいのですが、useRudecerへの理解が追いついておらずどう実装すればいいのか分かりません。
おそらくaddAnswers.jsx
とresult/page.jsx
をちょっといじればできるんだと思うのですが、なかなかうまくいきません。
result/page.jsx
に自分のこれまでの回答が一覧で表示されるようにするにはあとどこを修正すれば完成しますか?
'use client'
const data = [
{
'question': 'Ms. Ortega’s development team contributed ——– to the successful launch of the newest mobile application.',
'choices': ['automatically', 'substantially', 'sharply', 'accordingly'],
'answer': 'substantially'
},
{
'question': 'In order to meet production targets, inspection equipment that breaks down easily should be checked on a ——– basis.',
'choices': ['regular', 'regularly', 'regularize', 'regularity'],
'answer': 'regularly'
},
{
'question': '——– you experience any problems with the building’s equipment, you should contact the property manager.',
'choices': ['Becauseof', 'Incaseof', 'Immediately', 'If'],
'answer': 'If'
},
{
'question': 'Employees must park in the ——- parking lot until the renovation of the company building is completed.',
'choices': ['frequent', 'generous', 'complicated', 'temporary'],
'answer': 'temporary'
},
{
'question': 'Although the assembly machine has been used for more than 20 years, it is still ——–.',
'choices': ['annual', 'experienced', 'operational', 'previous'],
'answer': 'operational'
},
{
'question': 'Medical ——– are supposed to investigate the characteristics and effects of newly developed materials.',
'choices': ['expert', 'expertise', 'experts', 'expertly'],
'answer': 'experts'
},
{
'question': 'Darwin Construction, renowned for its ——– designs, has won the bid for the Dalton City Library.',
'choices': ['innovation', 'innovate', 'innovatively', 'innovative'],
'answer': 'innovative'
},
{
'question': 'Please make sure that ——– address is correct in the designated section of the order form.',
'choices': ['yours', 'yourself', 'your', 'you'],
'answer': 'your'
},
{
'question': 'Mr. Thompson was ——– as the marketing director after a successful market development in Asia.',
'choices': ['appointing', 'appointed', 'appoint', 'appoints'],
'answer': 'appointed'
},
{
'question': 'The Irwin City Tourist Information Office is ——– located in the center of the city.',
'choices': ['particularly', 'unfortunately', 'absolutely', 'conveniently'],
'answer': 'conveniently'
},
];
export default data;
'use cliant'
export const INITIAL = {
addAnswers: [],
};
export const reducer = (state, action) => {
switch (action.type) {
case 'ADD_ANSWER':
return {
...state,
addAnswers: [...state.addAnswers, action.payload],
};
case 'RESULT':
return {
...state,
};
default:
return state;
}
}
'use client'
import Link from "next/link";
import data from "../datas/datas";
import { useState, useReducer } from "react";
import { useSearchParams, } from "next/navigation";
import { INITIAL, reducer} from '../reducer';
const Question = () => {
const [currentNum, setCurrentNum] = useState(0);
const [selectedValue, setSelectedValue] = useState(null);
const [displayExplanation, setDisplayExplanation] = useState(false);
const [judgment, setJudgment] = useState(false);
// useReducer
const [state, dispatch] = useReducer(reducer, INITIAL);
const seeAnswer = useSearchParams().get('seeAnswer');
// process of handle selected
const handleSelect = (e) => {
setSelectedValue(e.target.value);
setJudgment(true);
dispatch({ type: 'ADD_ANSWER', payload: e.target.value });
}
const handleDisplayExplanation = () => {
setDisplayExplanation(true);
}
// process of next clicked
const handleNextButton = () => {
if (selectedValue !== null) {
data[currentNum].initialValue = selectedValue;
}
setCurrentNum(currentNum + 1);
setSelectedValue(null);
const radioButtons = document.querySelectorAll('input[name="drone"]');
radioButtons.forEach(radioButton => radioButton.checked = false);
console.log(state.addAnswers);
}
// process of prev clicked
const handlePrevButton = () => {
setCurrentNum(currentNum - 1);
const radioButtons = document.querySelectorAll('input[name="drone"]');
radioButtons.forEach(radioButton => radioButton.checked = false);
}
return (
<div>
<p>Q{currentNum + 1}. {data[currentNum].question}</p>
<fieldset>
<div>
<input type="radio" id={data[currentNum].choices[0]} name="drone" value={data[currentNum].choices[0]} onChange={handleSelect} />
<label for={data[currentNum].choices[0]}>A. {data[currentNum].choices[0]}</label>
</div>
<div>
<input type="radio" id={data[currentNum].choices[1]} name="drone" value={data[currentNum].choices[1]} onChange={handleSelect} />
<label for={data[currentNum].choices[1]}>B. {data[currentNum].choices[1]}</label>
</div>
<div>
<input type="radio" id={data[currentNum].choices[2]} name="drone" value={data[currentNum].choices[2]} onChange={handleSelect} />
<label for={data[currentNum].choices[2]}>C. {data[currentNum].choices[2]}</label>
</div>
<div>
<input type="radio" id={data[currentNum].choices[3]} name="drone" value={data[currentNum].choices[3]} onChange={handleSelect} />
<label for={data[currentNum].choices[3]}>D. {data[currentNum].choices[3]}</label>
</div>
</fieldset>
{/* if set each, show result every question */}
{seeAnswer === 'each' && judgment && (
<button type="button" onClick={handleDisplayExplanation}>True/false judgment</button>
)}
{displayExplanation && (
selectedValue === data[currentNum].answer ? (
<div>〇</div>
) : (
<div>✕</div>
)
)}
<div>
<button type="button" onClick={handlePrevButton}>PREV</button>
{data.length - 1 === currentNum ? (
<Link href="../result">show result</Link>
) : (
<button type="button" onClick={handleNextButton}>NEXT</button>
)}
</div>
</div>
export default Question;
'use client'
import {useReducer} from 'react'
import data from "../datas/datas";
const Result = () => {
return (
<div>
<h1>Result</h1>
<p>Your Answers: {state.addAnswers.length > 0 ? state.addAnswers.join(', ') : 'No answers submitted'}</p>
</div>
)
}
export default Result