React[hooks]实现多单词单词拼写demo(ZUCC智能终端与移动应用开发lab7)

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;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值