reactjs - 正在重置的状态

标签 reactjs react-hooks

React 和 React 钩子(Hook)的新手。我试图理解为什么我的状态被 initialState 覆盖。

当我输入一个值时,事情会按预期工作。但是,当我调整窗口大小时,它会将其重置为 initialState,我不知道为什么。
将值插入输入后updateBox显示正确的值。

任何人都可以为我解释发生了什么吗?

https://stackblitz.com/edit/react-hdf3sg


import React,{useState,useEffect,useRef} from 'react';
import './Layout.scss';

const initLayout = {
  size:{
    width: 16,
    height: 16,
  }
}
const clone = (obj) => {
  return JSON.parse(JSON.stringify(obj));
}

const Layout = ({props}) => {

  const boxContainer = useRef(null);

  const [layoutState,setLayoutState] = useState(initLayout)
  const [boxStyle,setBoxStyle] = useState({
    "height": "100%",
    "width": "90%",
  })

  useEffect(() =>{
    // State did update
    console.log("useEffect:State did update:",layoutState.size.width,":",layoutState.size.height)
    // updateBox()
  });

  useEffect(() =>{
    // Component did mount
    console.log("Component did mount")
    window.addEventListener("resize", updateBox);
    return () => {
      window.removeEventListener("resize", updateBox);
    };
  }, []);

  useEffect(() => {
    // This state did update
    console.log("layoutState did update",layoutState)
    updateBox()
  }, [layoutState]);

  const updateBox = () => {
    console.log("updateBox",layoutState.size.width,":",layoutState.size.height)

    let percentage = (layoutState.size.height/layoutState.size.width) * 100
    if(percentage > 100){
      percentage = 100
    }
    percentage = percentage+"%"

    // console.log("percentage",percentage)

    const cloneBoxStyle = clone(boxStyle)

    cloneBoxStyle.width = "100%"
    cloneBoxStyle.height = percentage
    setBoxStyle(cloneBoxStyle)

    // console.log("boxContainer",boxContainer)
    // console.log("height",boxContainer.current.clientHeight)
    // console.log("width",boxContainer.current.clientWidth)

  }



  const sizeRatioOnChange = (widthArg,heightArg) => {
    let width = (widthArg === null) ? layoutState.size.width : widthArg;
    let height = (heightArg === null) ? layoutState.size.height : heightArg;

    const cloneLayoutState = clone(layoutState);
    cloneLayoutState.size.width = width
    cloneLayoutState.size.height = height

    setLayoutState(cloneLayoutState)
  }

  const render = () => {
    console.log("render",layoutState.size.width,":",layoutState.size.height)
    // updateBox()
    // const enlargeClass = (true) ? " enlarge" : "" ;

    return (
      <div className={"layout"} >
        <div className="layout-tools-top">
          Layout Size Ratio 
          <input 
            type="number" 
            value={layoutState.size.width} 
            onChange={(e) => {sizeRatioOnChange(e.target.value,null)}}/>
          by
          <input 
            type="number" 
            value={layoutState.size.height} 
            onChange={(e) => {sizeRatioOnChange(null,e.target.value)}}/>

          <button className="button close">
            Close
          </button>
        </div>

        <div className="layout-container">
          <div className="layout-tools-side">
            <h2>Header</h2>
            <ul>

            </ul>
            <form>
              <input type="text" placeholder="Add Item" />
            </form>
          </div>
          <div className="layout-box-container" ref={boxContainer}>
            <div className="layout-box" style={boxStyle}>
              {/* {boxStyle.height} x {boxStyle.width} */}
            </div>
          </div>
        </div>
      </div>
    );
  }

  return render();
};

export default Layout;

enter image description here

最佳答案

问题在这里:

 useEffect(() => {
    // Component did mount
    console.log("Component did mount")
    window.addEventListener("resize", updateBox); //HERE
    return () => {
      window.removeEventListener("resize", updateBox);
    };
  }, []);
更新框 因为的回调函数,你绑定(bind)到resize window事件的函数将使用它被绑定(bind)时的状态(当组件挂载时)。添加事件监听器 在自己的闭包中执行。
要解决这个问题,您必须将状态保存在 ref 中,这样它仍然是最新的,当您从另一个闭包访问它时也是如此。
所以首先创建 ref 并将状态存储在其中:
const [layoutState,setLayoutState] = useState(initLayout);
const layoutRef= useRef({});
layoutRef.current = layoutState;
然后在里面更新框 您必须从 读取布局“状态”的功能布局引用 而不是 布局状态 :
  const updateBox = () => {
    let percentage = (layoutRef.current.size.height/layoutRef.current.size.width) * 100
    
    if(percentage > 100){
      percentage = 100
    }
    percentage = percentage+"%"

    const cloneBoxStyle = clone(boxStyle);

    cloneBoxStyle.width = "100%"
    cloneBoxStyle.height = percentage
    setBoxStyle(cloneBoxStyle)
  }
让我知道它是否有效,请提供反馈,因为这是我在这里的第一个答案:)

关于reactjs - 正在重置的状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56511176/

相关文章:

javascript - 在页面加载时在 Chrome 中调试 ReactJs - 使用控制台时,这个和其他所有内容都是未定义的

javascript - 如何使用 React JS 覆盖内部 CSS 中的背景颜色

reactjs - 调用 setState() 将执行函数值而不是传递它

javascript - 将 ref 传递给 HTML 元素到自定义钩子(Hook)

reactjs - React - 可重用的 Redux hook 切片问题(Redux Toolkit、Typescript)

reactjs - 从下到上逐渐填充一个圆圈

reactjs - 如何在不安装 material-ui 的情况下安装 Material-UI Docs?

reactjs - 为什么 ReactJS 中 DOM 不随着状态变化而更新?

javascript - 使用 React 和 Redux Hooks,为什么我的操作没有触发?

javascript - 如何使用react hooks在其中一个复选框上使用onChange事件来操作map函数内部的DOM