课程目标
入门 React,了解常规用法;
掌握面试中 React 的基础问题;
掌握 React 学习路线;
知识要点 React 简介
React 是一个声明式 ,高效且灵活的用于构建用户界面的 JavaScript 库,使用 React 可以将一些简短、独立的代码片段组合成复杂的 UI 界面,这些代码片段被称为“组件 ”
UI = render(data) -> 单向数据流
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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 var myapp = {} myapp.Model = function ( ) { var val = 0 this .add = function (v ) { if (val < 100 ) val += v } this .sub = function (v ) { if (val > 0 ) val -= v } this .getVal = function ( ) { return val } var self = this var views = [] this .register = function (view ) { views.push (view) } this .notify = function ( ) { for (var i = 0 ; i < views.length ; i++) { views[i].render (self) } } } myapp.View = function (controller ) { var $num = document .getElementById ('num' ) var $incBtn = document .getElementById ('increase' ) var $decBtn = document .getElementById ('decrease' ) this .render = function (model ) { $num.innerText = model.getVal () + 'rmb' } $incBtn.addEventListener ('click' , controller.increase ) $decBtn.addEventListener ('click' , controller.decrease ) } myapp.Controller = function ( ) { var model = null , view = null this .init = function ( ) { model = new myapp.Model () view = new myapp.View (this ) model.register (view) model.notify () } this .increase = function ( ) { model.add (1 ) model.notify () } this .decrease = function ( ) { model.sub (1 ) model.notify () } } (function ( ) { var controller = new myapp.Controller () controller.init () }())
JSX 模版语法 JSX 称为 JS 的语法扩展,将 UI 与逻辑层耦合在组件⾥,⽤ {} 标识。 因为 JSX 语法上更接近 JS ⽽不是 HTML,所以使⽤ camelCase(⼩驼峰命名)来定义属性的名称;JSX ⾥的 class 变成了 className ,⽽ tabindex 则变为 tabIndex 。
JSX 支持表达式 支持 JS 表达式、变量、方法名
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 const name = 'Josh Perez' const element = <h1 > Hello, {name}</h1 > function formatNmae (user ) { return user.firstName + ' ' + user.lastName } const user = { firstName : 'Harper' , lastName : 'Perez' } const element = ( <h1 > Hello, {formatNmae(user)}! </h1 > ) function getGreeting (user ) { if (user) { return <h1 > Hello, {formatNmae(user)}!</h1 > } return <h1 > Hello, Stranger.</h1 > }
JSX 指定属性 1 const element = <img src ={user.avatarUrl} > </img >
JSX 表示对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const element = ( <h1 className ="greeting" > Hello, world! </h1 > ) const element = React .createElement ( 'h1' , {className : 'greeting' }, 'Hello, world!' ) const element = { type : 'h1' , props : { className : 'greeting' , children : 'Hello, world!' } }
将 JSX 渲染为 DOM 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const element = <h1 > Hello, world</h1 > ReactDOM .render (element, document .getElementById ('root' ))function tick ( ) { const element = ( <div > <h1 > Hello, world</h1 > <h2 > It is {new Date().toLocaleTimeString()}.</h2 > </div > ) ReactDOM .render (element, document .getElementById ('root' )) } setInterval (tick, 1000 )
JSX 转 JS JSX 可以当做语法糖,可以在 babel 官⽹中尝试,https://babeljs.io/repl 可以使⽤官⽹提供的 create-react-app npm run eject 来看 babelrc 中的配置,主要使⽤https://www.babeljs.cn/docs/babel-preset-react
1 2 # 安装 babel 及 react 的依赖 npm install core-js @babel/core @babel/preset-env @babel/preset-react @babel/regiser babel-loader @babel/plugin-transform-runtime --sabe-dev
.babelrc
1 2 3 4 5 6 7 8 9 10 { "presets" : [ "@babel/preset-env" , "@babel/preset-es2015" , "@babel/preset-react" ] , "plugins" : [ "@babel/plugin-transform-runtime" ] }
组件 、 Props & state
组件,从概念上类似于 JavaScript 函数。它接受任意的⼊参(即 “props”),并返回⽤于描述⻚⾯展示内容的 React 元素。
组件
1 2 3 4 5 6 7 8 9 function Welcome (props ) { return <h1 > Hello, {props.name}</h1 > } class Welcome extends React.Component { render ( ) { return <h1 > Hello, {this.props.name}</h1 > } }
渲染组件 1 2 3 4 5 6 7 8 9 function Welcome (props ) { return <h1 > Hello, {props.name}</h1 > } const element = <Welcome name ="Sara" /> ReactDOM .render ( element, document .getElementById ('root' ) )
props 所有 React 组件都必须像纯函数一样保护它们的 props 不被更改。
state 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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 function Clock (props ) { return ( <div > <h1 > Hello, world!</h1 > <h2 > It is {props.date.toLocaleTimeString()}.</h2 > </div > ); } function tick ( ) { ReactDOM .render ( <Clock date ={new Date ()} /> , document .getElementById ('root' ) ); } setInterval (tick, 1000 );class Clock extends React.Component { constructor (props ) { super (props); this .state = {date : new Date ()}; } componentDidMount ( ) { this .timerID = setInterval ( () => this .tick (), 1000 ); } componentWillUnmount ( ) { clearInterval (this .timerID ); } tick ( ) { this .setState ({ date : new Date () }); } render ( ) { return ( <div > <h1 > Hello, world!</h1 > <h2 > It is {this.state.date.toLocaleTimeString()}.</h2 > </div > ); } } ReactDOM .render ( <Clock /> , document .getElementById ('root' ) );
setState 构造函数是唯一可以给 this.state 赋值的地方
1 this .setState ({comment : 'Hello' })
setState 更新可能是异步的 出于性能考虑,React 可能会把多个 setState() 调用合并成一个调用。 因为 this.props 和 this.state 可能会异步更新,所以你不要依赖他们的值来更新下一个状态。
1 2 3 4 5 6 7 8 this .setState ({ counter : this .state .counter + this .props .increment , }); this .setState ((state, props ) => ({ counter : state.counter + props.increment }));
State 的更新会被合并
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 constructor(props) { super(props); this.state = { posts: [], comments: [] }; } componentDidMount() { fetchPosts().then(response => { // 相当于 {posts: response.posts, ...otherState} this.setState({ posts: response.posts }); }); fetchComments().then(response => { this.setState({ comments: response.comments }); }); }
数据是向下流动的 state 只在当前的组件里生效,属于组件内的属性,重复实例化相同的组件,内部的内存地址也是不一样的; 例如 Clock 中计时器都是独立的
生命周期
render 是class组件必需的⽅法 获取最新的 props 和 state 在不修改组件 state 的情况下,每次调⽤时都返回相同的结果
constructor 如果不初始化 state 或不进⾏⽅法绑定,则不需要为 React 组件实现构造函数。
通过给 this.state 赋值对象来初始化内部 state。
为事件处理函数绑定实例
1 2 3 4 5 6 7 8 9 10 11 12 13 constructor(props) { super(props); // 不要在这里调用 this.setState() this.state = { counter: 0 }; this.handleClick = this.handleClick.bind(this); } // 避免将 props 的值复制给 state constructor(props) { super(props); // 不要这样做 this.state = { color: props.color }; }
componentDidMount 会在组件挂载后(插⼊ DOM 树中)⽴即调⽤ 依赖于 DOM 节点的初始化应该放在这⾥,如需通过⽹络请求获取数据; 可以在此⽣命周期⾥加 setState,但发⽣在浏览器更新屏幕之前,会导致性能问题; 有更新在render阶段的 constructor 中 init State,但有更新可以在此⽅法时 setState
componentDidUpdate 6 1 componentDidUpdate(prevProps, prevState, snapshot)
会在更新后会被立即调用。首次渲染不会执行此方法。
当组件更新后,可以在此处对 DOM 进行操作。如果你对更新前后的 props 进行了比较,也可以选择在此处进行网络请求。(例如,当 props 未发生变化时,则不会执行网络请求)。
1 2 3 4 5 6 componentDidUpdate(prevProps) { // 典型用法(不要忘记比较 props):加条件判断,不然死循环 if (this.props.userID !== prevProps.userID) { this.fetchData(this.props.userID); } }
如果组件实现了 getSnapshotBeforeUpdate() 生命周期(不常用),则它的返回值将作为 componentDidUpdate() 的第三个参数 “snapshot” 参数传递。否则此参数将为 undefined。 如果 shouldComponentUpdate() 返回值为 false,则不会调用 componentDidUpdate()。
componentWillUnmount componentWillUnmount() 会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等。
componentWillUnmount() 中不应调用 setState(),因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它。
shouldComponentUpdate (不常用)
6 1 shouldComponentUpdate(nextProps, nextState)
根据 shouldComponentUpdate() 的返回值,判断 React 组件的输出是否受当前 state 或 props 更改的影响。默认行为是 state 每次发生变化组件都会重新渲染。 作为性能优化使⽤,返回false可以跳过re-render shouldComponentUpdate() 返回 false,不会调⽤ UNSAFE_componentWillUpdate(),render() 和 componentDidUpdate()。
getDerivedStateFromProps (不常用) 是为了取代 componentWillReceiveProps 和 componentWillUpdate 设置的根据 props 的变化改变 state,它应返回⼀个对象来更新 state,如果返回 null 则不更新任何内容。
在使⽤此⽣命周期时,要注意把传⼊的 prop 值和之前传⼊的 prop 进⾏⽐较;
因为这个⽣命周期是静态⽅法,同时要保持它是纯函数,不要产⽣副作⽤;
getSnapshotBeforeUpdate (不常用)
6 1 getSnapshotBeforeUpdate(prevProps, prevState)
getSnapshotBeforeUpdate() 在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期的任何返回值将作为参数传递给 componentDidUpdate()。
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 class ScrollingList extends React.Component { constructor (props ) { super (props); this .listRef = React .createRef (); } getSnapshotBeforeUpdate (prevProps, prevState ) { if (prevProps.list .length < this .props .list .length ) { const list = this .listRef .current ; return list.scrollHeight - list.scrollTop ; } return null ; } componentDidUpdate (prevProps, prevState, snapshot ) { if (snapshot !== null ) { const list = this .listRef .current ; list.scrollTop = list.scrollHeight - snapshot; } } render ( ) { return ( <div ref ={this.listRef} > {/* ...contents... */}</div > ); } }
getDerivedStateFromError (不常用)
配合Error boundaries使⽤ 此⽣命周期会在后代组件抛出错误后被调⽤。 它将抛出的错误作为参数,并返回⼀个值以更新 state;
componentDidCatch (不常用) componentDidCatch() 会在“提交”阶段被调⽤,因此允许执⾏副作⽤。 它应该⽤于记录错误之类的情况;
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 class ErrorBoundary extends React.Component { constructor (props ) { super (props); this .state = { hasError : false }; } static getDerivedStateFromError (error ) { return { hasError : true }; } componentDidCatch (error, info ) { logComponentStackToMyService (info.componentStack ); } render ( ) { if (this .state .hasError ) { return <h1 > Something went wrong.</h1 > ; } return this .props .children ; } }
UNSAFE_componentWillMount (不建议使⽤) UNSAFE_componentWillMount() 在挂载之前被调⽤; 它在 render() 之前调⽤,因此在此⽅法中同步调⽤ setState() 不会⽣效; 需要的话⽤componentDidMount替代。
UNSAFE_componentWillReceiveProps (不建议使⽤) UNSAFE_componentWillReceiveProps() 会在已挂载的组件接收新的 props 之前被调⽤; 如果你需要更新状态以响应 prop 更改(例如,重置它),你可以⽐较 this.props 和 nextProps 并在此⽅法中使⽤ this.setState() 执⾏ state 转换。
UNSAFE_componentWillUpdate (不建议使⽤)
当组件收到新的 props 或 state 时,会在渲染之前调⽤ UNSAFE_componentWillUpdate();
使⽤此作为在更新发⽣之前执⾏准备更新的机会;
初始渲染不会调⽤此⽅法; 如果 shouldComponentUpdate() 返回 false,则不会调⽤ UNSAFE_componentWillUpdate();
事件处理 语法格式
在JSX元素上添加事件,通过on*EventType这种内联⽅式添加,命名采⽤⼩驼峰式(camelCase)的形式,⽽不是纯⼩写(原⽣HTML中对DOM元素绑定事件,事件类型是⼩写的);
⽆需调⽤addEventListener进⾏事件监听,也⽆需考虑兼容性,React已经封装好了⼀些的事件类型属性;
使⽤ JSX 语法时你需要传⼊⼀个函数作为事件处理函数,⽽不是⼀个字符串;
不能通过返回 false 的⽅式阻⽌默认⾏为。你必须显式的使⽤ preventDefault;
1 2 3 4 5 6 7 8 9 10 11 12 function ActionLink ( ) { function handleClick (e ) { e.preventDefault (); console .log ('The link was clicked.' ); } return ( <a href ="#" onClick ={handleClick} > Click me </a > ); }
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 class Toggle extends React.Component { constructor (props ) { super (props); this .state = {isToggleOn : true }; this .handleClick = this .handleClick .bind (this ); } handleClick ( ) { this .setState (state => ({ isToggleOn : !state.isToggleOn })); } render ( ) { return ( <button onClick ={this.handleClick} > {this.state.isToggleOn ? 'ON' : 'OFF'} </button > ); } } ReactDOM .render ( <Toggle /> , document .getElementById ('root' ) );
为什么要绑定 this
6 1 2 3 4 5 6 7 function createElement (dom, params) { var domObj = document.createElement(dom) domObj.onclick = params.onclick domObj.innerHTML = params.conent return domObj } // createElement 的 onClick 函数是绑定到 domObj 上的,如果 this 不显示绑定,不会绑定到 Toggle 上
绑定 this 的方法:
不显示使用 bind
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class LoggingButton extends React.Component { handleClick = () => { console .log ('this is:' , this ); } render ( ) { return ( <button onClick ={this.handleClick} > Click me </button > ); } }
箭头函数,问题:每次 render 都会创建不同的回调函数,如果该回调函数作为 props 传入子组件,每次子组件都要 re-render
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class LoggingButton extends React.Component { handleClick ( ) { console .log ('this is:' , this ); } render ( ) { return ( <button onClick ={() => this.handleClick()}> Click me </button > ); } }
接收参数
事件对象 e 会被作为第⼆个参数传递;
通过箭头函数的⽅式,事件对象必须显式的进⾏传递;
通过 Function.prototype.bind 的⽅式,事件对象以及更多的参数将会被隐式的进⾏传递;
1 2 <button onClick={(e ) => this .deleteRow (id, e)}>Delete Row </button> <button onClick ={this.deleteRow.bind(this, id )}> Delete Row</button >
条件渲染 if else 渲染 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 34 35 36 37 38 class LoginControl extends React.Component { constructor (props ) { super (props); this .handleLoginClick = this .handleLoginClick .bind (this ); this .handleLogoutClick = this .handleLogoutClick .bind (this ); this .state = {isLoggedIn : false }; } handleLoginClick ( ) { this .setState ({isLoggedIn : true }); } handleLogoutClick ( ) { this .setState ({isLoggedIn : false }); } render ( ) { const isLoggedIn = this .state .isLoggedIn ; let button; if (isLoggedIn) { button = <LogoutButton onClick ={this.handleLogoutClick} /> ; } else { button = <LoginButton onClick ={this.handleLoginClick} /> ; } return ( <div > <Greeting isLoggedIn ={isLoggedIn} /> {button} </div > ); } } ReactDOM .render ( <LoginControl /> , document .getElementById ('root' ) );
与运算符 && 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function Mailbox (props ) { const unreadMessages = props.unreadMessages ; return ( <div > <h1 > Hello!</h1 > {unreadMessages.length > 0 && <h2 > You have {unreadMessages.length} unread messages. </h2 > } </div > ); } const messages = ['React' , 'Re: React' , 'Re:Re: React' ];ReactDOM .render ( <Mailbox unreadMessages ={messages} /> , document .getElementById ('root' ) );
返回 false 的表达式,会跳过元素,但会返回该表达式
1 2 3 4 5 6 render() { const count = 0 return ( <div>{count && <h1>Message: {count}</h1>}</div> ) }
三元运算符 1 2 3 4 5 6 7 8 9 10 11 render() { const isLoggedIn = this.state.isLoggedIn; return ( <div> {isLoggedIn ? <LogoutButton onClick={this.handleLogoutClick} /> : <LoginButton onClick={this.handleLoginClick} /> } </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 34 35 36 37 38 39 40 41 function WarningBanner (props ) { if (!props.warn ) { return null ; } return ( <div className ="warning" > Warning! </div > ); } class Page extends React.Component { constructor (props ) { super (props); this .state = {showWarning : true }; this .handleToggleClick = this .handleToggleClick .bind (this ); } handleToggleClick ( ) { this .setState (state => ({ showWarning : !state.showWarning })); } render ( ) { return ( <div > <WarningBanner warn ={this.state.showWarning} /> <button onClick ={this.handleToggleClick} > {this.state.showWarning ? 'Hide' : 'Show'} </button > </div > ); } } ReactDOM .render ( <Page /> , document .getElementById ('root' ) );
列表 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 function NumberList (props ) { const numbers = props.numbers ; const listItems = numbers.map ((number ) => <li key ={number.toString()} > {number} </li > ); return ( <ul > {listItems}</ul > ); } const numbers = [1 , 2 , 3 , 4 , 5 ];ReactDOM .render ( <NumberList numbers ={numbers} /> , document .getElementById ('root' ) );
若没有 key,会 warning a key should be provided for list items; key 可以帮助 react diff,最好不要用 index 作为 key,会导致性能变差; 如果不指定显式的 key 值,那么 React 将默认使用索引用作为列表项目的 key 值。
key 注意点
key 要保留在 map 的遍历元素上
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 function ListItem (props ) { const value = props.value ; return ( <li key ={value.toString()} > {value} </li > ); } function NumberList (props ) { const numbers = props.numbers ; const listItems = numbers.map ((number ) => <ListItem key ={number.toString()} value ={number} /> ); return ( <ul > {listItems} </ul > ); } const numbers = [1 , 2 , 3 , 4 , 5 ];ReactDOM .render ( <NumberList numbers ={numbers} /> , document .getElementById ('root' ) );
key 只是在兄弟节点之间必须唯一
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 function Blog (props ) { const sidebar = ( <ul > {props.posts.map((post) => <li key ={post.id} > {post.title} </li > )} </ul > ); const content = props.posts .map ((post ) => <div key ={post.id} > <h3 > {post.title}</h3 > <p > {post.content}</p > </div > ); return ( <div > {sidebar} <hr /> {content} </div > ); } const posts = [ {id : 1 , title : 'Hello World' , content : 'Welcome to learning React!' }, {id : 2 , title : 'Installation' , content : 'You can install React from npm.' } ]; ReactDOM .render ( <Blog posts ={posts} /> , document .getElementById ('root' ) );
在 JSX 中嵌入 map()
1 2 3 4 5 6 7 8 9 10 function NumberList (props ) { const numbers = props.numbers ; return ( <ul > {numbers.map((number) => <ListItem key ={number.toString()} value ={number} /> )} </ul > ); }
补充知识点 React 如何预防 XSS 1 2 3 const title = response.potentialyMaliciousInput const element = <h1 > {title}</h1 >
React DOM 在渲染所有输入内容之前,默认会进行转义。
部分源码:
6 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 for (index = match.index; index < str.length; index++) { switch (str.charCodeAt(index)) { case 34: // " escape = '"' break case 38: // & escape = '&' break case 39: // ' escape = ''' break case 60: // < escape = '&;t;' break case 62: // > escape = '>' break default: continue } }
关于 setState 的异步 异步目的:batch 处理、性能优化
合成事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class App extends Component { state = {val : 0 } increment = () => { this .setState ({val : this .state .val + 1 }) console .log (this .state .val ) } render ( ) { return ( <div onClick ={this.increment} > {`Counter is: ${this.state.val}`} </div > ) } }
生命周期
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class App extends Component { state = {val : 0 } componentDidiMount ( ) { this .setState ({val : this .state .val + 1 }) console .log (this .state .val ) } render ( ) { return ( <div > {`Counter is: ${this.state.val}`} </div > ) } }
原生事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class App extends Component { state = {val : 0 } changeValue = () => { this .setState ({val : this .state .val + 1 }) console .log (this .state .val ) } componentDidiMount ( ) { document .body .addEventListener ('click' , this .changeValue , false ) } render ( ) { return ( <div > {`Counter is: ${this.state.val}`} </div > ) } }
setTimeout
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class App extends Component { state = {val : 0 } componentDidiMount ( ) { setTimeout (_ => { this .setState ({val : this .state .val + 1 }) console .log (this .state .val ) }, 0 ) } render ( ) { return ( <div > {`Counter is: ${this.state.val}`} </div > ) } }
批处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class App extends Component { state = {val : 0 } batchUpdates = () => { this .setState ({val : this .state .val + 1 }) this .setState ({val : this .state .val + 1 }) this .setState ({val : this .state .val + 1 }) } render ( ) { return ( <div onClick ={this.batchUpdates} > {`Counter is: ${this.state.val}`} // 1 </div > ) } }
setState 只在合成事件和⽣命周期中是“异步”的,在原⽣事件和 setTimeout 中都是同步的;
setState的“异步”并不是说内部由异步代码实现,其实本身执⾏的过程和代码都是同步的, 只是合成事件和钩⼦函数的调⽤顺序在更新之前,导致在合成事件和钩⼦函数中没法⽴⻢拿到更新后的值,形式了所谓的“异步”, 当然可以通过第⼆个参数 setState(partialState, callback) 中的callback拿到更新后的结果。
setState 的批量更新优化也是建⽴在“异步”(合成事件、钩⼦函数)之上的,在原⽣事件和 setTimeout 中不会批量更新,在“异步”中如果对同⼀个值进⾏多次 setState , setState 的批量更新策略会对其进⾏覆盖,取Y后⼀次的执⾏,如果是同时 setState 多个不同的值,在更新时会对其进⾏合并批量更新。
create-react-class 自动绑定 this
1 2 3 4 5 6 7 8 9 10 11 12 13 14 var createReactClass = require ('create-react-class' );var LoggingButton = createReactClass ({ handleClick : function ( ) { console .log ('this is:' , this ); }, render : function ( ) { return ( <button onClick ={this.handleClick} > Click me </button > ); } });