Javascript 在返回之前设置状态总是失败,因为返回尚未完成

Javascript 在返回之前设置状态总是失败,因为返回尚未完成,javascript,reactjs,Javascript,Reactjs,我发现了许多类似的问题,但我永远无法找到解决方案,我不知道如何解决我的问题 我有一个相当大的网格(2D数组)正在生成,我在其中映射它并插入一个节点组件。此过程在网格组件生成此网格时在网格组件内完成 分解我的bug: 我以前在ComponentDidMount中有过它,它会计算数组的宽度和高度并创建网格,这在创建网格时起到了作用,不过,最佳实践告诉我,除非是HTTP调用数据,否则不会在ComponentDidMount中设置状态 在render(){return()}中,我有一个if语句,它检查状

我发现了许多类似的问题,但我永远无法找到解决方案,我不知道如何解决我的问题

我有一个相当大的网格(2D数组)正在生成,我在其中映射它并插入一个节点组件。此过程在网格组件生成此网格时在网格组件内完成

分解我的bug:

我以前在ComponentDidMount中有过它,它会计算数组的宽度和高度并创建网格,这在创建网格时起到了作用,不过,最佳实践告诉我,除非是HTTP调用数据,否则不会在ComponentDidMount中设置状态

render(){return()}
中,我有一个if语句,它检查状态是否未定义,并呈现某种消息,例如
初始化网格
,如果数组的状态未定义,它将呈现
DisplayGrid()
。即使在渲染栅格之后,if也不会触发

这里的底线是,我不知道如何在加载状态之前正确延迟渲染,或者在设置状态后重新加载渲染

我尝试在
GenerateGrid()
中使用回调来调用
DisplayGrid()
,并让我的主要组件返回调用
GenerateGrid()
,但是调用DisplayGrid后,结果是一个无休止的循环,或者再次调整后,一个未定义的映射被调用

以下是完整组件的一个损坏示例:

export default class Grid extends React.Component {
  constructor(){
    super();
    this.state = {
      nodeSize : 50,
      nodeArray : [],
    }
  }
  // Generate a dynamic grid
  GenerateGrid = () => {
    const newNodeArray = [];
    const nodeSize = this.state.nodeSize;

    // get window inner hieght + width based on browser size (onstart) and remove 50px from height due to header
    let screenWidth = window.innerWidth;
    let screenHieght = window.innerHeight - 50;

    // get max amount of nodes based on node size
    const whNodes =  [Math.trunc(screenWidth / nodeSize),Math.trunc(screenHieght / nodeSize)];

    // begin creating the 2D array representing the grid
    for (let row = 0; row < whNodes[0]; row++) { 
      const newRow = []; // initialize 1D array
      for (let col = 0; col < whNodes[1]; col++) {
        newRow.push([]); // initalize 2D array
      }
      newNodeArray.push(newRow); // push into newNodeArray
    } 
    this.setState(
      {nodeArray : newNodeArray}, // set nodeArray state with the new 2D array based on viewport.
      // this.DisplayNodes()  // call function once completed if I used this GenerateGrid method within the return render (does not work)
    );
  }
  DisplayNodes = () => {
    const {nodeArray} = this.state.nodeArray; // get the node array from state
    console.log(nodeArray); // the bug is here. Always undefined.
    return (
      <div id="grid">
        {nodeArray.map((row, rowIdx) => {
          return (
            <div>
              {row.map((node,nodeIdx) => <Node/>)}
            </div>
          )
        })}
      </div>
    )
  }
  render() {
    const {nodeArray} = this.state.nodeArray; // get the node array from state
    console.log(nodeArray);
    return (
      <div id="grid-wrapper">
        {this.GenerateGrid()}
      </div>
    )
  }
}
  render() {
    return (
      <div id="grid-wrapper">
        {this.GenerateGrid()} //create a infinte setState loop
      </div>
    )
  }
然后在主组件的渲染中:

export default class Grid extends React.Component {
  constructor(){
    super();
    this.state = {
      nodeSize : 50,
      nodeArray : [],
    }
  }
  // Generate a dynamic grid
  GenerateGrid = () => {
    const newNodeArray = [];
    const nodeSize = this.state.nodeSize;

    // get window inner hieght + width based on browser size (onstart) and remove 50px from height due to header
    let screenWidth = window.innerWidth;
    let screenHieght = window.innerHeight - 50;

    // get max amount of nodes based on node size
    const whNodes =  [Math.trunc(screenWidth / nodeSize),Math.trunc(screenHieght / nodeSize)];

    // begin creating the 2D array representing the grid
    for (let row = 0; row < whNodes[0]; row++) { 
      const newRow = []; // initialize 1D array
      for (let col = 0; col < whNodes[1]; col++) {
        newRow.push([]); // initalize 2D array
      }
      newNodeArray.push(newRow); // push into newNodeArray
    } 
    this.setState(
      {nodeArray : newNodeArray}, // set nodeArray state with the new 2D array based on viewport.
      // this.DisplayNodes()  // call function once completed if I used this GenerateGrid method within the return render (does not work)
    );
  }
  DisplayNodes = () => {
    const {nodeArray} = this.state.nodeArray; // get the node array from state
    console.log(nodeArray); // the bug is here. Always undefined.
    return (
      <div id="grid">
        {nodeArray.map((row, rowIdx) => {
          return (
            <div>
              {row.map((node,nodeIdx) => <Node/>)}
            </div>
          )
        })}
      </div>
    )
  }
  render() {
    const {nodeArray} = this.state.nodeArray; // get the node array from state
    console.log(nodeArray);
    return (
      <div id="grid-wrapper">
        {this.GenerateGrid()}
      </div>
    )
  }
}
  render() {
    return (
      <div id="grid-wrapper">
        {this.GenerateGrid()} //create a infinte setState loop
      </div>
    )
  }
