lab7
作业要求
作业设计
根据UI设计,将需要完成的程序分成两个组件,一个是game,用于生成26个英文字母,并且实现返回和完成按钮,另一个是inputBoard组件,用于生成填空的单词
作业难点
生成单词的函数
比如student这个单词,想要随机扣掉字母,首先要确定两个随机数,一个是扣掉几个字母,一个是扣掉哪几个字母。扣掉几个字母,我设置最小值是2,最大值是字符长度。然后要根据扣掉字符的数量,随机扣掉第几个字符,我们用missNum代表要扣掉的字母数,missIndex存放扣掉的字母下标。这里我设计的算法有一个问题,就是有可能missIndex的个数少于missNum,因为随机生成的数字可能重复,我进行了去重操作。
const makeWord = ()=>{
const length = correctWord.length;
word = correctWord;
for(let cnt = 0;cnt<length;cnt++){
const missNum = Math.floor((Math.random()*length-1)+2); //扣掉字母的个数
let missIndex = []; //扣掉字母的下标
for(let i = 0;i<missNum;i++){
missIndex.push(Math.floor((Math.random()*length)));
}
missIndex = missIndex.filter((value,index)=>{
return missIndex.indexOf(value)===index;
})
missIndex.sort((a,b)=>{return a-b});
for(let i = 0;i<missIndex.length;i++){
word[cnt] = word[cnt].replace(word[cnt][missIndex[i]],'_') ;
}
}
console.log(word);
}
hooks的生命周期
react和hooks生命周期的不同
使用React Hooks模拟生命周期 - 掘金 (juejin.cn)
我在function中定义了一个word
let word = ["student","handsome","oli"]
用useEffect监控index,index改变产生副作用,执行useEffect中组件并且重新渲染,这时候word的值为空。也就是说除了useState的数据不会根据更新改变,其他的变量只在第一次mount的时候才会有数据。
useState中set函数的异步性
如果你使用
//index=1;
setIndex(index+1);
console.log(index);//output is 1
这是因为set函数是异步的,他会在下一次组件重新渲染之后才更新,所以我想到首先要将他重新渲染,用useEffect监控要改变的变量,然后下文如果要使用这个变量,直接用index+1,或者再声明一个useRef变量,他是同步更新的可以立马获取当前值
setIndex(index+1);
// index = index+1;
console.log(index)
console.log(words);
if(state.history[state.history.length-1][index+1]==words[index+1]){
isBack.current = true;
}
踩坑
组件渲染两边
使用了严格模式
[译]我的 React 组件会渲染两次,我快疯了 - 掘金 (juejin.cn)
一开始把生成随机数写在子组件
发现每次父组件调用子组件,随机数都会重新生成,所以生成随机数的函数要写在父组件中
const length = correctWord.length;
word = correctWord;
for(let cnt = 0;cnt<length;cnt++){
const missNum = Math.floor((Math.random()*length-1)+2); //扣掉字母的个数
let missIndex = []; //扣掉字母的下标
for(let i = 0;i<missNum;i++){
missIndex.push(Math.floor((Math.random()*length)));
}
missIndex = missIndex.filter((value,index)=>{
return missIndex.indexOf(value)===index;
})
missIndex.sort((a,b)=>{return a-b});
for(let i = 0;i<missIndex.length;i++){
word[cnt] = word[cnt].replace(word[cnt][missIndex[i]],'_') ;
}
}
console.log(word);
// setWords(()=>{
// return [
// ...word
// ]
// }) 先定义再赋值不行
const [words,setWords] = useState([...word]);
console.log(words);
完整代码
game.js
import React,{useEffect,useLayoutEffect, useRef, useState} from 'react'
import InputBoard from './inputBoard'
function Game() {
const correctWord = ["student","handsome","oli"];
let word = [];
const [index,setIndex] = useState(0);
const isBack = useRef(true);
const [words,setWords] = useState([...correctWord]);
const [word1,setWord1] = useState([...correctWord]);
let history = [];
const [state,setState] = useState({
history : history
})
const makeWord = ()=>{
const length = correctWord.length;
word = correctWord;
for(let cnt = 0;cnt<length;cnt++){
const missNum = Math.floor((Math.random()*length-1)+2); //扣掉字母的个数
let missIndex = []; //扣掉字母的下标
for(let i = 0;i<missNum;i++){
missIndex.push(Math.floor((Math.random()*length)));
}
missIndex = missIndex.filter((value,index)=>{
return missIndex.indexOf(value)===index;
})
missIndex.sort((a,b)=>{return a-b});
for(let i = 0;i<missIndex.length;i++){
word[cnt] = word[cnt].replace(word[cnt][missIndex[i]],'_') ;
}
}
console.log(word);
}
useLayoutEffect(()=>{ //dom渲染之前
console.log("11");
makeWord();
console.log(word);
setWords(()=>{
return [
...word
]
})
setWord1(()=>{
return [
...word
]
})
state.history.push(JSON.parse(JSON.stringify(word)));
},[])
console.log(word1);
console.log(words);
// makeWord();
const alphabet = Array.from(new Array(26), (ele, index) => {
return String.fromCharCode(97 + index);
})
const showAlphabet = ()=>{
return (
alphabet.map((value)=>{
return <button
key = {value}
className="square"
alp = {value}
onClick = {()=>handleClick(value,index)}>
{value}
</button>
})
)
}
const handleClick = (v,i=0)=>{
console.log("接受点击");
console.log(v);
if(state.history.length==0){
isBack.current = true;
}
else isBack.current = false;
let temp = JSON.parse(JSON.stringify(words));
const first = temp[i].indexOf('_');
// console.log(first);
temp[i] = temp[i].replace(temp[i][first],v) ;
// console.log(temp);
setWords(()=>{
return [
...temp
]
})
state.history.push(JSON.parse(JSON.stringify(temp)));
console.log(state.history);
console.log(words);
}
const checkCorrect = ()=>{
console.log("点击按钮");
if(words[index]==correctWord[index]&&index!=correctWord.length-1){
setIndex(index+1);
// index = index+1;
console.log(index)
console.log(words);
if(state.history[state.history.length-1][index+1]==words[index+1]){
isBack.current = true;
}
// console.log(state.history);
// console.log(state.history[state.history.length-1][index+1],word)
}
else if(index==correctWord.length-1){
alert("完成拼写");
}
else {
alert("拼写错误")
}
}
const backHistory = ()=>{
let l = state.history.length-1;
console.log(state.history[l-1][index])
console.log(index);
if(l==1||state.history[l-1][index]==word1[index]){
isBack.current = true;
}
else isBack.current = false;
// console.log("存储长度l"+l);
const temp = state.history[l-1];
console.log(temp);
setWords(()=>{
return [
...temp
]
})
let history = state.history;
history.pop();
setState(()=>{
return {
history:history
}
})
}
return (
<div className="game">
<div className="board-row">
{showAlphabet()}
</div>
<div className="board-row">
<InputBoard words = {words} index = {index} />
</div>
<div className="board-row">
<button onClick = {()=>checkCorrect()} >√</button>
<button disabled = {isBack.current} onClick = {()=>backHistory()}> 后退</button>
</div>
</div>
);
}
export default Game;
inputBoard.js
function InputBoard(props) {
// let words = ["student","handsome","oli"];
// const index = 0;
const showInput = ()=>{
let length = props.words[props.index].length;
// console.log(props.index);
// console.log(props.words);
// console.log("jie"+props.length);
return (
props.words[props.index].split("").map((value,index)=>{ //取出每个单词
// value.split(" ").map(()=>{})
for(let i = 0;i<length;i++){
// console.log( words[index]);
return <span className="square" key = {i+index} >{value}</span>
}
})
)
}
return (
<>
<div>
{showInput()}
</div>
</>
);
}
export default InputBoard;