JSX是JavaScript的语法扩展,用来描述用户界面javascript
因为 JSX 编译后会调用 React.createElement
方法,因此在包含JSX的模块中必须先引入React
模块html
<div><span>
。自定义组件标签名以大写字母开头 <MyComponents.DatePicker color="blue" />
标签名不能为表达式java
function Story(props) { // 错误!JSX 标签名不能为一个表达式。 return <components[props.storyType] story={props.story} />; } function Story(props) { // 正确!JSX 标签名能够为大写开头的变量。 const SpecificStory = components[props.storyType]; return <SpecificStory story={props.story} />; }
true
Babel转译器会将JSX转译为React.createElement方法,该方法首先会进行一些避免bug的检查,以后返回React元素(一个JavaScript对象)。JSX 只是为 React.createElement(component, props, ...children)
方法提供的语法糖。react
React DOM 使 React 元素 和 浏览器 DOM 的数据内容保持一致npm
经过ReactDOM.render()
将React元素渲染到页面上json
React元素是一个不可变的(immutable),元素被建立以后没法改变其内容和属性数组
若要更新,建立一个新的React元素,从新调用ReactDOM.render()
渲染 浏览器
React DOM 首先会比较元素内容前后的不一样,而在渲染过程当中只会更新改变了的部分性能优化
独立的、可复用的部件服务器
接收任意的输入值(称之为“props”),并返回一个React元素。
函数定义
function Welcome(props) { return <h1>Hello, {props.name}</h1>; }
类定义
class Welcome extends React.Component { render() { return <h1>Hello, {this.props.name}</h1>; } }
function Welcome(props) { return <h1>Hello, {props.name}</h1>; } ReactDOM.render( <Welcome name="Sara" />, document.getElementById('root') );
调用自定义组件,组件上的属性集合到props对象上传递给组件
全部的React组件必须像纯函数(输入值不会被改变,输入值相同总会输出相同的结果)那样使用它们的props。
PropTypes
类型检查
PropTypes
包含一整套验证器,可用于确保你接收的数据是有效的。
当你给属性传递了无效值时,JavsScript 控制台将会打印警告。出于性能缘由,propTypes
只在开发模式下进行检查。
注意:React.PropTypes
自 React v15.5 起已弃用。请使用prop-types
库代替。
defaultProps
属性默认值
类型检查发生在 defaultProps
赋值以后,因此类型检查也会应用在 defaultProps
上面。
状态,组件内部维护
this.state
的地方this.props
和this.state
的更新多是异步的,React 能够将多个setState()
调用合并成一个调用来提升性能。
// Wrong this.setState({ counter: this.state.counter + this.props.increment, }); // Correct this.setState((prevState, props) => ({ counter: prevState.counter + props.increment }));
setState()
是一个请求
// 不依赖state计算时书写 // callback在setState执行完成同时组件被重渲以后执行,等同于componentDidUpdate的做用 this.setState({ counter: 2 }, [callback]); // 依赖state以前的状态 this.setState((prevState) => { return {counter: prevState.quantity + 1}; });
defaultProps
, propTypes
constructor()
- 构造函数是初始化状态的合适位置。UNSAFE_componentWillMount()
- 装配发生前调用,在这方法里同步地设置状态将不会触发重渲render()
- 渲染时调用componentDidMount()
- 组件装配完成时调用,初始化DOM节点,发送网络请求,事件订阅UNSAFE_componentWillReceiveProps(nextProps)
- 装配了的组件接收到新属性前调用,即便属性未有任何改变,也可能会调用该方法,请确保比较先后值shouldComponentUpdate(nextProps, nextState)
- 当接收到新属性或状态时在渲染前调用,该方法并不会在初始化渲染或当使用forceUpdate()
时被调用UNSAFE_componentWillUpdate()
- 接收到新属性或状态时时调用,不能在这调用this.setState()
getDerivedStateFromProps(nextProps, prevState)
- 组件实例化后和接受新属性时调用,调用this.setState()
一般不会触发,返回响应属性getSnapshotBeforeUpdate(prevProps, prevState)
- 在最新的渲染输出提交给DOM前将会当即调用,这一辈子命周期返回的任何值将会 做为参数被传递给componentDidUpdate()
componentDidUpdate(prevProps, prevState)
- 更新发生后当即调用,不会在初始化渲染时调用。操做DOM,发送请求componentWillUnmount()
- 组件被卸载和销毁以前马上调用。清理定时器、请求、DOM节点、事件订阅类的方法默认不会绑定this
,解决办法:
使用实验性的属性初始化器
class LoggingButton extends React.Component { // This syntax ensures `this` is bound within handleClick. // Warning: this is *experimental* syntax. handleClick = () => { console.log('this is:', this); } render() { return ( <button onClick={this.handleClick}> Click me </button> ); } }
使用箭头函数定义回调函数
class LoggingButton extends React.Component { handleClick() { console.log('this is:', this); } render() { // This syntax ensures `this` is bound within handleClick return ( <button onClick={(e) => this.handleClick(e)}> Click me </button> ); } }
每次渲染时会建立一个不一样的回调函数,若是回调函数做为一个属性值传入低阶组件,会致使额外渲染
React封装的一个合成事件SyntheticEvent
事件处理函数返回false
不会再阻止事件传播, 因此必须得手动触发e.stopPropagation()
和e.preventDefault()
方法。
boolean bubbles boolean cancelable DOMEventTarget currentTarget boolean defaultPrevented number eventPhase boolean isTrusted DOMEvent nativeEvent void preventDefault() boolean isDefaultPrevented() void stopPropagation() boolean isPropagationStopped() DOMEventTarget target number timeStamp string type
class Popper extends React.Component{ constructor(){ super(); this.state = {name:'Hello world!'}; } preventPop(name, e){ //事件对象e要放在最后 e.preventDefault(); alert(name); } render(){ return ( <div> <p>hello</p> {/* Pass params via bind() method. */} <a onClick={this.preventPop.bind(this, this.state.name)}>Click</a> <a onClick={(e) => {this.preventPop(this.state.name, e)}}>Click</a> </div> ); } }
在render函数中使用条件语句实现条件渲染,可使用变量来储存元素
在JSX中使用条件运算符组成表达式实现条件渲染
让 render
方法返回 null
隐藏组件
经过使用{}
在JSX内构建一个元素集合
key
每一个列表元素须要有key
属性
keys
能够在DOM中的某些元素被增长或删除的时候帮助React
识别哪些元素发生了变化
key
会做为给React
的提示,但不会传递给你的组件
function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) => <li key={number.toString()}> {number} </li> ); return ( <ul>{listItems}</ul> ); }
经过onChange+setState控制状态改变,使React控制组件状态
<input type="text" value={this.state.value} onChange={this.handleChange} />
<textarea value={this.state.value} onChange={this.handleChange} />
<select value={this.state.value} onChange={this.handleChange}> <option value="grapefruit">Grapefruit</option> <option value="lime">Lime</option> <option value="coconut">Coconut</option> <option value="mango">Mango</option> </select>
当你有处理多个受控的input
元素时,你能够经过给每一个元素添加一个name
属性,来让处理函数根据 event.target.name
的值来选择作什么。
经过ref获取获取DOM
在 React 的生命周期中,表单元素上的 value
属性将会覆盖 DOM 中的值
使用defaultValue指定初始值
使用 react 常常会遇到几个组件须要共用状态数据的状况。
这种状况下,咱们最好将这部分共享的状态提高至他们最近的父组件当中进行管理。
经过子代props.children
或者自定义属性承载组件
使用组合实现包含关系,动态定义传入容器的子组件
使用组合实现特殊实例,替换继承的做用,好比说Prom
React v16.3
React.createRef()
class CustomTextInput extends React.Component { constructor(props) { super(props); // 建立 ref 存储 textInput DOM 元素 this.textInput = React.createRef(); this.buttonInput = React.createRef(); this.focusTextInput = this.focusTextInput.bind(this); this.setTextInputRef = element => { this.buttonInput = element; }; } focusTextInput() { // 直接使用原生 API 使 text 输入框得到焦点 // 注意:经过 "current" 取得 DOM 节点 this.textInput.current.focus(); } render() { // 告诉 React 咱们想把 <input> ref 关联到构造器里建立的 `textInput` 上 return ( <div> <input type="text" ref={this.textInput} /> <input type="button" value="Focus the text input" onClick={this.focusTextInput} ref={this.setTextInputRef} /> </div> ); } }
ref
的更新会发生在componentDidMount
或 componentDidUpdate
生命周期钩子以前。
开发模式下React会更大更慢,所以必定要用生产版本部署
?react_perf
(例如, http://localhost:3000/?react_perf
)。使用SCU控制
支持ES6的状况下,使用Object.assign/扩展运算符返回新数据,防止引用类型数据突变
使用Immutable.js保持数据不可变,下降出错率
key
属性,开发者能够示意哪些子元素多是稳定的。共享那些被认为对于一个组件树而言是“全局”的数据,例如当前认证的用户、主题或首选语言。
不要仅仅为了不在几个层级下的组件传递 props 而使用 context,它是被用于在多个层级的多个组件须要访问相同数据的情景。
const {Provider, Consumer} = React.createContext(defaultValue); <Provider value={/* some value */}> <Consumer> {value => /* render something based on the context value */} </Consumer>
每当Provider的值发送改变时, 做为Provider后代的全部Consumers都会从新渲染。 从Provider到其后代的Consumers传播不受shouldComponentUpdate方法的约束,所以即便祖先组件退出更新时,后代Consumer也会被更新。
聚合一个子元素列表,代替组件根元素使用
<></>
是 <React.Fragment/>
的语法糖。
<></>
语法不能接受键值或属性,要添加key属性须要使用<React.Fragment/>
Portals 提供了一种将子节点渲染到父组件之外的 DOM 节点的方式。
ReactDOM.createPortal(child, container) // child 可渲染的React子元素 // container DOM元素
虽然DOM树中的位置平行,但React树中组件仍在根组件树中,树组件仍能捕获到事件
错误边界组件用于捕获其子组件树 JavaScript 异常,记录错误并展现一个回退的 UI 。
错误边界在渲染期间,生命周期方法内,以及整个组件树构造函数内捕获错误。
错误边界没法捕获事件处理函数内部的错误,事件处理函数内部的错误使用try...catch捕获。
错误边界没法捕获异步事件的错误,异步事件的错误在回调函数内部自行处理。
错误边界没法捕获服务器端渲染和错误边界自身抛出的错误。
自 React 16 开始,任何未被错误边界捕获的错误将会卸载整个 React 组件树。
若是一个类组件定义了 componentDidCatch(error, info):
方法,则该组件是一个错误边界组件。
class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } componentDidCatch(error, info) { // error: 错误信息 // info: 组件栈追踪 this.setState({ hasError: true }); logErrorToMyService(error, info); } render() { if (this.state.hasError) { // You can render any custom fallback UI return <h1>Something went wrong.</h1>; } return this.props.children; } }
错误边界的粒度彻底取决于你的应用。你能够将其包装在最顶层的路由组件并为用户展现一个 “发生异常(Something went wrong)“的错误信息,就像服务端框架一般处理崩溃同样。你也能够将单独的插件包装在错误边界内部以保护应用不受该组件崩溃的影响。
Web Components是W3C规范的新功能,提供自定义元素封装功能。至关于在DOM的层面封装一个自定义元素,元素的展现和特性在Web Components内部实现。在React眼中,一个Web Component和一个普通元素无异。
React组件是React层面的元素单元,封装有UI、逻辑、数据响应。
对组件逻辑进行重用的一种抽象模式
高阶组件就是一个函数,且该函数接受一个组件做为参数,并返回一个新的组件
const EnhancedComponent = higherOrderComponent(WrappedComponent);
经过将原组件 包裹 在容器组件里面的方式来 组合 使用原组件。高阶组件就是一个没有反作用的纯函数。
请使用组合性高阶组件,避免使用更改性高阶组件
在高阶组件内部修改(或以其它方式修改)原组件的原型属性,称为更改性高阶组件
function logProps(InputComponent) { InputComponent.prototype.componentWillReceiveProps(nextProps) { console.log('Current props: ', this.props); console.log('Next props: ', nextProps); } // 咱们返回的原始组件实际上已经 // 被修改了。 return InputComponent; } // EnhancedComponent会记录下全部的props属性 const EnhancedComponent = logProps(InputComponent);
在高阶组件内部使用组合返回一个新的组件,称为组合型高阶组件
function logProps(WrappedComponent) { return class extends React.Component { componentWillReceiveProps(nextProps) { console.log('Current props: ', this.props); console.log('Next props: ', nextProps); } render() { // 用容器组件组合包裹组件且不修改包裹组件,这才是正确的打开方式。 return <WrappedComponent {...this.props} />; } } }
高阶组件应该传递与它要实现的功能点无关的props属性
render() { // 过滤掉与高阶函数功能相关的props属性, // 再也不传递 const { extraProp, ...passThroughProps } = this.props; // 向包裹组件注入props属性,通常都是高阶组件的state状态 // 或实例方法 const injectedProp = someStateOrInstanceMethod; // 向包裹组件传递props属性 return ( <WrappedComponent injectedProp={injectedProp} {...passThroughProps} /> ); }
最大化使用组合
const ConnectedComment = connect(commentSelector, commentActions)(Comment);
connect函数返回一个高阶组件
使用compose代替高阶组件嵌套使用
const enhance = compose( // 这些都是单参数的高阶组件 withRouter, connect(commentSelector) ) const EnhancedComponent = enhance(WrappedComponent)
高阶组件返回组件命名
function withSubscription(WrappedComponent) { class WithSubscription extends React.Component {/* ... */} WithSubscription.displayName = `WithSubscription(${getDisplayName(WrappedComponent)})`; return WithSubscription; } function getDisplayName(WrappedComponent) { return WrappedComponent.displayName || WrappedComponent.name || 'Component'; }
refs不会被传递到被包裹组件,React16.3版本中加入React.forwardRef解决这个问题
function logProps(Component) { class LogProps extends React.Component { componentDidUpdate(prevProps) { console.log('old props:', prevProps); console.log('new props:', this.props); } render() { const {forwardedRef, ...rest} = this.props; // Assign the custom prop "forwardedRef" as a ref return <Component ref={forwardedRef} {...rest} />; } } // Note the second param "ref" provided by React.forwardRef. // We can pass it along to LogProps as a regular prop, e.g. "forwardedRef" // And it can then be attached to the Component. function forwardRef(props, ref) { return <LogProps {...props} forwardedRef={ref} />; } // These next lines are not necessary, // But they do give the component a better display name in DevTools, // e.g. "ForwardRef(logProps(MyComponent))" const name = Component.displayName || Component.name; forwardRef.displayName = `logProps(${name})`; return React.forwardRef(forwardRef); }
<DataProvider render={data => ( <h1>Hello {data.target}</h1> )}/>
一个函数属性,用于渲染
属性名不必定是render,重要的是它起到的做用
与jQuery协同,把DOM操做交给jQuery,React数据驱动渲染与jQuery DOM分离
aria-*
HTML属性for
特性被写做htmlFor
import()
动态导入 + react-loadable
模块
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; import Loadable from 'react-loadable'; const Loading = () => <div>Loading...</div>; const Home = Loadable({ loader: () => import('./routes/Home'), loading: Loading, }); const About = Loadable({ loader: () => import('./routes/About'), loading: Loading, }); const App = () => ( <Router> <Switch> <Route exact path="/" component={Home}/> <Route path="/about" component={About}/> </Switch> </Router> );
React.createElement( type, [props], [...children] )
React.cloneElement( element, [props], [...children] )
以 element
做为起点,克隆并返回一个新的React元素(React Element)。生成的元素将会拥有原始元素props与新props的浅合并。新的子级会替换现有的子级。来自原始元素的 key
和 ref
将会保留。
验证对象是不是一个React元素。返回 true
或 false
。
React.Children
提供了处理 this.props.children
这个数据结构的工具。
React.Children.map(children, function[(thisArg)]) React.Children.forEach(children, function[(thisArg)]) React.Children.count(children) React.Children.only(children) React.Children.toArray(children)
import ReactDOM from 'react-dom'
ReactDOM.render( element, container, [callback] )
ReactDOM.findDOMNode(component)