render(){
返回(
{this.GenerateGrid()}//创建一个infinte setState循环
)
}

这也会抛出一个错误,即映射未定义(即在调用
DisplayGrid
方法之前未设置状态)。

您可能不应该在
render
函数中调用
setState
。 您可以尝试从
GenerateGrid
返回
newnoderray
,并将其传递给
DisplayNodes

GenerateGrid = () => {
    const newNodeArray = [];
    const nodeSize = this.state.nodeSize;

    // get window inner hieght + width based on browser size (onstart) and remove 50px from height due to header
    let screenWidth = window.innerWidth;
    let screenHieght = window.innerHeight - 50;

    // get max amount of nodes based on node size
    const whNodes = [
      Math.trunc(screenWidth / nodeSize),
      Math.trunc(screenHieght / nodeSize)
    ];

    // begin creating the 2D array representing the grid
    for (let row = 0; row < whNodes[0]; row++) {
      const newRow = []; // initialize 1D array
      for (let col = 0; col < whNodes[1]; col++) {
        newRow.push([]); // initalize 2D array
      }
      newNodeArray.push(newRow); // push into newNodeArray
    }
    return this.DisplayNodes(newNodeArray);
  };

您可能不应该在
render
函数中调用
setState
。 您可以尝试从
GenerateGrid
返回
newnoderray
,并将其传递给
DisplayNodes

GenerateGrid = () => {
    const newNodeArray = [];
    const nodeSize = this.state.nodeSize;

    // get window inner hieght + width based on browser size (onstart) and remove 50px from height due to header
    let screenWidth = window.innerWidth;
    let screenHieght = window.innerHeight - 50;

    // get max amount of nodes based on node size
    const whNodes = [
      Math.trunc(screenWidth / nodeSize),
      Math.trunc(screenHieght / nodeSize)
    ];

    // begin creating the 2D array representing the grid
    for (let row = 0; row < whNodes[0]; row++) {
      const newRow = []; // initialize 1D array
      for (let col = 0; col < whNodes[1]; col++) {
        newRow.push([]); // initalize 2D array
      }
      newNodeArray.push(newRow); // push into newNodeArray
    }
    return this.DisplayNodes(newNodeArray);
  };

没有错误。您在
DisplayNodes()
函数和
render()
函数中的分解都不正确。您正在数组中而不是数组中查找对象。请将
const{noderray}=this.state.noderray
更改为
const{noderray}=这个.state
我想你会很好的。

没有bug。你在
DisplayNodes()
函数和
render()
函数中的解构都是不正确的。你在数组中寻找一个对象,而不是数组。更改每个
常量{noderray}=this.state.noderray
到just
const{noderray}=this.state
我认为你会很好。

除了已经指出的问题(渲染中的错误解构和设置状态)之外,这里重要的是理解如何在react中管理数据

render()
应该只渲染来自状态和道具的数据(返回元素)。修改数据应该在渲染之外进行。我不清楚在本例中,
GenerateArray
在做什么。是应该在组件装载时只运行一次,还是希望它运行每个渲染

我以前在ComponentDidMount时有过它,它会计算数组的宽度和高度并创建网格,这在创建网格时起到了作用,不过,最佳实践告诉我,除非是HTTP调用数据,否则不会在ComponentDidMount中设置状态

你基本上只是格式化你的数据,或者在这里计算初始状态。这个逻辑应该放在
构造函数中
。把你的计算结果放在
This.state={noderray:result,…}

然后你应该问自己,“这个逻辑什么时候应该再次运行?”
GenerateGrid
的结果取决于
nodeSize
和屏幕尺寸。显然
nodeSize
在这里永远不会改变,它可能是一个常数50。
screenWidth
screenHeight
也不会改变,所以我认为在最初进行这些计算之后,您不应该重新运行此逻辑。在这种情况下,您应该将其从渲染中移除。如果希望网格在屏幕尺寸更改时重新计算,则必须为window onResize事件创建侦听器,并在状态中更新新的
screenHeight
screenWidth
,然后在每个渲染中运行此格式化逻辑


同样,非常重要的是要记住,
render
应该只渲染状态和道具中的数据,而您创建的生命周期方法和侦听器应该更改渲染过程中使用的状态

,除了已经指出的问题(渲染中的错误解构和设置状态)这里重要的是理解如何在react中管理数据

render()
应该只渲染来自状态和道具的数据(返回元素)。修改数据应该在渲染之外进行。我不清楚在本例中,
GenerateArray
在做什么。是应该在组件装载时只运行一次,还是希望它运行每个渲染

我以前在ComponentDidMount时有过它,它会计算数组的宽度和高度并创建网格,这在创建网格时起到了作用,不过,最佳实践告诉我,除非是HTTP调用数据,否则不会在ComponentDidMount中设置状态

你基本上只是格式化你的数据,或者在这里计算初始状态。这个逻辑应该放在
构造函数中
。把你的计算结果放在
This.state={noderray:result,…}

然后