历史
React在2013年开源,在2015引入函数式组件,不过在平常开发中常常被忽略。
ReactJS Core Team 确实大部分红员都曾在推特上公开夸赞过对函数式编程 与 ML 系语言(或其特性)的优势:Sebastian 平常提到 OCaml,Sophie 至少提过 Rust/Kotlin/Swift 而且嫌弃过 Dart 没有 ADT 和 non-nullability,Dan 和 Andrew 的 Redux 主要受 Elm 影响,Dan 曾提过学习高阶函数后省去了一半设计模式,Andrew 的 Recompose 主要利用了函数的组合性,其余成员未知。前端
为何引入class组件:vue
Chenglou: God forbid React api led newcomers into something familiar instead of FP purists’ agendas lol。
难道还不容许 React API 设计得对新人更友好了?
Cristiano: So I guess also making React in JS in the first place was the ultimate trolling.
咱们先把 React 作成 JS 就是找骂啊……
Jordan: They're onto us.
这怎么怪到咱们头上了……
事实是,即便在 FB 内部,也显然不是全部程序员都熟悉函数式编程的概念。作一个前端框架是拿来用的,若是有你们熟悉的概念能够对照,为何刻意要去用你们不熟悉的概念呢?对于迁移至 ES6 Class,主要的目的是为了减小 React 特有的 API,毕竟 并不由于它「接受一个函数」就比 ES6 class 更函数式了……react
在以前class组件一般被认为有更多的功能,例如能够拥有state,能够调用生命周期,而如今在hooks引入以后这个说法就不成立了。之前Function组件没有state,因此也叫SFC(stateless functional component),如今更新叫作FC(functional component)。或许你也据说过,这两类组件中,有一类的性能更好。哪一类呢?不少这方面的性能测试,都是 有缺陷的 ,所以要从这些测试中 得出结论 ,不得不谨慎一点。性能主要取决于你代码要实现的功能(以及你的具体实现逻辑),和使用函数组件仍是类组件,没什么关系。咱们观察发现,尽管函数组件和类组件的性能优化策略 有些不一样 ,可是他们性能上的差别是很微小的。程序员
先看下面两个组件:
函数式组件在父组件中执行的函数的方法:编程
function Greeting() { return <p>Hello</p>; } // Inside React const result = Greeting(props); // <p>Hello</p>
类组件在父组件中先实例化一个对象,而后执行这个对象上的render方法:设计模式
class Greeting extends React.Component { render() { return <p>Hello</p>; } } // Inside React const instance = new Greeting(props); // Greeting {} const result = instance.render(); // <p>Hello</p>
再来看两段代码
一个两秒后执行alter的按钮的函数式组件api
function ProfilePage(props) { const showMessage = () => { alert('我是 ' + props.user); }; const handleClick = () => { setTimeout(showMessage, 2000); }; return ( <button onClick={handleClick}>Function</button> ); }
一个两秒后执行alter的按钮的函数式组件数组
class ProfilePage extends React.Component { showMessage = () => { alert('我是' + this.props.user); }; handleClick = () => { setTimeout(this.showMessage, 2000); }; render() { return <button onClick={this.handleClick}>Class</button>; } }
通常咱们会认为上面两个组件是彻底等价的。开发者常常像上面这样,在函数组件和类组件之间重构代码,却没有意识到他们隐含的差别。然而这两个是有一些差异,你有看出这两个的区别吗?
咱们用一个组件将上面两个组件包裹缓存
function App() { const [user, setUser] = useState('小码王') return ( <div className="App"> <p>{user}</p> <button onClick={() => setUser('小码世界')}>changeName</button> <br/> <ClassButton user={user}/> <FunctionButton user={user}/> </div> ); }
当咱们先点击Class按钮而后再点击changName按钮,alert出的我是小码世界,而咱们先点击Function再点击changName,alter出的我是小码王。
为何会这样呢?
咱们能够看到在函数式组件中user是在props中读取的,而在类组件中user是从this.props中读取的,区别就在this上,在react中props是不可变,而this是可变的,因此当父组件的值改变时this也改变了。
有什么方法使类组件也实现函数式组件的效果呢?性能优化
class ProfilePage extends React.Component { render() { // Capture the props! const props = this.props; const showMessage = () => { alert('我是 ' + props.user); }; const handleClick = () => { setTimeout(showMessage, 2000); }; return <button onClick={handleClick}>Class</button>; } }
在render函数中创造了一个props的闭包,这个问题就解决了,是否是感受段代码比较熟悉,其实在render函数里面的代码抽离出来就是函数式的组件了。因此当函数式组件有render方法之外的功能,就能够实现类组件的任何功能了,这就是hooks了。
在 Hooks 的协议设计考量上,与本来的 React HoC Design 其实会有不少的不一样,主要缘由也许就在于 HoC 总的来讲是 Props 导向的设计,而 Hooks 则是更 functional 风格的调用形态。而且,HoC 可能会倾向于避免产生过多的 HoC 层级,而产生过深的 VDOM Tree。Hooks 大能够更自由地讲更多的 use 方法分离式的调用,也可以获得更大的自由度;
从react team 公布 hooks的概念时,淘宝内部作了一些简单的研究与调研,结论是hooks是类react体系的将来主流编程模式,不管是基于hooks后业务代码会更简练仍是复用更容易,这些都是下降了react 编程的门槛。
尤雨溪也称vue3.0的特性吸收了不少hooks的灵感,并在最新的RFC(意见征求稿)中发布了Function API + Hooks 。
React Hook让无狀态组件拥有了许多只有有狀态组件的能力,如自更新能力(setState,使用useState),访问ref(使用useRef或useImperativeMethods),访问context(使用useContext),使用更高级的setState设置(useReducer),及进行相似生命周期的阶段性方法(useEffect或useLayoutEffect)。
function useReducer(reducer, initialArg,init){ var initialState = void 0; if (init !== undefined) { initialState = init(initialArg); } else { initialState = initialArg; } function dispatch(action){ memoizedState = reducer(memoizedState,action); render(); } memoizedState = memoizedState||initialState; return [memoizedState, dispatch]; } function useState(initialState){ return useReducer((oldState, newState)=>newState, initialState); }
useRef() === useState({current: initialValue })[0]
useCallback和useMemo的参数跟useEffect一致,他们之间最大的区别有是useEffect会用于处理反作用,而前两个hooks不能。
useMemo和useCallback都会在组件第一次渲染的时候执行,以后会在其依赖的变量发生改变时再次执行;而且这两个hooks都返回缓存的值,useMemo返回缓存的变量,useCallback返回缓存的函数。