Reactjs 随着时间的推移,不断地改变状态

Reactjs 随着时间的推移,不断地改变状态,reactjs,conways-game-of-life,Reactjs,Conways Game Of Life,我正在尝试使用React来实现生活游戏,它基本上是有效的。我的实现包括一个start按钮,该按钮触发游戏,并且必须保持循环,直到用户按下按钮stop 我说它是有效的…主要是因为我可以看到矩阵正在按预期发展,但我无法使用while子句循环这个过程。当我删除这样一个子句时,每次用户按下start,游戏都会执行一个循环,但我希望游戏能够持续执行循环 代码如下: import React from 'react'; import AppBar from '@material-ui/core/AppBar

我正在尝试使用React来实现生活游戏,它基本上是有效的。我的实现包括一个
start
按钮,该按钮触发游戏,并且必须保持循环,直到用户按下按钮
stop

我说它是有效的…主要是因为我可以看到矩阵正在按预期发展,但我无法使用
while
子句循环这个过程。当我删除这样一个子句时,每次用户按下
start
,游戏都会执行一个循环,但我希望游戏能够持续执行循环

代码如下:

import React from 'react';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';
import Button from '@material-ui/core/Button';
import TextField from '@material-ui/core/TextField';
import Grid from './Grid';

class Matrix extends React.Component {
  constructor (props) {
    super(props);

    this.state = {
      cycle: 0,
      rows: 120,
      columns: 260,
      livingBase: 0.01,
      matrix: null,
      killWith: 2,
      setAliveWith: 4,
      continue: true
    };    
  }

  getRandomMatrix = () => {
    let randomMatrix=[]
    let randomRow = [];
    let randomNumber = null;

    for (let i=0; i<this.state.columns; i++) {
      randomRow = []
      for (let j=0; j<this.state.rows; j++) {
        randomNumber = Math.random();
        randomRow.push(randomNumber < this.state.livingBase? true: false);
      }
      randomMatrix.push(randomRow);
    }
    
    this.setState({matrix: randomMatrix})
  }

  getNextMatrix = () => {
    let newMatrix = this.state.matrix.slice();

    const getCurrentCellLivingNeighbours = (n, m) => {
      let currenCellLivingNeighburs = 0;
      
      const getNeighbour = (l, k) => {
        let tryCell = false;

        try {
          tryCell = this.state.matrix[l][k];
          return tryCell
        } catch {
          return false
        } 
      }

      if (getNeighbour(n-1, m-1)) {
        currenCellLivingNeighburs++;
      }
      if (getNeighbour(n-1, m)) {
        currenCellLivingNeighburs++;
      }
      if (getNeighbour(n-1, m+1)) {
        currenCellLivingNeighburs++;
      }
      if (getNeighbour(n, m-1)) {
        currenCellLivingNeighburs++;
      }
      if (getNeighbour(n, m+1)) {
        currenCellLivingNeighburs++;
      }
      if (getNeighbour(n+1, m-1)) {
        currenCellLivingNeighburs++;
      }
      if (getNeighbour(n+1, m)) {
        currenCellLivingNeighburs++;
      }
      if (getNeighbour(n+1, m+1)) {
        currenCellLivingNeighburs++;
      }

    return currenCellLivingNeighburs;
    }

    for (let j=0; j<this.state.matrix.length; j++) {
      for (let i=0; i<this.state.matrix[0].length; i++) {
        let currentCell = this.state.matrix[j][i];
        let livingNeigbours = getCurrentCellLivingNeighbours(j, i)
        
        if (currentCell) {
          if (livingNeigbours<2 || livingNeigbours>3) {
            newMatrix[j][i] = false;
          }
        } else {
          if (livingNeigbours === 3) {
            newMatrix[j][i] = true;
          }
        }
      }
    }
    this.setState({matrix: newMatrix})
  }

  handleResetClick = () => {
    this.getRandomMatrix();
  }

  catchLivingBaseChange = (e) => {
    this.setState({livingBase: parseInt(e.target.value)/100})
  }

  handleStartClick = () => {
    while (this.state.continue) {
      this.getNextMatrix();
    }
  }

  render () {
    return (
      <div>
        <AppBar position="static">
          <Toolbar>
            <div style={{display: 'flex'}}>
              <div>
                <Typography variant="h6" >
                  The Game Of Life
                </Typography>
              </div>
              <div style={{paddingLeft: 15}}>
                <TextField id="livingBase" label="Porcentaje de Inicio" defaultValue="1" onChange={this.catchLivingBaseChange.bind(this)} />
                <Button color="black" variant='contained' onClick={this.handleResetClick.bind(this)} >Reset</Button>
                <Button color="black" variant='contained' onClick={this.handleStartClick.bind(this)} >Start</Button>
              </div>
            </div>
          </Toolbar>
        </AppBar>
        {this.state.matrix? <Grid matrix={this.state.matrix} />: <h1>Push reset to init matrix...</h1>}
      </div>
    )
  }
}

