最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 精读《React — 5 Things That Might Surprise You》 - 掘金

    正文概述 掘金(落落落洛克)   2021-09-11   35

    1. 使用之前的状态设置状态是不可预测的

    状态管理是 React 的基础,虽然useState可能是最常见的钩子,但可能对其实际行为有些不了解。 让我们来看看以下组件:

    import React, { useState } from "react";
    import "./styles.css";
    
    export default function App() {
      const [counter, setCounter] = useState(0);
      return (
        <div className="App">
          <h1>Counter: {counter}</h1>
          <button
            onClick={() => {
              setCounter(counter + 1);
              setCounter(counter + 1);
            }}
          >
            +
          </button>
        </div>
      );
    }
    

    在用户单击按钮后,您希望计数器状态的值是多少? A. 2 B. 1 ✔️

    点击demo

    原因是在我们的状态更新期间,我们使用了之前的状态值:setCounter(count + 1)。本质上,setState函数被包装在功能组件闭包中,因此它提供了在该闭包中捕获的值。这意味着当它最终被执行时(setState函数是异步的),它可能持有一个不再相关的状态值。最重要的是,setState 的连续执行可能会导致 React 的调度算法使用相同的事件处理程序处理多个非常快速的状态更新。 在异步函数中设置状态时也可能出现同样的问题:

    onClick={() => { 
       setTimout(() => { setCounter(counter + 1); ), 1000); 
    }};
    

    但是,不用担心,React 实际上为这个问题提供了一个简单的解决方案——“functional updates”。 setCounter((prevCounter) => prevCounter + 1);

    // incorrect
    const update = useCallback(() => {
       setCounter(counter + 1);
    }, [counter]);
    
    // correct ✔️
    const update = useCallback(() => {
       setCounter(prevCounter => prevCounter + 1);
    }, []);
    

    2.可以使用useRef来存储静态变量

    我们习惯于使用 React 中的 ref 机制作为访问元素的 DOM 节点的手段,无论是因为我们需要它来计算其大小、设置焦点状态,或者基本上做任何 React 自然不能做的事情。但是 refs 也可以用于不同的目的——我们可以使用类组件非常容易·实现这一点,但我们不能使用函数式组件——保留一个不会在每次渲染时重新创建的静态变量

    点击demo

    3. React 可以强制重新挂载一个组件

    写入DOM的成本非常高。这就是为什么我们通常不想重新mount 组件,除非绝对必要。但是有时我们必须,出于各种原因。那么在那种情况下,我们如何告诉 react 卸载并立即重新mount 组件?用一个简单的技巧——为我们的组件提供一个key,并改变它的值。

    著名的 React 警告

    精读《React — 5 Things That Might Surprise You》 - 掘金

    key是帮助 React 跟踪元素的东西,即使我们已经改变了它在组件结构中的位置或重新渲染了父级(否则每次渲染都会导致整个组件数组被重新安装,这是不好的性能)。

    使用这种机制,我们可以欺骗 React 认为一个组件与其之前的自己不同,并导致它重新挂载。

    点击demo

    import React, { useEffect, useState, useCallback } from "react";
    import "./styles.css";
    
    export default function App() {
      const [key, setKey] = useState(1);
      const [console, setConsole] = useState([]);
    
      const onLifecycleChange = useCallback((message) => {
        setConsole((prevConsole) => [message, ...prevConsole]);
      }, []);
      return (
        <div className="App">
          <button
            onClick={() => {
              setKey((oldKey) => oldKey + 1);
            }}
          >
            Remount
          </button>
          <ChildComp key={key} onLifecycleChange={onLifecycleChange} />
    
          <div className="console">
            {console.map((text, i) => (
              <div key={i}>{text}</div>
            ))}
          </div>
        </div>
      );
    }
    
    const ChildComp = React.memo(({ onLifecycleChange }) => {
      useEffect(() => {
        onLifecycleChange("mounting ChildComp");
        return () => {
          onLifecycleChange("ummounting ChildComp");
        };
      }, [onLifecycleChange]);
    
      return <div style={{ marginTop: 10 }}>Child Comp</div>;
    });
    

    4.Context不像你期望的那样工作

    • use-context-selector可以解决context带来的性能问题

    • 频繁更新状态(状态共享)的,推荐使用Redux等状态管理工具

    import React, { useState, useContext } from "react";
    import "./styles.css";
    
    const SomeContext = React.createContext({});
    
    export default function App() {
      const [contextValue, setContextValue] = useState({ name: "John", age: 55 });
    
      const onChangeAge = (e) => {
        const age = e.target.value;
        setContextValue((prevContextValue) => ({ ...prevContextValue, age }));
      };
    
      const onChangeName = (e) => {
        const name = e.target.value;
        setContextValue((prevContextValue) => ({ ...prevContextValue, name }));
      };
    
      return (
        <div className="App">
          <SomeContext.Provider value={contextValue}>
            <Wrapper />
            <input value={contextValue.age} onChange={onChangeAge} />
            <input value={contextValue.name} onChange={onChangeName} />
          </SomeContext.Provider>
        </div>
      );
    }
    
    const Wrapper = () => {
      return (
        <div>
          <Name />
          <Age />
        </div>
      );
    };
    
    const Name = () => {
      const { name } = useContext(SomeContext);
      console.log("name rendered");
      return <h1>Name: {name}</h1>;
    };
    
    const Age = () => {
      const { age } = useContext(SomeContext);
      console.log("age rendered");
      return <h1>Age: {age}</h1>;
    };
    
    

    点击demo

    5. React 有一个完整的 API 来处理 children 属性

    React.Children.toArray(children)
    // If you want to use map/forEach:
    React.Children.map(children, fn)
    React.Children.forEach(children, fn)
    
    React.Children.count(children)
    
    React.Children.only(children)
    
    import React from "react";
    import "./styles.css";
    
    export default function App() {
      return (
        <div className="App">
          <Wrapper>
            <h2 style={{ color: "red", margin: 0 }}>Red</h2>
            <h2 style={{ color: "blue" }}>Blue</h2>
            <h2 style={{ color: "green" }}>Green</h2>
          </Wrapper>
          <Wrapper>hello</Wrapper>
        </div>
      );
    }
    
    const Wrapper = ({ children }) => {
      const childrenArray = React.Children.toArray(children);
      console.log(childrenArray);
      return (
        <div style={{ border: "1px solid", padding: 20, margin: 5 }}>
          <div>{children}</div>
          <div>Number of children: {React.Children.count(children)}</div>
          <div>
            children type: <strong>{typeof children}</strong>
          </div>
        </div>
      );
    };
    

    点击demo

    参考文献

    • medium.com/geekculture…

    起源地 » 精读《React — 5 Things That Might Surprise You》 - 掘金

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元