本文最后更新于 2024-03-22T23:32:48+00:00
发展要史 1、JS 能操作 DOM
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <div id="app" > <h1 > Hello</h1 > <h2 > my name is</h2 > <h3 > react</h3 > </div>function createElememt (tag, props, children ) { const el = document .createElememt (tag) Object .entries (props).forEach (([key, value] ) => { el.setAttribute (key, value) }) children.forEach (child => el.appendChild (child)) }createElememt ('div' , { id : 'app' }, [ createElememt ('h1' , null , ['Hello' ]), createElememt ('h2' , null , ['my name is' ]), createElememt ('h3' , null , ['react' ]), ])
2、根据createElememt
就能生成对应的 DOM 结构,但发现有点麻烦,所以 React 让 Babel 帮忙实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 const App = ( ) => ( <div id ="app" > <h1 > Hello</h1 > <h2 > my name is</h2 > <h3 > react</h3 > </div > )const App = ( ) => React .createElement ("div" , { id : "app" }, React .createElement ("h1" , null , "Hello" ), React .createElement ("h2" , null , "my name is" ), React .createElement ("h3" , null , "react" ) );
总结:React 核心是写 HTML 片段(JSX),然后让 Babel 编译为可执行的渲染函数,调用该函数能创建 DOM,但 React 做的事情不止于此,但可以这样简单的理解。
基础 创建一个基础的 React 项目
1 npx create-react-app projectName
组件分类 类组件 基础写法 1 2 3 4 5 6 import React , { Component } from 'react' export default class ClassComName extends Component { render ( ) { return <div > I am Class Component</div > } }
响应式数据写法 this.state
、this.setState
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import React , { Component } from "react" ;export default class ClassComName extends Component { constructor ( ) { super (); this .state = { name : "Class Component~" , number : 1 , }; } handleClick ( ) { this .setState ({ number : this .state .number + 1 }); } render ( ) { return ( <div > <h1 > I am 【{this.state.name}】</h1 > <button onClick ={() => this.handleClick()}>Add Number</button > <div > Number: {this.state.number}</div > <hr /> </div > ); } }
父子传参 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import React , { Component } from "react" ;export default class ClassComName extends Component { constructor (props ) { super (props); this .state = { name : "Class Component~" , number : props.initNumber , }; } handleClick ( ) { const number = this .state .number + 1 ; this .setState ({ number }); this .props .callback (number , this .state .name ); } render ( ) { return ( <div > <h1 > I am 【{this.state.name}】</h1 > <div > props: {JSON.stringify(this.props)}</div > <button onClick ={() => this.handleClick()}>Add Number</button > <div > Number: {this.state.number}</div > <hr /> </div > ); } }
生命周期 初始化阶段 constructor
:初始化调用,初始化实例状态(state)和绑定事件处理器,不推荐在这里做数据获取或订阅操作。static getDerivedStateFromProps
:在实例创建及后续每次 props 改变时都会调用,返回对象将与当前 state 合并,生成新的 statecomponentWillMount
:已弃用 ,渲染之前执行,若有了getDerivedStateFromProps
或getSnapshotBeforeUpdate
时不执行render
:执行,生成新的虚拟 DOM 用于 DIFF(若需要),但还未去更新 DOM 哦componentDidMount
:渲染完成时调用,常用于网络请求、订阅或者手动 DOM 操作等。
更新阶段 componentWillReceiveProps
:已弃用 ,props 改变时触发,建议用getDerivedStateFromProps
shouldComponentUpdate
:更新拦截,根据返回的布尔值决定是否更新。可用于数据提交中时锁定其他操作componentWillUpdate
:已弃用 ,更新前调用,建议用getSnapshotBeforeUpdate
render
:执行,生成新的虚拟 DOM 用于 DIFF(若需要),但还未去更新 DOM 哦getSnapshotBeforeUpdate
:获取更新 DOM 前的快照,获取元素某些信息(如滚动位置)componentDidUpdate
:更新完成时调用,谨慎调用setState
会触发重新渲染
销毁阶段 componentWillUnmount
:销毁之前调用,用于清理任何定时器、取消网络请求、解绑事件监听器等资源清理工作。
函数式组件 基础写法 1 2 3 export default function FuncComName ( ) { return <div > I am Function Component</div > }
响应式数据写法 useState
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import { useState } from "react" ;export default function FuncComName ( ) { const [name] = useState ("Function Component~" ); const [number , setNumber] = useState (1 ); const handleClick = ( ) => { setNumber (number + 1 ); }; return ( <div > <h1 > I am 【{name}】</h1 > <button onClick ={() => handleClick()}>Add Number</button > <div > Number: {number}</div > <hr /> </div > ); }
父子传参 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import { useState } from "react" ;export default function FuncComName (props ) { const [name] = useState ("Function Component~" ); const [number , setNumber] = useState (props.initNumber ); const handleClick = ( ) => { const _number = number + 1 ; setNumber (_number); props.callback (_number, name); }; return ( <div > <h1 > I am 【{name}】</h1 > <div > props: {JSON.stringify(props)}</div > <button onClick ={() => handleClick()}>Add Number</button > <div > Number: {number}</div > <hr /> </div > ); }
生命周期 函数式组件是没有生命周期的,只有一些钩子函数来替代生命周期。
useEffect 处理副作用。
1 2 3 useEffect (fun, deps) fun:它的返回值将在下一次 fun 执行前调用 deps:数组,当值改变时,执行上一次的 fun 返回值,然后再执行 fun
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 useEffect (() => { console .log ('getDerivedStateFromProps' ) }, []) useEffect (() => { console .log ('getDerivedStateFromProps' ) }, [props]) useEffect (() => { console .log ('componentDidMount' ) }, []) useEffect (() => { return () => { console .log ('componentWillUnmount' ) } }, []) useEffect (() => { console .log ('componentDidUpdate' ) })
补充知识 Fiber 参考资料:万字长文介绍 React Fiber 架构的原理和工作模式 带你彻底读懂 React VDOM DIFF - 掘金 Fiber:本质是 JS 对象,也可以称为 React 版的虚拟 DOM。链表结构
Vue vs React Vue:使用 template,写法比较固定,但编译时可以做很多优化。 React:使用 JSX,写法非常灵活