正在重置的状态 [英] State being reset

查看:54
本文介绍了正在重置的状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

新手反应 &反应钩子.我试图理解为什么我的状态被 initialState 覆盖.

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

有人能帮我分析一下发生了什么吗?

解决方案

问题出在这里:

 useEffect(() => {//组件确实挂载了console.log(组件确实挂载了")window.addEventListener(resize", updateBox);//这里返回 () =>{window.removeEventListener(resize", updateBox);};}, []);

您绑定到调整大小窗口事件的 updateBox 函数将使用它在绑定时(组件确实安装时)的状态,因为 addEventListener 的回调strong> 在它自己的闭包中执行.

为了解决这个问题,你必须将状态保存在一个 ref 中,这样它仍然是当前的,当你从另一个闭包访问它时也是如此.所以首先创建 ref 并将状态存储在其中:

const [layoutState,setLayoutState] = useState(initLayout);const layoutRef= useRef({});layoutRef.current = layoutState;

然后在 updateBox 函数中,您必须读取布局状态";来自 layoutRef 而不是 layoutState:

 const updateBox = () =>{让百分比 = (layoutRef.current.size.height/layoutRef.current.size.width) * 100如果(百分比 > 100){百分比 = 100}百分比=百分比+%"const cloneBoxStyle = clone(boxStyle);cloneBoxStyle.width = "100%";cloneBoxStyle.height = 百分比setBoxStyle(cloneBoxStyle)}

让我知道它是否有效并请提供反馈,因为这是我在这里的第一个答案:)

Newbie to React & React hooks. I'm trying to understand why my state is being overwritten by initialState.

When I input a value, things work as expected. However when I resize the window it resets it to the initialState and I'm not sure why. After inserting values into the inputs updateBox displays the correct values.

Can anybody break this down for me as to what is happening?

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;

解决方案

The problem is here:

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

the updateBox function you are binding to the resize window event will use the state it had at the moment it was bounded (when the component did mount) because the callback of addEventListener is executed in its own closure.

To solve this you have to save the state inside a ref, that way it will still be current, also when you are accessing it from another closure. so first create the ref and store the state in it:

const [layoutState,setLayoutState] = useState(initLayout);
const layoutRef= useRef({});
layoutRef.current = layoutState;

and then inside the updateBox function you have to read the layout "state" from layoutRef instead of 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)
  }

Let me know if it works and please give feedback since this is my first answer here :)

这篇关于正在重置的状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