I'm trying to score points after the answer is answered correctly or wrongly. Possibly is something easy to see but I'm still new to react ... sorry;/ I will appreciate any help.
const handleOption = () => {
if (isClick[countQuestion - 1]) return;
let newdata = [...isClick];
newdata[countQuestion - 1] = true;
setIsClick(newdata);};
<div className="options-display">
{questions.options.map((options) => {
return (
<button
className={`btn-option ${
isClick[countQuestion - 1]
? options === questions.answer ? "correct" : "incorrect"
:""
}`}
key={options}
onClick={handleOption}
>
{options}
</button>
);
})}</div>
export default Question;
And that's my sec component=child
import React, {useState} from 'react'
function Score(){
const [score,setScore]=useState(0)
return (
<div>
<h1>Your score is: {score}</h1>
</div>)}
export default Score;
You should use a hook called useEffect to run code after a component has been rendered. Here's an example of how to use it:
import React, { useEffect } from 'react';
function Score() {
const [score, setScore] = useState(0);
useEffect(() => {
if (isClick[countQuestion - 1]) {
let newScore = score + 1;
setScore(newScore);
}
}, [isClick]);
return (
<div>
<h1>Your score is: {score}</h1>
</div>
);
}
Related
I need to call function resetToken() from another page when i click on button.
resetToken() should change useState to generate new code. I don't know how to import this function to another page and use it.
I have import
import Captcha from '../../../components/Captcha/Captcha'; and displayed with <Captcha/> in return( ... )
So when i click on button I need to call function resetToken() to generate new code or call again import because I have in <Captcha/>
React.useEffect(() => {
resetToken();
},[]);
This code is Captcha.jsx
import React from 'react';
import './Captcha.css';
function Captcha({statusOfCaptcha}){
const [status, setStatus] = React.useState(undefined);
const [code, setCode] = React.useState(undefined);
const [text, setText] = React.useState("");
const [seconds, setSeconds] = React.useState(120);
function resetToken(){
//generate code
var codeGenerated = "";
var possible = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz123456789";
for (var i = 0; i < 6; i++){
codeGenerated += possible.charAt(Math.floor(Math.random() * possible.length));
}
setCode(codeGenerated);
//reset every 120 second
setInterval(function(){
var codeGenerated = "";
var possible = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz123456789";
for (var i = 0; i < 6; i++){
codeGenerated += possible.charAt(Math.floor(Math.random() * possible.length));
}
setCode(codeGenerated);
setSeconds(120);
setStatus(undefined);
setText("");
}, 120000);
const interval = setInterval(() => {
setSeconds(seconds => seconds - 1);
}, 1000);
return () => clearInterval(interval);
}
React.useEffect(() => {
resetToken();
},[]);
function checkCaptcha(e){
if(e === code){
setStatus(true);
statusOfCaptcha(true);
} else{
setStatus(false);
statusOfCaptcha(false);
}
}
return (
<div className='captcha'>
<div className="background">
<p onCopy={(e) => e.preventDefault()} className="unselectable">{code}</p>
<a>{seconds}</a>
</div>
<div className='input-captcha'>
<input type="text" placeholder="Zadejte kód" value={text} onChange={(e) => {checkCaptcha(e.target.value); setText(e.target.value)}}/>
{status === false && (<i class='bx bx-x text-color-red'></i>)}
{status === true && (<i class='bx bx-check text-color-green'></i>)}
</div>
</div>
)
}
export default Captcha;
This code is index.jsx
import React from 'react'
import Captcha from '../../../components/Captcha/Captcha';
function Index() {
function change(){
//here i need to call function from Captcha.jsx - resetToken();
}
return (
<div>
<Captcha statusOfCaptcha={resCaptchaData}/>
<button onclick={change}>Reset captcha code</button>
</div>
)
}
export default Index
It would be better to use a custom hook, to store your state, and resetToken function, So you can use it in multiple places.
For more resources about custom hooks.
https://reactjs.org/docs/hooks-custom.html
You can do this in several ways
for example you can use state manager like context api or redux.
In order to have access to your states or functions everywhere and in all pages and components
Or you can put the resetToken function in the parent component and have access to it in the child components.
export const ParentComponent = (children) => {
function resetToken {
....
}
return (
<Recapcha resetToken={resetToken} />
)
}
const Recapcha = ({resetToken}) => {
return (...)
}
I made my basic ToDo list site after learning react. I wanted to add a function of saving the items on reload. I am a beginner in react so I am facing difficulty in this. I tried the following code:
import React from "react";
import ToDoList from "./components/ToDoList";
import Navbar from './components/Navbar'
import '../src/App.css'
export default function TodoInput() {
const saveLocalTasks = () => {
let savedTasks = localStorage.getItem('tasks')
console.log(savedTasks)
if (savedTasks) {
return JSON.parse(localStorage.getItem('tasks'))
} else {
return []
}
}
const [task, setTask] = React.useState('')
const [count, setCount] = React.useState(0)
const [taskList, setTaskList] = React.useState([saveLocalTasks()])
const [disable, setDisable] = React.useState(true)
const [viewTaskList, setViewTaskList] = React.useState(true)
const updateTaskList = () => {
setTaskList([...taskList, {object: task, key: Date.now()}])
setTask('')
setViewTaskList(false)
setCount(count + 1)
setDisable(true)
}
const inputValue = e => {
setTask(e.target.value)
e.target.value === '' || task === '' || task.length === 0
?
setDisable(true)
:
setDisable(false)
}
// console.log(task.length)
React.useEffect(() => {
localStorage.setItem('tasks', JSON.stringify(taskList.object))
}, [taskList])
return (
<div>
<Navbar />
<header>
<div className="todolist-border">
<div className="todo-input-form">
<input
className = "inputText"
placeholder="Add a Task"
value={task}
onChange = {inputValue}
/>
<button disabled = {disable} onClick = {updateTaskList} className="todo-add-button">+</button>
</div>
{
viewTaskList || count === 0
?
<div className="pendingTasks-div">
<img className = "pending-task-image"
src= "https://dm0qx8t0i9gc9.cloudfront.net/watermarks/image/rDtN98Qoishumwih/task-pending-cartoon-business-vector-illustrations_zJCs81OO_SB_PM.jpg"
alt="pending-tasks" />
<p className="no-task-message">There are no pending tasks!! #Enjoy🥳🥳</p>
</div>
:
<ToDoList count = {count} setCount = {setCount} task = {task} taskList = {taskList} setTaskList = {setTaskList}/>
}
</div>
</header>
</div>
)
}
But the following error is coming up:
The following is the code for ToDoList component:
import React from "react";
export default function ToDoList(props) {
const deleteTaskListItem = (key) => {
const updatedList = props.taskList.filter((item) => {
return (
item.key !== key
)
})
props.setTaskList(updatedList)
props.setCount(props.count - 1)
}
return(
<div>
{props.taskList.map((item) => {
return (
<div key = {item.key} className="todolist-div">
<input type="checkbox" className="list-checkbox">
</input>
<p>{item.object}</p>
<button onClick={()=>deleteTaskListItem(item.key)} className="delete-button">X</button>
</div>
)
})}
</div>
)
}
Kindly suggest a method to add this feature.
The above error happens when you try to JSON.parse undefined. Check this link. Here, I tried to do some changes in your code on CodeSandbox. There you can find some changes I have made.
Firstly, you shouldn't try to set data in this useState const [taskList, setTaskList] = React.useState([saveLocalTasks()]). You should set data in useEffect.
In the following code, you are trying to save taskList.object but taskList is an array. The below code will throw an error.
React.useEffect(() => {
localStorage.setItem('tasks', JSON.stringify(taskList.object))
}, [taskList])
As you asked in your question, you want to try to save data when the user reloads the window. You can achieve this by using window.onbeforeunload event (line 48).
Hope the above will help you.
P.S: The codesandbox code I shared isn't fully functional. I have made just some changes that will help you to go ahead with your coding. Thank you.
Damn, two days, two noob questions, sorry guys.
Yesterday, I spent the whole afternoon reading the docs but my fart-ey brain cannot process how to use react hooks to pass data from a child to a parent.
I want to create a button on my parent that can listen to his child's state to check on it and change the background color depending on its value.
Thing is, the child component is mapping some stuff so I cannot create a button (otherwhise it would be rendered multiple times and not only once like I want).
I've thought about moving all the data to my parent component but I cannot understand how since I'm fairly new to React and it's been only two months of learning how to code for me basically.
I will now provide the code for the parent and the child component.
The parent :
import React from "react";
import Quizz from "./components/Quizz";
export default function App() {
const [quizz, setQuizz] = React.useState([]);
React.useEffect(() => {
async function getData() {
const res = await fetch(
"https://opentdb.com/api.php?amount=5&category=27&type=multiple"
);
const data = await res.json();
setQuizz(data.results)
}
getData();
}, []);
function checkOnChild(){ /* <== the function I'd like to use to check on my Quizz component's "activeAnswer" state */
console.log(quizz);
}
const cards = quizz.map((item, key) => {
return <Quizz {...item} key={key}/>;
});
return (
<div>
{cards}
<button onClick={checkOnChild}>Check answers</button> /* <== the button that will use the function */
</div>
);
}
and the child :
import React from "react";
import { useRef } from "react";
export default function Quizz(props) {
const [activeAnswer, setActiveAnswer] = React.useState('');/* <== the state I'd like to check on from my parent component */
function toggle(answer) {
setActiveAnswer(answer);
}
function shuffleArray(array) {
for (let i = array.length - 1; i > 0; i--) {
let j = Math.floor(Math.random() * (i + 1));
let temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
let answers = props.incorrect_answers;
const ref = useRef(false);
if (!ref.current) {
answers.push(props.correct_answer);
shuffleArray(answers);
ref.current = true;
}
const answerDiv = answers.map((answer, key) => (
<div key={key} className="individuals" onClick={()=> toggle(answer)}
style={{background: answer == activeAnswer ? "#D6DBF5" : "transparent" }}>
{answer}
</div>
));
console.log(answers);
console.log(activeAnswer);
console.log(props.correct_answer);
return (
<div className="questions">
<div>
<h2>{props.question}</h2>
</div>
<div className="individuals__container">{answerDiv}</div>
<hr />
</div>
);
}
I'm really sorry If it seems dumb or if I'm making forbidden things lmao, but thanks in advance for your help guys!
This should get you a bit further I think.
export default function App() {
const [quizData, setQuizData] = useState([])
const [quizState, setQuizState] = useState({})
useEffect(() => {
async function getData() {
const res = await fetch('https://opentdb.com/api.php?amount=5&category=27&type=multiple')
const data = await res.json()
const results = data.results
setQuizData(results)
setQuizState(results.reduce((acc, curr) => ({ ...acc, [curr.question]: '' }), {}))
}
getData()
}, [])
function checkOnChild() {
console.log(quizState)
}
const cards = quizData.map((item) => {
return <Quizz {...item} key={item.question} quizState={quizState} setQuizState={setQuizState} />
})
return (
<div>
{cards}
<button onClick={checkOnChild}>Check answers</button>
</div>
)
}
export default function Quizz(props) {
function handleOnClick(answer) {
props.setQuizState(prevState => ({
...prevState,
[props.question]: answer,
}))
}
const answers = useMemo(() => {
const arr = [...props.incorrect_answers, props.correct_answer]
return shuffleArray(arr)
}, [props.incorrect_answers, props.correct_answer])
const answerDiv = answers.map((answer) => (
<div
className="individuals"
key={answer}
onClick={() => handleOnClick(answer)}
style={{ background: answer == props.quizState[props.question] ? '#D6DBF5' : 'transparent' }}
>
{answer}
</div>
))
return (
<div className="questions">
<div>
<h2>{props.question}</h2>
</div>
<div className="individuals__container">{answerDiv}</div>
<hr />
</div>
)
}
I am making a chess game and I need to integrate a count down timer, e.g - so when it's the white players turn their clock is counting down until they move.
To avoid changing a lot more code that is not present in this question ,I would like to keep function "move" as is, though I could change CountDownTimer if needed,
For now I would like to know how to call the react hook setTimerOn in the CountDownTimer component from the function move,then I can work out the rest myself.
From what I have read you cannot do this with react hooks? so just looking for
anything that works, if that means changing CountDownTimer.
export function move(from, to, promotion) {
let tempMove = { from, to }
if (member.piece === chess.turn()) {
const legalMove = chess.move(tempMove)
if (legalMove) {
updateGame()
//i would like to access CountDownTimer and call setTimerOn(true)
// i can work out the code for white and black / start and stop myself afterwards
}
}
,
}
import React from 'react'
function CountDownTimer(){
const [time, setTime] = React.useState(0);
const [timerOn, setTimerOn] = React.useState(false);
React.useEffect(() => {
let interval = null;
if (timerOn) {
interval = setInterval(() => {
setTime((prevTime) => prevTime + 10);
}, 10);
} else if (!timerOn) {
clearInterval(interval);
}
return () => clearInterval(interval);
}, [timerOn]);
return (
<div className="Timers">
<h2>Stopwatch</h2>
<div id="display">
<span>{("0" + Math.floor((time / 60000) % 60)).slice(-2)}:</span>
<span>{("0" + Math.floor((time / 1000) % 60)).slice(-2)}:</span>
<span>{("0" + ((time / 10) % 100)).slice(-2)}</span>
</div>
<div id="buttons">
{!timerOn && time === 0 && (
<button onClick={() => setTimerOn(true)}>Start</button>
)}
{timerOn && <button onClick={() => setTimerOn(false)}>Stop</button>}
{!timerOn && time > 0 && (
<button onClick={() => setTime(0)}>Reset</button>
)}
{!timerOn && time > 0 && (
<button onClick={() => setTimerOn(true)}>Resume</button>
)}
</div>
</div>
);
});
export default CountDownTimer; ```
Based on React documentation, React Hook can be called from function components or other hooks.
In your situation, you should consider the utilization of React Context. You need to move up timerOn state and setTimerOn method as context values. So that, all components which are wrapped by the context provider can utilize the values.
First, create some helpers for managing context.
// TimerOn.js
import React, { createContext, useContext } from 'react';
// create a context
const TimerOnContext = createContext();
// create a hook to provide context value
export function useTimerOn() {
const contextValue = useContext(TimerOnContext);
return contextValue;
}
// custom provider that will wrap your main components
export function TimerOnProvider({ children }) {
const [timerOn, setTimerOn] = React.useState(false);
return (
<TimerOnContext.Provider value={{ timerOn, setTimerOn }}>
{children}
</TimerOnContext.Provider>
);
}
For instance, I create two simple components to demonstrate the timer component and caller component.
// CountDownTimer.js
import React from "react";
import { useTimerOn } from "./TimerOn";
export default function CountDownTimer() {
const { timerOn } = useTimerOn();
// detect changes
React.useEffect(() => {
if (timerOn) {
console.log('timer is on');
} else {
console.log('timer is off');
}
}, [timerOn]);
return (
<div>{timerOn ? 'timer on' : 'timer off'}</div>
);
}
// MoveCaller.js
import React from "react";
import { useTimerOn } from "./TimerOn";
export default function MoveCaller() {
const { timerOn, setTimerOn } = useTimerOn();
// move then set timer
const move = () => {
setTimerOn(!timerOn);
}
return (
<div>
<button type="button" onClick={move}>
Move
</button>
</div>
);
}
Then, you can wrap all main components with the provider component. So, the move function in a component can change the state of timerOn and be read by another component.
import React from 'react';
import CountDownTimer from './CountDownTimer';
import MoveCaller from './MoveCaller';
import { TimerOnProvider } from './TimerOn';
export default function ChessApp() {
return (
<TimerOnProvider>
<CountDownTimer />
<MoveCaller />
</TimerOnProvider>
);
}
I know this is very common error Invariant Violation: Hooks can only be called inside the body of a function component but still I am not able to figure it out how to fix it in my code.
What I understood is the issue is with useMemo hook in my code ? please guide me. As per my understanding, problem is mismatching versions of React and ReactDOM or it is related to I am not calling my hooks properly. Parent component is using react 15 and child component's code refer react 16.8 code.
Problem is with specific to this code -
/**
* Get the difference from parseDiff in a formatLines
*/
const diff = useMemo(() => {
const diffText = formatLines(
diffLines(props.startupConfigData, props.runningConfigData),
{
context: 3
}
);
const [diff] = parseDiff(diffText, { nearbySequences: "zip" });
return diff;
}, [props.startupConfigData, props.runningConfigData]);
const { type, hunks } = diff;
/**
* Token used for useMemo
*/
const tokens = useMemo(() => tokenize(hunks), [hunks]);
My full component code -
import React, { useMemo } from "react";
import { diffLines, formatLines } from "./unidiff";
import { parseDiff, Diff, Hunk } from "react-diff-view";
import "./diff.less";
import tokenize from "./tokenize";
import { DnxLoader } from "*external*/#cisco-dna/dnx-react-components";
import i18n from "amdi18n-loader!~/nls/i18_compliance";
import { labels } from "../constants";
import { getStatusComplianceType } from "../common";
const DiffViewer = props => {
const { compareWith } = props;
/**
* Get the difference from parseDiff in a formatLines
*/
const diff = useMemo(() => {
const diffText = formatLines(
diffLines(props.startupConfigData, props.runningConfigData),
{
context: 3
}
);
const [diff] = parseDiff(diffText, { nearbySequences: "zip" });
return diff;
}, [props.startupConfigData, props.runningConfigData]);
const { type, hunks } = diff;
/**
* Token used for useMemo
*/
const tokens = useMemo(() => tokenize(hunks), [hunks]);
/**
* Get text based on selection - startup/running
*/
const getStartupText = () => {
if (compareWith == undefined || compareWith === "startup") {
return i18n.label_startup_configuration;
} else {
return i18n.label_running_configuration;
}
};
/**
* Get date format
* #param {*} date
*/
const getFormattedDate = date => {
var lastUpdateTimeData;
const notAvailable = i18n.label_non_applicable;
if (date !== null) {
lastUpdateTimeData = moment(date).format(labels.lastUpdateTimeFormatAmPm);
} else {
lastUpdateTimeData = notAvailable;
}
return lastUpdateTimeData;
};
const statusDisplayDetails = getStatusComplianceType(
"COMPLIANT",
true
);
/**
* return function
*/
return (
<div className="margin-left-right">
{hunks ? (
<div>
<div className="flex">
<div className="startup-text">
{getStartupText()}
<div className="font-size-10">
{i18n.label_no_of_lines}:{" "}
{props.startUpFile.totalNoOfLines}
</div>
<div className="font-size-10">{i18n.label_archived_on}: {getFormattedDate(props.startUpFile.createdTime )}</div>
</div>
<div className="running-text">
{i18n.label_running_configuration}
<div className="font-size-10">
{i18n.label_no_of_lines}:{" "}
{props.runningFile.totalNoOfLines}
</div>
<div className="font-size-10">{i18n.label_archived_on}: {getFormattedDate(props.runningFile.createdTime)}</div>
</div>
</div>
{ Array.isArray(hunks) && hunks.length ? (
<div className="diff-div">
<Diff
viewType="split"
diffType={type}
hunks={hunks}
tokens={tokens}
>
{hunks =>
hunks.map(hunk => <Hunk key={hunk.content} hunk={hunk} />)
}
</Diff>
</div>
) : (
<div className="div-margin-diff">
{statusDisplayDetails}
<span>{compareWith === "running" ? i18n.label_running_config_compliant : i18n.label_running_startup_config_compliant}</span>
</div>
)
}
</div>
) : (
<div className="loading-icon">
<DnxLoader color="#026E97" size="54" label="Loading..." />
</div>
)}
</div>
);
};
export default DiffViewer;
Can someone please point what is the problem ?