React引入虚拟DOM,状态,单项数据流等设计理念,
形成以组件为核心,利用组件搭建UI的开发方式,将数据,组件状态和UI映射在一起
- 一个组件对应一个功能,单一职责
- map循环列表时,必须添加 key属性,且 key属性不能是 undefined
- state是异步的,我们所做的任何修改不会立即生效,并且可能会在下一次渲染时生效
- 组件名称,必须是大驼峰命名,组件必须以大写字母开头
React 八种条件渲染,
React不同条件渲染出不同效果
https://www.jianshu.com/p/629234e7c63a
https://zhuanlan.zhihu.com/p/38220426
https://blog.logrocket.com/conditional-rendering-in-react-c6b0e5af381e/
http://www.voycn.com/article/yi-zaireactzhongshixiantiaojianxuanrande7zhongfangfa
https://blog.csdn.net/iceking66/article/details/80649140
https://blog.csdn.net/weixin_33774615/article/details/87946811
jsx不同的渲染
- if语句
- 三元运算 ternary operator
- 逻辑 &&
- switch case
- 枚举 enums
- 多层条件渲染 multi-level conditional reandering
- 高阶组件
if语句
如果没有data没有数据,可以提前return
组件如果return null, 将不会被渲染出来
function App({dataSource}) {
// 阻止组件渲染
if (!Array.isArray(dataSource)) return null
if (!dataSource.length) return <Empty /> // antd的 Empty组件
return (
<>{data.map(item => <ListItem data={data} />)}</>
)
}
三元运算 ternary operator
三元运算符来代替if…else… 条件渲染
三元运算的条件渲染更加的简洁
function App({data, mode}) {
if (!Array.isArray(data)) return null
if (!data.length) return <Empty /> // antd的 Empty组件
return (
<>
{
(mode === 'edit')
? <ListItem data={data} />
: <ListEdit data={data} />
}
</>
)
}
// a ? b : c 三元运算
<div style={{ display: (this.state.status === 1) ? 'none' : 'block' }} >
逻辑 &&
当你想渲染一个组件或者什么也不渲染的场景
用 && 可以使返回 null 的情况的条件渲染更加的简洁,
缺点:如果 data是 0,就会显示 0
function List({data}) {
return (
<>
{
data && <ListItem data={data} />
}
</>
)
}
switch case
- 多种条件渲染的情况,例如依据不同的state渲染不同的Component
- 多种条件中渲染最好的方式是枚举
- switch…case语句,永远要加上default情况,因为React组件要么返回元素,要么返回null
- 如果组件依据 state 属性渲染时,最后添加上 PropTypes验证
- 将条件渲染结果内联在switch…case中的方法是,使用立即调用函数 ```jsx Notification.propTypes = { text: PropTypes.string, state: PropTypes.oneOf([‘info’, ‘warning’, ‘error’]) }
function Notification({ text, state }) {
switch (state) {
case ‘warning’:
return
// 内联 switch case
function Notification({ text, state }) {
return (
<>
{(() => {
switch (state) {
case ‘info’:
return
)
}
<a name="t8q05"></a>
### 枚举 enums
多种条件中渲染最好的方式是**枚举**
<a name="u3zSk"></a>
### 多层条件渲染 multi-level conditional reandering
<br />
<a name="47MyS"></a>
## UI视图的本质
1. 渲染逻辑与 UI视图表现的内在统一
2. react没有采取 html与 js分离的原则,对这两部分进行了组合
3. react把 HTML与渲染逻辑进行了耦合,就形成了 jsx
<a name="FTDnX"></a>
### jsx的特点
1. 常规的 html或 js代码都可以与 jsx兼容
2. 可以在 js中嵌入表达式,语法上更贴近 js
3. 使用 jsx指定子元素
1. 可以使用 /> 来闭合标签,就像 HTML5的单标签一样
2. 也可以包含很多子元素
4. jsx命名使用小驼峰命名,camelCase
1. class,要写成 className
2. for,要写成 htmlFord等
5. 自定义 jsx属性,要使用 data-开头
6. jsx最终会编译为 React.createElement() 对象
1. 2种写法,完全相同的结果
2. 1:是 jsx语法;2 是原生的 js代码
3. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/112859/1613015704904-bdf5ff57-a45e-465c-9e20-daa1745534d5.png#averageHue=%23272932&height=136&id=bl2Hd&originHeight=272&originWidth=1452&originalType=binary&ratio=1&rotation=0&showTitle=false&size=213305&status=done&style=none&title=&width=726)
```jsx
<Logo src="./images/logo.jpg" />
const Menu = (
<Menu>
<Menu.Item>UI</Menu.Item>
<Menu.Item>Web</Menu.Item>
</Menu>
)
// 小驼峰命名, data-属性
const element = <div className="title" tabIndex={1} data-index="10"/>
文件后缀用 .jsx 还是 .js
- jsx不是标准的 js语法
- 推荐在 .js文件里面使用标准的 js语法
- 在 react语法中使用 .jsx文件,区分更直观一些
- react并不强制使用 jsx,可以使用原生的 js
- 总结:使用 .jsx 或 .js都可以,因为主流编辑器都可以识别这两种文件
jsx key值
- 不能用 Math.random() 作为 key
- 不推荐使用 index作为 key
- 因为一旦列表的数据重排,数据索引也会发生变化,不利于渲染优化
- 建议给 key一个固定的唯一值
- key不能重复,key的唯一性仅限于当前的列表;不是全局的唯一
Form 动态 key
- Form表单Bug,删除,永远只删除最后一项
- react 表单项动态删除,删掉的都是最后一个,因为 你用了 index作为 key
- react 删除数据永远都是从最后面删除
- 在遍历后,不要把index用于元素个项的识别上,例如:key name等
- 假设 你的key设置为map中的索引,假设为0,1,2(原dom树),现在你用splice删除掉1,重新渲染时,还是会按map索引按顺序渲染为0,1(新dom树),由于react渲染机制是比较的key值,发现key(0,1)都没变,所以保留原dom树的0,1元素(包括里面内容都不变),而由于数量少了一个,渲染的最后一个就没有渲染,就感觉是删除的最后一个。
- 你要分页渲染一个列表,每次点击翻页会重新渲染,使用唯一id作为 key
- 翻页后,三条记录的key和组件都发生了改变,因此三个子组件都会被卸载然后重新渲染
input输入一下卡顿一下,需要点击才能输入
- React中的 diff算法,通过 key值判断,前后虚拟DOM是否发生变化
- 用动态输入的值作为 key,每次都会重新 renderDOM,引起重绘
- 不能用输入的值,或 Math.random或时间戳作为 key
渲染 html
const createMarkup = (body) => {
return { __html: body };
}
<div dangerouslySetInnerHTML={createMarkup(markdownHtml)} />
- 组件声明
- 始终声明 PropTypes
- Props 非空检测
- 使用 Props 初始化
- 计算属性
- 事件回调命名
- 组件化优于多层 render
- 纯函数的 render]
- 状态上移优于公共方法
- 容器组件
- classnames
始终声明 PropTypes
https://www.jb51.net/article/122796.htm
https://www.wenjiangs.com/doc/itn09qbji
Props验证对于组件的正确使用是一种非常有用的方式。
可以避免随着你的应用的程序越来越复杂从而出现很多的bug和问题。并且,它还可以是你的程序变得更易读
每一个组件都声明 PropTypes,非必须的 props 应提供默认值
人知的 props 如 children, dispatch 也不应该忽略
如果一个组件没有声明 dispatch 的 props,那么一眼就可以知道该组件没有修改 store 了
Props 初始化
http://shripadk.github.io/react/tips/props-in-getInitialState-as-anti-pattern.html
https://blog.csdn.net/sinat_17775997/article/details/59021696
除非 props 的命名明确指出了意图,否则不该使用 props 来初始化 state
// good
constructor (props) {
this.state = {
items: props.initialItems
}
}
// bad
constructor (props) {
this.state = {
items: props.items
}
}
如果在开发一系列会 dispatch 的组件时,可在这些组件的目录建立单独的 .eslintrc 来只忽略 dispatch
App.propTypes = {
value: PropTypes.array.isRequired,
onChange: PropTypes.func.isRequired
}
function App() {
}
defaultProps
对于并非 isRequired
的 proptype,必须对应设置 defaultProps,避免再增加 if 分支带来的负担
如有必要,使用 PropTypes.shape 明确指定需要的属性
// good
class MyComponent extends Component {
render() {
return <div>{this.props.person.firstName}</div>
}
}
MyComponent.defaultProps = {
person: {
firstName: 'Guest'
}
}
// bad
render () {
if (this.props.person) {
return <div>{this.props.person.firstName}</div>
} else {
return <div>Guest</div>
}
}
Prop Validation
classnames
使用 classNames 来组合,多个 class
// good
render () {
const classes = {
selected: true,
menu: true,
active: this.props.display
}
return <div className={classnames(classes)} />
}
// bad 字符串拼接
render () {
return <div className={'menu ' + this.props.display ? 'active' : ''} />
}
纯函数的渲染
render 函数应该是一个纯函数
stateless component 无状态也是
不依赖 this.state、this.props 以外的变量,也不改变外部状态
减少 window. 全局属性的使用
数组遍历,map,必须要用 key属性
在一个函数里面,改变传入的对象本身是不好的写法
// bad
render () {
return <div>{window.navigator.userAgent}</div>
}
// good
render () {
return <div>{this.props.userAgent}</div>
}