Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

精读《Function VS Class 组件》 #137

Closed
ascoders opened this issue Mar 14, 2019 · 10 comments
Closed

精读《Function VS Class 组件》 #137

ascoders opened this issue Mar 14, 2019 · 10 comments

Comments

@ascoders
Copy link
Owner

ascoders commented Mar 14, 2019

函数式组件与 Class 组件到底有哪些区别?

从这篇文章切入:how-are-function-components-different-from-classes


精读《Function VS Class 组件》

@ascoders ascoders changed the title 精读《Stateless VS Class 组件》 精读《Function VS Class 组件》 Mar 17, 2019
@ystarlongzi
Copy link

文章里提到的「Capture」特性,可以理解为是有函数的闭包带来的一个「特点」吧

@ascoders
Copy link
Owner Author

@ystarlongzi hooks 的 Capture Value 不是闭包带来的,对比以下代码:

function test() {
  let temp = 5;

  const log = () => {
    setTimeout(() => {
      console.log('3 秒前 temp = 5,现在 temp =', temp);
    }, 3000);
  };

  log();
  temp = 3;
}

test();
// 3 秒前 temp = 5, 现在 temp = 3

以及 Hooks 版本:

const App = () => {
  const [temp, setTemp] = React.useState(5);

  const log = () => {
    setTimeout(() => {
      console.log("3 秒前 temp = 5,现在 temp =", temp);
    }, 3000);
  };

  return (
    <div
      onClick={() => {
        log();
        setTemp(3);
        // 3 秒前 temp = 5,现在 temp = 5
      }}
    >
      xyz
    </div>
  );
}

@ascoders
Copy link
Owner Author

再解释一下原因:

之所以会如此,是因为每次执行 useState 的第二个参数修改值时,可以理解为发生了一次完全拷贝:

// During first render
function Counter() {
  const count = 0; // Returned by useState()
  // ...
  function handleAlertClick() {
    setTimeout(() => {
      alert('You clicked on: ' + count);
    }, 3000);
  }
  // ...
}

// After a click, our function is called again
function Counter() {
  const count = 1; // Returned by useState()
  // ...
  function handleAlertClick() {
    setTimeout(() => {
      alert('You clicked on: ' + count);
    }, 3000);
  }
  // ...
}

// After another click, our function is called again
function Counter() {
  const count = 2; // Returned by useState()
  // ...
  function handleAlertClick() {
    setTimeout(() => {
      alert('You clicked on: ' + count);
    }, 3000);
  }
  // ...
}

每次执行值都固化了下来,所以不管等几秒后执行,值都永远不变,每次 render 间 state 完全独立。

@ascoders
Copy link
Owner Author

但是可以用闭包修复 Class Component 的这个问题,在闭包内存储 props,这样就不会因为 this.props 的变化访问当非当前 props 了!

render() {
  const props = this.props
  // ... use props
}

不过如果用 Component Class,每个 Function 都是一个完整的闭包,可谓是 React 利用闭包自动解决了 props mutable 的问题。

不过 useState 的情况就不是单纯闭包解决的了,可以参考这篇文章 a-complete-guide-to-useeffect 正好也在下期精读里。

@jeffrey-fu
Copy link

是在handleClick这里捕获瞬时的Props吗?

import React from "react";

class ProfilePage extends React.Component {
    showMessage = (props) => {
        alert("Followed " + props.user);
    };

    handleClick = () => {
        const props = this.props; // 在这里捕获瞬时的Props?
        setTimeout(() => this.showMessage(props), 3000);
    };

    render() {
        return <button onClick={this.handleClick}>Follow</button>;
    }
}

export default ProfilePage;

@muzea
Copy link

muzea commented Apr 2, 2019

@jeffrey-fu 是,但我觉得叫做 "捕获瞬时的Props" 好奇怪,觉得翻译成 这里保留了一个对当前props的引用,更好一点。
原文中,props 是不可变的,每次都是构造一个新的props传入,我觉得这样合适一点。

@ascoders
Copy link
Owner Author

ascoders commented Apr 2, 2019

setState 返回了新的引用在下一个渲染被使用,上一个渲染的闭包内值都不会变化。

@yuanyeAjax
Copy link

看了《怎么替代 componentDidUpdate》,把代码改成如下

let mounting = true // 而不是 const mounting = useRef(true);
useEffect(() => {
  if (mounting) {
    mounting = false
  } else {
    fn()
  }
})

似乎mounting的值没变过,一直是true。请问这个是不是Capture特性造成的?搞不太懂Capture特性,但又觉得这个特性很重要,求教。

@yuanyeAjax
Copy link

看了《怎么替代 componentDidUpdate》,把代码改成如下

let mounting = true // 而不是 const mounting = useRef(true);
useEffect(() => {
  if (mounting) {
    mounting = false
  } else {
    fn()
  }
})

似乎mounting的值没变过,一直是true。请问这个是不是Capture特性造成的?搞不太懂Capture特性,但又觉得这个特性很重要,求教。

我好像知道问题所在了。每次组件重新渲染,mounting 都会被重新赋值为true。感觉我这个问题很蠢,哈哈。。。

@ystarlongzi
Copy link

这个「Capture」特性,我仔细想了下,如果从作用域的角度去考虑的话,就一下子释然了

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants