【发布时间】:2020-02-16 14:30:30
【问题描述】:
为了实践我在 React 中学到的东西,我正在尝试在 React 中制作某种 QCM。
the architecture of the components of the application
这张图片描述了我的应用程序组件的架构。
App 组件包含主要状态和改变状态的功能。
组件板包含 4 个建议的答案和一些实用功能,用于打乱它从 App 组件收到的答案。
所以用户可以点击包含答案的按钮。如果答案错误,按钮变为红色。如果答案正确,则按钮变为绿色,App 组件的状态更改为将正确答案的数量增加 1。此外,由于状态的另一个元素,显示了“按钮下一步”组件。它允许更改问题和答案。当新答案出现时,我希望答案按钮变为初始颜色。
问题是:如何通过单击“按钮下一步”组件来更改答案组件的状态?
所以,我已经将答案按钮的颜色存储在它的状态中,并且它的更新是通过调用 App 组件中的一个函数的 onClick 事件完成的。
我想过当好答案的数量增加一时将答案按钮的颜色更改为其初始颜色,但结果似乎很随机。
当我在网上搜索答案时,我只发现了这种问题,但是元素处于相同的 react 组件中并且使用相同的状态。
有人有想法吗?
PS:目前,我尝试在没有 redux 和 hooks 的情况下做一些事情。当我只用基本的反应就能成功时,我会使用钩子。
import React from 'react';
import './App.css';
const datas = [
{
id:1,
question: 1,
answer: 11
},
{
id:2,
question: 2,
answer: 22
},
{
id:3,
question: 3,
answer: 33
},
{
id:4,
question: 4,
answer: 44
},
{
id:5,
question: 5,
answer: 55
},
{
id:6,
question: 6,
answer: 66
},
{
id:7,
question: 7,
answer: 77
},
{
id:8,
question: 8,
answer: 88
},
{
id:9,
question: 9,
answer: 99
}
]
class App extends React.Component {
constructor(props){
super(props)
this.state = {
guesses: 0,
won: false,
buttonClicked: false
}
}
getId(datas){
const tabIdLetters = []
datas.map((data, index) =>
(tabIdLetters.push(data.id))
)
return tabIdLetters
} //return an array with the ID elements of the datas
getRandom(arr, n) {
var result = new Array(n),
len = arr.length,
taken = new Array(len);
if (n > len)
throw new RangeError("getRandom: more elements taken than available");
while (n--) {
var x = Math.floor(Math.random() * len);
result[n] = arr[x in taken ? taken[x] : x];
taken[x] = --len in taken ? taken[len] : len;
}
return result;
} //get n random elements from a tab
getOneRandom(arr) {
var result,
len = arr.length;
var x = Math.floor(Math.random() * len);
result = arr[x]
return result;
} //get one random element from a tab
handleWon(){
this.setState({
won: true
})
}
handleButtonNext(){
const newGuesses = this.state.guesses + 1
this.setState({
guesses: newGuesses,
won: false,
buttonClicked: true
})
}
render(){
const lettersSelected = this.getRandom(this.getId(this.props.datas), 4) //the 4 answers which will be displayed
const letterQueried = this.getOneRandom(lettersSelected) //among these 4 letters, one will be the one being asked
return (
<div className="App">
<Board datas={datas} className="board" lettersSelected={lettersSelected} letterQueried={letterQueried} app={this} />
<LetterQuerried lettersSelected={lettersSelected} letterQueried={letterQueried} app={this} />
{this.state.won && <ButtonNext app={this} style={{display:this.state.visible}} />}
</div>
)
}
}
export default App;
//============== component in which there are the 4 answers buttons ==================
class Board extends React.Component{
constructor(props){
super(props)
}
shuffle(array) {
var currentIndex = array.length, temporaryValue, randomIndex;
// While there remain elements to shuffle...
while (0 !== currentIndex) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
// And swap it with the current element.
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
} //shuffle the array to display the answer buttons in a random order
//The component should re render only if the button next has been clicked
shouldComponentUpdate(nextProps, nextState){
if(nextProps.app.state.buttonClicked == false){
return false
}
else{
return true
}
}
render(){
const datas = this.shuffle(this.props.datas)
return(
<div>
{datas.map((data, index) =>
(this.props.lettersSelected.includes(data.id) && <LetterProposed id={data.id} data={data.answer} key={index} letterQueried={this.props.letterQueried} app={this.props.app} board={this} />)
)}
</div>
)
}
}
//=========================== answer button component ===================================
class LetterProposed extends React.Component{
constructor(props){
super(props)
this.state = {
bgColor: 'gray'
}
}
handlerClick(e){
this.props.app.state.buttonClicked = false
if(e.target.id == this.props.letterQueried){ //correct answer
this.setState({
bgColor: 'green'
})
this.props.app.handleWon()
}
else if(e.target.id != this.props.letterQueried){ //wrong answer
this.setState({
bgColor: 'red'
})
}
}
shouldComponentUpdate(nextProps){
if(this.props.app.state.guesses !== nextProps.app.state.guesses){
return false
}
else{
return true
}
}
render(){
return(
<button id={this.props.id} onClick={this.handlerClick.bind(this)} style={{backgroundColor:this.state.bgColor}}>{this.props.data}</button>
)
}
}
//================= Question component ========================
class LetterQuerried extends React.Component{
constructor(props){
super(props)
}
shouldComponentUpdate(nextProps, nextState){
if(nextProps.app.state.buttonClicked == false){
return false
}
else{
return true
}
}
render(){
return(
<p>{this.props.letterQueried}</p>
)
}
}
//==================== Button next component ==============================
class ButtonNext extends React.Component{
constructor(props){
super(props)
this.state = {
visible: 'block'
}
}
handlerClick(){
this.props.app.handleButtonNext()
}
render(){
return(
<button onClick={this.handlerClick.bind(this)}>Suivant</button>
)
}
}
【问题讨论】:
-
你能提供到目前为止你尝试过的代码吗?这将有助于为您的问题提供清晰和更好的解决方案。另请参阅有关如何在论坛上提问的部分
-
@chitova263 我已经编辑了我的消息以添加代码。我只隐藏了实用程序功能使其更短
标签: reactjs