useEffect 中有一个 setState 并且是 console.logging null

useEffect has a setState in it and is console.logging null

我会尽量用最好的方式表达这个...

当我通过道具将函数发送到 child,然后再次将其发送到另一个 child 时,然后使用点击在 'grandparent' 函数中激活它。当我 console.log 在 grandparent 中的原始函数中 console.log 是一个状态时,它打印未定义,但是当我在那个 grandparent 中并尝试激活该函数时,它将正确记录状态。如果有人能更深入地帮助我,那就太好了,我们可以打电话!

import React, { useEffect } from 'react';

import Row from '../row/row';

import './body.css';

import { nanoid } from 'nanoid';

export default function Body () {
    
    const [boxMain, setBoxMain] = React.useState(null)

    const [rows, setRows] = React.useState(null)

    const ref = React.useRef(null)

    function changeBox (event) {
        console.log(event);
        console.log(boxMain);
    }

    React.useEffect(() => {

        /* Describes array with all information */
        const sideBoxes = 40; 
        
        const heightContainer = ref.current.offsetHeight
        const widthContainer = ref.current.offsetWidth;

        const numRows = Math.floor(heightContainer / sideBoxes) - 1
        const numBoxes = Math.floor(widthContainer / sideBoxes)

        /* Beginning of array birth */

        let main = Array(numRows).fill().map(() => new Array(numBoxes).fill({
            id: "",
            water: false,
            land: false,
            air: false,
        }));
        /* End of array birth */
        
        const rows = []
        for (let i = 0; i < numRows; i++) {
            const id = nanoid();
            rows.push(
                <Row
                key={id}
                id={id}
                rowNumber={i}
                numBoxes={numBoxes}
                sideBoxes={sideBoxes}
                changeBox={changeBox}
                main={main}
                />
                )
            }

            setRows(rows)
            setBoxMain(main)

        }, [])

    
    return (
        <div>
            <div onClick={() => changeBox("test")}>
                TEST
            </div>
            <div ref={ref} className='body'>
                {rows}
            </div>
        </div>
    )
}

这里的示例 onClick={() => changeBox("test") 该函数可以正常工作并正确记录“boxMain”。但是当我将 changeBox={changeBox} 传递给 ...

import React, { useEffect } from "react";

import Box from "../box/box";

import "./row.css";

import { nanoid } from 'nanoid';

export default function Row (props) {
    
    const ref = React.useRef(null)
    const [boxes, setBoxes] = React.useState()

    useEffect(() => {
        
        const tempBoxes = []

        for (let i = 0; i < props.numBoxes; i++) {

            const id = nanoid()
            
            tempBoxes.push(
                <Box 
                    rowNumber={props.rowNumber}
                    columnNumber={i}
                    key={id} 
                    id={id}
                    side={props.sideBoxes}
                    changeBox={props.changeBox}
                    main={props.main}
                />
            )
        }

        setBoxes(tempBoxes)

    }, [])
    
    
    return (
        <div ref={ref} className="row-main">
            {boxes}
        </div>
    )
}

然后将 changeBox={props.changeBox} 传递给 ...

import React from "react";

import "./box.css";

export default function Box (props) {
    
    React.useEffect(() => {
        props.main[props.rowNumber][props.columnNumber] = props.id
    }, [])

    const [detectChange, setDetectChange] = React.useState(0)
    const ref = React.useRef(null)
    const styles = {
            width: `${props.side}px`,
            height: `${props.side}px`,
        }


    return (
        <div
            ref={ref}
            className="box-main"
            key={props.id}
            id={props.id}
            rownumber={props.rowNumber}
            columnnumber={props.columnNumber}
            style={styles}
            onClick={() => props.changeBox([props.id, props.rowNumber, props.columnNumber])}
        >
            
        </div>
    )
}

然后我将 onClick={() => props.changeBox([props.id, props.rowNumber, props.columnNumber])} 和它 returns 到原始的 changeBox...

 function changeBox (event) {
        console.log(event);
        console.log(boxMain);
    }

但是当我单击该框时,它 returns 事件正确但 returns boxMain 为空。 当我单击 parent 函数中的 onClick 时,尽管它 console.log 一切正常。

我知道这是一大堆信息,但我知道修复必须很简单,或者至少我的方法应该改变。

感谢您的任何反馈!! :)

编辑 1:

这是正常的输出。

但是当我简单地在代码中添加一个 space 并将其保存在 VS Code 中时(我猜发生了某种类型的重新渲染?)然后它修复为...

尽管 ID 确实发生了变化,所以我认为一切都以某种方式刷新了。

Body 组件的 useEffect 钩子只运行一次,因为它没有任何依赖,因此 changeBox 传递给它的子和孙子的回调具有默认状态 boxMain,它永远不会更新。

这就是为什么在 Body 组件中调用 changeBox 会正确记录 boxMain 数组,而在子组件中调用 props.changeBox 会正确记录 null.

----------------解决方案--------------------

这不是最佳解决方案,但它会让您了解为什么它以前不起作用,以及如何解决它。

import React, { useEffect } from 'react';

import Row from '../row/row';

import './body.css';

import { nanoid } from 'nanoid';

export default function Body () {

const [boxMain, setBoxMain] = React.useState(null)

const [rows, setRows] = React.useState(null)
const [rowsData, setRowsData] = React.useState(null)

const ref = React.useRef(null)

function changeBox (event) {
    console.log(event);
    console.log(boxMain);
}

React.useEffect(() => {

    /* Describes array with all information */
    const sideBoxes = 40; 
    
    const heightContainer = ref.current.offsetHeight
    const widthContainer = ref.current.offsetWidth;

    const numRows = Math.floor(heightContainer / sideBoxes) - 1
    const numBoxes = Math.floor(widthContainer / sideBoxes)

    /* Beginning of array birth */

    let main = Array(numRows).fill().map(() => new Array(numBoxes).fill({
        id: "",
        water: false,
        land: false,
        air: false,
    }));
    /* End of array birth */
    
    const rowsData = []
    for (let i = 0; i < numRows; i++) {
        const id = nanoid();
        rowsData.push({
            key: id,
            id,
            rowNumber: id,
            numBoxes,
            sideBoxes,
        })
    }

    setRowsData(rowsData)
    setBoxMain(main)

}, [])

React.useEffect(() => {
    const rows = []
    for (let i = 0; i < rowsData?.length; i++) {
        const id = nanoid();
        const data = rowsData[i];
        rows.push(
            <Row
                {...data}
                changeBox={changeBox}
                main={boxMain}
            />
        )
    }
    setRows(rows)
}, [rowsData, boxMain, changeBox])


return (
    <div>
        <div onClick={() => changeBox("test")}>
            TEST
        </div>
        <div ref={ref} className='body'>
            {rows}
        </div>
    </div>
)

}