export default Matrix;
从“React”导入React;
从“@material ui/core/AppBar”导入AppBar;
从“@material ui/core/Toolbar”导入工具栏;
从“@material ui/core/Typography”导入排版;
从“@material ui/core/Button”导入按钮;
从“@material ui/core/TextField”导入TextField;
从“./Grid”导入网格;
类矩阵扩展了React.Component{
建造师(道具){
超级(道具);
此.state={
周期:0,
行:120,
栏目:260,
livingBase:0.01,
矩阵:空,
基尔维思:2,
setAliveWith:4,
继续:对
};    
}
getRandomMatrix=()=>{
让随机矩阵=[]
设randomRow=[];
设randomNumber=null;
for(设i=0;i{
让currencellivingnighburs=0;
const getnexture=(l,k)=>{
让tryCell=false;
试一试{
tryCell=this.state.matrix[l][k];
返回tryCell
}抓住{
返回错误
} 
}
if(getnexter(n-1,m-1)){
currenCellLivingNeighburs++;
}
如果(相邻(n-1,m)){
currenCellLivingNeighburs++;
}
if(getnexter(n-1,m+1)){
currenCellLivingNeighburs++;
}
if(getnexter(n,m-1)){
currenCellLivingNeighburs++;
}
if(getnexter(n,m+1)){
currenCellLivingNeighburs++;
}
if(getnexter(n+1,m-1)){
currenCellLivingNeighburs++;
}
如果(相邻(n+1,m)){
currenCellLivingNeighburs++;
}
if(getNeighbor(n+1,m+1)){
currenCellLivingNeighburs++;
}
返回电流活Neighburs;
}
对于(设j=0;j{
this.setState({livingBase:parseInt(e.target.value)/100})
}
handleStartClick=()=>{
while(this.state.continue){
这个.getNextMatrix();
}
}
渲染(){
返回(
生命的游戏
重置
开始
{this.state.matrix?:将重置推送到init matrix…}
)
}
}
导出默认矩阵;

方法
handleStartClick()
是我想使用
while
子句循环的方法,但是添加这样的子句时屏幕不会更新。

while循环会阻止主线程,因此它们不会给你的应用程序更新UI的机会。我建议你使用或执行更新

可能看起来像这样:

const nextMatrix = () => {
  // compute and return next generation
}

const Life = () => {
  const [matrix, setMatrix] = useState();
  const [running, setRunning] = useState(false);

  const update = useCallback(() => {
    setMatrix(nextMatrix()); // update state with the next generation
    if (running) {
      requestAnimationFrame(update); // run again asap (usually 60Hz)
    }
  }, [running])

  return (
    {/* render current matrix here */}

    <button onClick={() => setRunning(!running)}>{running ? 'stop' : 'start'}</button>
  )
}
const nextMatrix=()=>{
//计算并返回下一代
}
常量生命=()=>{
const[matrix,setMatrix]=useState();
const[running,setRunning]=useState(false);
const update=useCallback(()=>{
setMatrix(nextMatrix());//使用下一代更新状态
如果(正在运行){
requestAnimationFrame(更新);//尽快再次运行(通常为60Hz)
}
},[正在运行])
返回(
{/*在此处呈现当前矩阵*/}
setRunning(!running)}>{running?'stop':'start'}
)
}

请注意,这种方法可能会对浏览器造成负担。如果您担心给其他任务一些喘息空间,您可以使用setTimeout并减少更新矩阵的频率。

而循环会阻塞主线程,因此它们不会给您的应用程序更新UI的机会。我建议您使用或执行更新

可能看起来像这样:

const nextMatrix = () => {
  // compute and return next generation
}

const Life = () => {
  const [matrix, setMatrix] = useState();
  const [running, setRunning] = useState(false);

  const update = useCallback(() => {
    setMatrix(nextMatrix()); // update state with the next generation
    if (running) {
      requestAnimationFrame(update); // run again asap (usually 60Hz)
    }
  }, [running])

  return (
    {/* render current matrix here */}

    <button onClick={() => setRunning(!running)}>{running ? 'stop' : 'start'}</button>
  )
}
const nextMatrix=()=>{
//计算并返回下一代
}
常量生命=()=>{
const[matrix,setMatrix]=useState();
const[running,setRunning]=useState(false);
const update=useCallback(()=>{
setMatrix(nextMatrix());//使用下一代更新状态
如果(正在运行){
requestAnimationFrame(更新);//尽快再次运行(通常为60Hz)
}
},[正在运行])
返回(
{/*在此处呈现当前矩阵*/}
setRunning(!running)}>{running?'stop':'start'}
)
}

请注意,这种方法可能会对浏览器造成负担。如果您担心给其他任务一些喘息空间,您可以使用setTimeout并减少更新矩阵的频率。

在使用
while
循环时是否会在屏幕上挂起?我不认为您可以在长时间运行的Javascript过程中做到这一点,它很容易冻结你的用户界面


您可以尝试使用
setTimeout
setInterval
将您的逻辑发布到事件循环的下一个周期。

在使用
while
循环时,您是否会在屏幕上挂起?我认为在Javascript中,您无法通过长时间运行的过程来实现这一点,它很容易冻结您的UI


您可以尝试使用
setTimeout
setInterval
将逻辑发布到事件循环的下一个周期。

这一行中有一个异常
让newMatrix=this.state.matrix.slice();
this.state.matrix最初为=
null
,您正在尝试对它进行切片

Cannot read property 'slice' of null
这就是为什么
getNextMatrix()
不起作用的原因


另外,您应该改用
setInterval
,因为这会阻止您的UI更新。

此行中有一个异常
让newMatrix=this.state.matrix.slice();
this.state.matrix
最初是
  const waitFrame = () => new Promise(resolve => requestAnimationFrame(resolve));

  handleStartClick = async() => {   // async allows this function to use await
    while (this.state.continue) {
      this.getNextMatrix();
      await waitFrame();            // await lets this function give up control to the browser 
    }
  }