You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
const{Provider, Consumer}=React.createContext(defaultValue);<Providervalue={/* some value */}><Consumer>{value=>/* render something based on the context value */}</Consumer>
概述
React 编程思路
可以简单概括为两步:
1. 创建组件
创建组件的语法有两种:使用JSX或者
React.createElement()
创建组件的方法有两种:使用函数或者类
1. 使用函数的话,需要返回JSX(会转换为
React.createElement()
)2. 使用类的话,需要提供render函数,并返回JSX
在React里,组件有三种类型:
2. 挂载组件
挂载很简单,仅需要
ReactDOM.render()
这个API即可。完整API如下:
组件的基本特性
一般情况下,给组件添加的属性会添加到props:函数组件是第一个入参(一般会命名为props),类组件通过
this.props
访问。props有一个严格的规则(只读性):所有的React组件必须像纯函数那样使用它们的props。
所以,我们想通过props重新渲染组件的话,仅能通过
ReactDOM.render()
再次挂载了。如果你还需要:
1. 维护一些状态,状态更新的时候自动渲染组件
通过类组件,我们可以使用一些特性,例如局部状态、生命周期钩子。
通过在类构造函数里初始化状态:
如果需要更新状态的话,我们可以使用API:
this.setState()
。有三件事需要注意:1. 不要直接更新状态
2. 状态更新可能是异步的
对于异步更新的情况,可以给
this.setState()
传递一个回调,第一个参数为先前的状态,第二个参数为props3. 状态更新合并
即
this.setState()
仅更新参数里提及的状态,不影响其它的。比如
this.state = {a:1, b:2}
,当我们更新状态
this.setState({a: 3})
,state的状态将会更新为
{a:3, b:2}
2. 监听组件的交互事件
React 元素的事件处理和 DOM元素的很相似。但是语法上有一些不同:
值得注意的还有另外三件事:
e
是一个合成事件,React解决了跨浏览器的兼容性问题Function.prototype.bind()
3. 了解组件的生命周期
每一个组件都有几个你可以重写以让代码在处理环节的特定时期运行的“生命周期方法”。
方法中带有前缀 will 的在特定环节之前被调用,而带有前缀 did 的方法则会在特定环节之后被调用。
借助网上的一张图,方便理解:
装配阶段
1. constructor(props)
构造函数是初始化状态的合适位置。若不初始化状态且不绑定方法,那也不需要为React组件定义一个构造函数。
2. static getDerivedStateFromProps(nextProps, prevState)
组件实例化后和接受新属性时将会调用getDerivedStateFromProps。它应该返回一个对象来更新状态,或者返回null来表明新属性不需要更新任何状态。
注意,如果父组件导致了组件的重新渲染,即使属性没有更新,这一方法也会被调用。如果你只想处理变化,你可能想去比较新旧值。
调用this.setState() 通常不会触发 getDerivedStateFromProps()。
3. componentWillMount() / UNSAFE_componentWillMount()
UNSAFE_componentWillMount()
在装配发生前被立刻调用。其在render()之前被调用,因此在这方法里同步地设置状态将不会触发重渲。避免在该方法中引入任何的副作用或订阅。对于这些使用场景,我们推荐使用
constructor()
来替代。4. render()
当被调用时,其应该检查
this.props
和this.state
并返回以下类型中的一个:<div />
,或者是一个你定义的合成组件。ReactDOM.createPortal
创建。return test && <Child />
写法,其中 test 是布尔值。)render()
函数应该纯净,意味着其不应该改变组件的状态,其每次调用都应返回相同的结果,同时不直接和浏览器交互。若需要和浏览器交互,将任务放在componentDidMount阶段或其他的生命周期方法。5. componentDidMount()
componentDidMount()
在组件被装配后立即调用。初始化使得DOM节点应该进行到这里。若你需要从远端加载数据,这是一个适合实现网络请求的地方。在该方法里设置状态将会触发重渲。这一方法是一个发起任何订阅的好地方。如果你这么做了,别忘了在
componentWillUnmount()
退订。在这个方法中调用
setState()
将会触发一次额外的渲染,但是它将在浏览器刷新屏幕之前发生。谨慎使用这一模式,因为它常导致性能问题。更新阶段
1. componentWillReceiveProps(nextProps) / UNSAFE_componentWillReceiveProps(nextProps)
推荐使用
getDerivedStateFromProps
而不是UNSAFE_componentWillReceiveProps
。调用this.setState通常不会触发
UNSAFE_componentWillReceiveProps
。2. static getDerivedStateFromProps()
同前面的
static getDerivedStateFromProps()
3. shouldComponentUpdate(nextProps, nextState)
当接收到新属性或状态时,shouldComponentUpdate() 在渲染前被调用。默认为true。该方法并不会在初始化渲染或当使用forceUpdate()时被调用。
当他们状态改变时,返回false 并不能阻止子组件重渲。
当前,若shouldComponentUpdate()返回false,而后UNSAFE_componentWillUpdate(),render(), 和 componentDidUpdate()将不会被调用。注意,在未来React可能会将shouldComponentUpdate()作为一个线索而不是一个严格指令,返回false可能仍然使得组件重渲。
4. componentWillUpdate(nextProps, nextState) / UNSAFE_componentWillUpdate(nextProps, nextState)
当接收到新属性或状态时,
UNSAFE_componentWillUpdate()
会在渲染前被立即调用。在更新发生前,使用该方法是一次准备机会。该方法不会在初始化渲染时调用。注意你不能在这调用
this.setState()
,若你需要更新状态响应属性的调整,使用getDerivedStateFromProps()
代替。5. render()
同前面的
render()
6. getSnapshotBeforeUpdate(prevProps, prevState)
getSnapshotBeforeUpdate()
在最新的渲染输出提交给DOM前将会立即调用。它让你的组件能在当前的值可能要改变前获得它们。这一生命周期返回的任何值将会 作为参数被传递给componentDidUpdate()
。7. componentDidUpdate(prevProps, prevState)
componentDidUpdate()
会在更新发生后立即被调用。该方法并不会在初始化渲染时调用。卸载
componentWillUnmount()
componentWillUnmount()
在组件被卸载和销毁之前立刻调用。可以在该方法里处理任何必要的清理工作,例如解绑定时器,取消网络请求,清理任何在componentDidMount环节创建的DOM元素。错误处理
componentDidCatch()
错误边界是React组件,并不是损坏的组件树。错误边界捕捉发生在子组件树中任意地方的JavaScript错误,打印错误日志,并且显示回退的用户界面。错误边界捕捉渲染期间、在生命周期方法中和在它们之下整棵树的构造函数中的错误。
模板引擎相关
条件渲染
因为render函数返回null、undefined和布尔值(包括true、false)的话,React什么都不渲染。
所以我们可以通过这个特性来达到根据条件来渲染组件的目的。
方式:
列表渲染
仅需要在JSX里通过
<Parent>{ components }</Parent>
就可以渲染列表,components应该是一个数组,所以我们一般会通过Array.prototype.map()
去生成components。JSX会去解析components并把它们按顺序插入父组件中。
Keys
Keys可以在DOM中的某些元素被增加或删除的时候帮助React识别哪些元素发生了变化。因此你应当给数组中的每一个元素赋予一个确定的标识。
元素的key只有在它和它的兄弟节点对比时才有意义。所以数组元素中使用的key在其兄弟之间应该是独一无二的。然而,它们不需要是全局唯一的。
其它
React和HTML DOM属性的区别
checked属性
标签type属性值为checkbox或radio时,支持checked属性。
defaultChecked这是非受控组件的属性,用来设定对应组件首次加载时是否选中状态。
类名属性
在React中,使用className属性指定一个CSS类。
dangerouslySetInnerHTML函数
dangerouslySetInnerHTML是React提供的替换浏览器DOM中的innerHTML接口的一个函数。
htmlFor
因为在javascript中for是一个保留字,所以React元素使用 htmlFor代替。
onChange函数
onChange事件处理函数的表现正如你所期望的:无论form表单何时发生变化,这个事件都会被触发。
selected
组件支持selected属性。你可以使用该属性设定组件是否选中的状态。这对构建受控组件很有用。style属性
style属性接受一个键为小驼峰命名法命名的javascript对象作为值,而不是像css字符串。
suppressContentEditableWarning
一般来说,当一个拥有子节点的元素被标记为contentEditable时,React会发出一个警告信息,因为此时contentEditable是无效的。
value
<input>
和<textarea>
组件都支持value属性。<select>
支持使用value属性来设置选中项。defaultValue属性对应的是非受控组件的属性,用来设置组件第一次加载时的值。
Refs
ref可以引用到React渲染后的元素,它就是普通的HTML元素,所以它可以使用原生的HTML元素的方法。
在React组件挂载后或更新后,ref才可以被正确引用,所以一般会使用在声明周期函数:
componentDidMout
、componentDidUpdate
基本使用方式:
Fragments
React 中一个常见模式是为一个组件返回多个元素。Fragments 可以让你聚合一个子元素列表,并且不在DOM中增加额外节点。
使用方式:
复合组件
前面提到的几乎是针对单组件的情况。但是在构建大型应用的时候,使用复合组件可以节省很多时间。
复合关系包括父子组件关系、兄弟组件关系。
状态提升
使用 react 经常会遇到几个组件需要共用状态数据的情况。这种情况下,我们最好将这部分共享的状态提升至他们最近的父组件当中进行管理。
步骤:
组合而不是继承
React 具有强大的组合模型,我们建议使用组合而不是继承来复用组件之间的代码。
React.createElement()
)给组件。Context
Context 设计目的是为共享那些被认为对于一个组件树而言是“全局”的数据,例如当前认证的用户、主题或首选语言。
使用方式:
Portals
Portals 提供了一种很好的将子节点渲染到父组件以外的 DOM 节点的方式。
使用方式:
高阶组件
就跟高阶函数一样,函数可以被作为参数传入另一个函数,函数还可以返回另一个函数。高阶组件的意思就是,组件可以作为props传入另一个组件,组件还可以返回另一个组件。
高阶组件就是一个没有副作用的纯函数。高阶组件是通过将原组件 包裹(wrapping) 在容器组件(container component)里面的方式来 组合(composes) 使用原组件。
高阶组件有以下约定:
还有以下注意事项:
hoist-non-react-statics
库可以帮到你React.forwardRef
的 API 来解决这一问题Render Props
前面提到,可以通过props传递数值、函数、组件给子组件。
不仅如此,props还可以传递返回组件的函数,一般使用箭头函数表示。这就是Render Props。
这对于降低组件间的耦合度是很有帮助的。父组件不需要知道具体的子组件,子组件也不必关系父组件怎么引用它。
参考
React 官方文档
React 中文文档
RUNOOB的React 教程
React 学习笔记
react学习笔记
React学习笔记
The text was updated successfully, but these errors were encountered: