Appearance
安装
CDN 引入
可以通过 CDN 获得 React 和 ReactDOM 的 UMD 版本:
html
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>上述版本仅用于开发环境,不适合用于生产环境。压缩优化后可用于生产的 React 版本可通过如下方式引用:
html
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>如果需要加载指定版本的 react 和 react-dom,可以把 18 替换成所需加载的版本号。
create-react-app
Create React App 是一个用于学习 React 的舒适环境,也是用 React 创建新的单页应用的最佳方式。
它会自动配置开发环境,以便能够使用最新的 JavaScript 特性,提供良好的开发体验,并为生产环境优化你的应用程序。需要在机器上安装 Node >= 14.0.0 和 npm >= 5.6。要创建项目,执行:
bash
npx create-react-app my-app
cd my-app
npm start基础
JSX
JSX,是 JavaScript 的语法扩展。在 React 中建议配合使用 JSX,可以很好地描述 UI 应该呈现出它应有交互的本质形式。JSX 可能会使人联想到模板语言,但它具有 JavaScript 的全部功能。
基本写法:
jsx
// dom 类型标签
const element = <h1>123</h1>;
// react 组件类型标签
const element = <HelloWorld />;
// 混用 dom 和 react
const element = (
<div>
<HelloWorld />
</div>
);
// 使用表达式计算
const element = <div>{1+2}</div>;
// 表达式中使用列表渲染
const element = (
<ul>
{
todos.map((item, index), function () {
return <li key="index">item<li>
})
}
</ul>
);注意,使用表达式的方法时,不能使用 js 多行语句,遇到需要使用多行语句时,可以使用三目运算符或者逻辑与替代:
jsx
// 写法一
let complete;
const element = (
<div>
{
complete ? <CompletedList /> : null
}
</div>
);
// 写法二
let complete;
const element = (
<div>
{
complete && <CompletedList />
}
</div>
);React DOM 在渲染所有输入内容之前,默认会进行转义,它可以确保在应用中永远不会注入那些并非自己明确编写的内容:
jsx
const title = response.potentiallyMaliciousInput;
// 直接使用是安全的:
const element = <h1>{title}</h1>;在 JSX 中注释的格式为 {/* 注释 */},比如:
jsx
consr element = (
<div>
{/* 这里是一个注释 */}
<span>React</span>
</div>
)生命周期
界面渲染
事件处理
写法
在 JSX 中,事件使用小驼峰法,即 onclick 要写成 onClick。
事件绑定
在 React16 版下时,事件会自动绑定到当前组件上,但是在 React16 以上,我们需要手动将事件绑定到当前组件上。
js
class TestComponnet extends React.Component{
constructor() {
this.handleClick = this.handleClick.bind(this);
}
}注意:必须谨慎对待 JSX 回调函数中的 this,在 JavaScript 中,class 的方法默认不会绑定 this。如果你忘记绑定 this.handleClick 并把它传入了 onClick,当你调用这个函数的时候 this 的值为 undefined。
如果觉得使用 bind 很麻烦,这里有两种方式可以解决。你可以使用 public class fields 语法:
jsx
/**
* 方案一:CRA 默认启用此语法
*/
class LoggingButton extends React.Component {
// This syntax ensures `this` is bound within handleClick.
handleClick = () => {
console.log('this is:', this);
};
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
);
}
}jsx
/**
* 方案二:在回调中使用箭头函数
* 注意:此语法问题在于每次渲染 LoggingButton 时都会创建不同的回调函数。在大多数情况下,
* 这没什么问题,但如果该回调函数作为 prop 传入子组件时,这些组件可能会进行额外的重新渲染。
* 我们通常建议在构造器中绑定或使用 class fields 语法来避免这类性能问题
*/
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}
render() {
// 此语法确保 `handleClick` 内的 `this` 已被绑定。
return (
<button onClick={() => this.handleClick()}>
Click me
</button>
);
}
}传参
默认的参数 event:
jsx
<button onClick={this.handleClick}>Click me</button>
handleClick(e) {
console.log(e.target);
}在 event 的基础上再加其他参数,e 为默认参数:
jsx
<button onClick={(e) => this.handleClick(id, e)}>Delete Row</button>
<button onClick={this.handleClick.bind(this, id)}>Delete Row</button>
handleClick(param1, param2, e) {
console.log(param1, param2, e);
e.preventDefault(); // 阻止默认事件运行
}上述两种方式是等价的,分别通过箭头函数和 Function.prototype.bind 来实现。在这两种情况下,React 的事件对象 e 会被作为第二个参数传递。如果通过箭头函数的方式,事件对象必须显式的进行传递,而通过 bind 的方式,事件对象以及更多的参数将会被隐式的进行传递。
原生事件
使用事件监听器的时候,要在 componentDidMount 中增加,在 componentWillUnmount 中移除:
jsx
// 监听按钮的点击事件
<button ref="myBtn">点击我</button>
componentDidMount() {
this.refs.myBtn.addEventListener('click', function (e) {
console.log('触发事件')
})
},
componentWillUnmount() {
this.refs.myBtn.removeEventListener('click', function (e) {
console.log('移除事件');
});
}
// 监听敲击键盘事件
componentDidMount() {
window.addEventListener('keypress', function (e) {
code = e.which;
console.log(code);
})
},
componentWillUnmount() {
window.removeEventListener('keypress', function (e) {
console.log('移除事件');
});
}状态提升
在 React 应用中,任何可变数据应当只有一个相对应的唯一「数据源」。通常,state 都是首先添加到需要渲染数据的组件中去。然后,如果其他组件也需要这个 state,那么你可以将它提升至这些组件的最近共同父组件中。应当首先依靠自上而下的数据流,而不是尝试在不同组件间同步 state。
虽然提升 state 方式比双向绑定方式需要编写更多的「样板」代码,但带来的好处是,排查和隔离 bug 所需的工作量将会变少。由于「存在」于组件中的任何 state,仅有组件自己能够修改它,因此 bug 的排查范围被大大缩减了。此外,你也可以使用自定义逻辑来拒绝或转换用户的输入。
组合 vs 继承
进阶
高阶组件
操作 DOM
非受控组件
性能优化
HOOK
Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
| Hook | 描述 |
|---|---|
useState | 设置和改变 state,代替原来的 state 和 setState |
useEffect | 代替原来的生命周期,componentDidMount,componentDidUpdate 和 componentWillUnmount 的合并版 |
useLayoutEffect | 与 useEffect 作用相同,但它会同步调用 effect |
useMemo | 控制组件更新条件,可根据状态变化控制方法执行、优化传值 |
useCallback | useMemo 优化传值,useCallback 优化传的方法,是否更新 |
useRef | 跟以前的 ref 一样,只是更简洁了 |
useContext | 上下文爷孙及更深组件传值 |
useReducer | 代替原来 redux 里的 reducer,配合 useContext 一起使用 |
useDebugValue | 在 React 开发者工具中显示自定义 hook 的标签,调试使用。 |
useImperativeHandle | 可以让你在使用 ref 时自定义暴露给父组件的实例值。 |
