基础概览
state 的使用
-
React可以将多个
setState()
调用合并成一个调用来提高性能 -
状态更新可能是异步的
-
不能依靠
this.props
和this.state
计算下一个状态 -
setState的第二种形式
this.setState((prevState, props) => { // 先前的状态 prevState // 此次更新被应用的 props })
事件处理
-
arrow functions 和
Function.prototype.bind
两种为事件处理函数传递参数-
arrow functions
使用这种语法的问题是每次该组件渲染时都会创建一个不同的回调函数-
如果该回调函数作为属性值传入低阶组件,这些组件可能会进行额外的重新渲染
-
-
列表 & keys
-
如果列表项目的顺序可能会变化,我们不建议使用索引来用作键值,因为这样做会导致性能的负面影响,还可能引起组件状态问题。
状态提升
-
使用 react 经常会遇到几个组件需要共用状态数据的情况。这种情况下,我们最好将这部分共享的状态提升至他们最近的父组件当中进行管理。
定义UI状态的最小表示
-
找出 state
-
它是通过 props 从父级传来的吗?如果是,他可能不是 state。
-
它随着时间推移不变吗?如果是,它可能不是 state。
-
你能够根据组件中任何其他的 state 或 props 把它计算出来吗?如果是,它不是 state。
-
-
确定 state 的位置
-
确定每一个需要这个 state 来渲染的组件
-
找到一个公共所有者组件
-
公共所有者拥有这个 state
-
进阶指南
Context
-
React组件通过props传递数据,是自顶向下的
-
context可以传递数据通过组件树,而不用向每个层级层层传递props
-
好处: 避免层层传递props,底层才能拿到数据
-
如果只想避免通过许多级别传递一些属性,那么组件组合通常比上下文更简单
-
谨慎的使用context,它可能会使组件复用变得困难
-
-
提供四个API
-
React.createContext
-
Context.Provider
-
Class.contextType
-
Context.Consumer
-
-
Context 简单使用
// light 为 defaultValue 仅在当一个组件在组件树中没有匹配到the closest Provider // 可以 传属性、方法 const ThemeContext = React.createContext('light'); class App extends React.Component { render() { // Use a Provider to pass the current theme to the tree below. // Any component can read it, no matter how deep it is. // In this example, we're passing "dark" as the current value. return ( <ThemeContext.Provider value="dark"> <Toolbar /> </ThemeContext.Provider> ); } } // A component in the middle doesn't have to // pass the theme down explicitly anymore. function Toolbar(props) { return ( <div> <ThemedButton /> </div> ); } // Consumer两种写法 class ThemedButton extends React.Component { // Assign a contextType to read the current theme context. // React will find the closest theme Provider above and use its value. // In this example, the current theme is "dark". static contextType = ThemeContext; render() { return <Button theme={this.context} />; } } class ThemedButton extends React.Component { render() { return ( <ThemeContext.Consumer> {value => ( <Button theme={value} /> )} </ThemeContext.Consumer> ); } }
-
一个生产者多个消费者
-
1 Context.Provider
-
n Context.Consume
-
-
Provider 值属性改变时,Consume将重新render。从Provider到Consume的传播不受
shouldComponentUpdate
方法约束。 -
Consume 可以通过
static contextType = ThemeContext
,然后使用 this.context获取到the closest Provider的value值 -
Consume 可以使用
<Context.Consumer> {value => /* render something based on the context value */} </Context.Consumer>
-
Consuming Multiple Contexts
-
多层Provider ,多层Consumer 嵌套
-
Error Boundaries
-
Error boundaries do not catch errors for:
-
Event handlers (learn more)
-
Asynchronous code (e.g.
setTimeout
orrequestAnimationFrame
callbacks) -
Server side rendering
-
Errors thrown in the error boundary itself (rather than its children)
-
-
A class component becomes an error boundary if it defines either (or both) of the lifecycle methods
static getDerivedStateFromError()
orcomponentDidCatch()
.-
Use
static getDerivedStateFromError()
to render a fallback UI after an error has been thrown. UsecomponentDidCatch()
to log error information.
-
-
Error Boundaries 简单使用
class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error) { // Update state so the next render will show the fallback UI. return { hasError: true }; } componentDidCatch(error, info) { // You can also log the error to an error reporting service 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; } }
Forwarding Refs
-
API React.forwardRef
const FancyButton = React.forwardRef((props, ref) => ( <button ref={ref} className="FancyButton"> {props.children} </button> )); // You can now get a ref directly to the DOM button: // 此处便获取了 button 的 引用 const ref = React.createRef(); <FancyButton ref={ref}>Click me!</FancyButton>;
-
使父组件可以获取子组件的引用,即可获取子组件实体,调用子组件的方法
Higher-Order Components
-
复用组件逻辑时使用
-
不要在 render 方法中使用 HOCs ,当更新时,会完整的卸载之前的组件树
Portals
-
API ReactDOM.createPortal(child, container)
-
使用场景 a parent component has an
overflow: hidden
orz-index
style, but you need the child to visually “break out” of its container. For example, dialogs, hovercards, and tooltips. -
事件冒泡能通过 portals 继续向上
Reconciliation
-
主要解释了 React’s “diffing” algorithm
-
Elements Of Different Types 元素类型不同,销毁旧的构建新的
-
DOM Elements Of The Same Type 元素类型相同,比较元素的属性,属性不同只更新属性
-
Component Elements Of The Same Type 组件元素类型相同,React更新props以匹配新元素,并调用componentWillReceiveProps()
and
componentWillUpdate()
-
Refs and the DOM
-
Refs 提供一种能够获取Dom节点或者组件的方法
-
经典的React数据流:props是父组件影响子组件的唯一方式,为了修改子组件,需要用新的props re-render子组件
-
-
什么时候使用
-
Managing focus, text selection, or media playback. 获取焦点,文本选择,媒体的播放
-
Triggering imperative animations. 触发动画
-
Integrating with third-party DOM libraries. 与第三方dom库整合
-
-
可以被声明式的写时 避免使用ref
-
不能使用ref在function components,因为它没有实例
-
生命周期中 ref的状况
-
当组件 mounts时,React将current property分配给 dom元素
-
当组件 unmounts时, 返回 null
-
Ref updates 在componentDidMount
or
componentDidUpdate 之前
-
Render Props
-
复用 状态和行为 给其它需要相同状态和行为的组件
-
例子,鼠标移动时,分享坐标值给各个组件
class Cat extends React.Component { render() { const mouse = this.props.mouse; return ( <img src="/cat.jpg" style={{ position: 'absolute', left: mouse.x, top: mouse.y }} /> ); } } class Mouse extends React.Component { constructor(props) { super(props); this.handleMouseMove = this.handleMouseMove.bind(this); this.state = { x: 0, y: 0 }; } handleMouseMove(event) { this.setState({ x: event.clientX, y: event.clientY }); } render() { return ( <div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}> {/* ...but how do we render something other than a <p>? */} this.props.children(this.state) </div> ); } } class MouseTracker extends React.Component { render() { return ( <div> <h1>Move the mouse around!</h1> {/* children prop doesn’t actually need to be named in the list of “attributes” in your JSX element */} <Mouse> {mouse => <Cat mouse={mouse} />} </Mouse> </div> ); } } // 也可以使用 HOC function withMouse(Component){ return class extends React.Component { render(){ return ( <Mouse> {mouse => <Component {...this.props} mouse={mouse} />} </Mouse> ) } } }