本着打好基础,快速上手,实用第一的思想,下文总结了一些平时开发常用的基础操作,适合入门参照。最好的学习资料还请移步 官方文档,期待同学们更精彩的分享。如有不当之处,请予指正。
类组件
// 引入依赖
import React from 'react';
import ReactDOM from 'react-dom';
class Hello extends React.Component {
render () {
return <div className='message-box'>
Hello {this.props.name}
</div>
}
}
ReactDOM.render(<Hello name='John' />, document.body)
React.Component
的性能优化版本。如果 props/state
没有改变,不会重新render。
import React, {PureComponent} from 'react';
class MessageBox extends PureComponent {
···
}
类组件API
this.forceUpdate();
// 设置state
this.setState({ ... });
this.setState(state => { ... });
// 获取state或props里的值
this.state.visible
this.props.name
// 或者使用es6解构语法
const { visible } = this.props;
const { name } = this.state;
默认值
默认prop值
Hello.defaultProps = {
color: 'blue'
}
默认state值
class Hello extends Component {
// 有 constructor() 时
constructor (props) {
super(props)
this.state = { visible: true }
}
// 使用Babel,可以使用 proposer-class-fields 来摆脱 constructor()
state = { visible: true }
}
获取props属性
用 this.props
来访问传递给组件的属性。
// 父组件
<Video fullscreen={true} autoplay={false} />
// 子组件,非限定render函数,组件内皆可
render () {
// this.props.fullscreen
const { fullscreen, autoplay } = this.props
···
}
传递children
// 父组件
<AlertBox>
<h1>咱老百姓今儿真啊么真高兴</h1>
</AlertBox>
// 子组件
class AlertBox extends Component {
render () {
return <div className='alert-box'>
{this.props.children} <!-- <h1>咱老百姓今儿真啊么真高兴</h1> -->
</div>
}
}
透传
// 父组件
...
<VideoPlayer src="video.mp4" />
...
// 子组件
class VideoPlayer extends Component {
...
render () {
// 孙组件
return <VideoEmbed {...this.props} />
}
}
函数式组件
函数组件没有state,它们的props将作为第一个参数传递给函数。
function MyComponent ({ name }) {
return <div className='message-box'>
Hello {name}
</div>
}
Hook
useState
import React, { useState } from 'react';
function Example() {
// 声明一个新的state变量"count",注意第二个参数使用CamelCase,约定以set-开头
const [count, setCount] = useState(0);
return (
<div>
<p>你点击了 {count} 次</p>
<button onClick={() => setCount(count + 1)}>
点击
</button>
</div>
);
}
useEffect
默认情况下,React在每次render后执行effect——包括第一次render。
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
// 类似于 componentDidMount 和 componentDidUpdate,注意第二参数是否为空数组
useEffect(() => {
document.title = `你点击了 ${count} 次`;
}, [count]);
return (
<div>
<p>你点击了 {count} 次</p>
<button onClick={() => setCount(count + 1)}>
点击
</button>
</div>
);
}
Hooks API
- useState(initialState)
- useEffect(() => { … })
- useContext(MyContext)
- useReducer(reducer, initialArg, init)
- useCallback(() => { … })
- useMemo(() => { … })
- useRef(initialValue)
- useImperativeHandle(ref, () => { … })
- useLayoutEffect 与useEffect相同,但它在所有DOM突变后同步触发
- useDebugValue(value) 在React DevTools中显示自定义钩子标签
DOM
ref
class MyComponent extends Component {
render () {
return <div>
<input ref={el => this.input = el} />
</div>
}
componentDidMount () {
this.input.focus();
}
}
Events
class MyComponent extends Component {
onChange = (event) => {
this.setState({ value: event.target.value })
}
render () {
return <input type="text"
value={this.state.value}
onChange={event => this.onChange(event)} />
}
}
生命周期 Lifecycle
- React16新的生命周期弃用了componentWillMount、componentWillReceiveProps,componentWillUpdate
- 新增了getDerivedStateFromProps、getSnapshotBeforeUpdate来代替弃用的三个钩子函数(componentWillMount、componentWillReceiveProps,componentWillUpdate)
- 新增了对错误的处理(componentDidCatch)
挂载阶段
在constructor()
上初始化state状态;
在componentDidMount()
上添加DOM事件处理程序、计时器等,然后在componentWillUnmount()
上删除它们。
constructor (props) render之前执行
componentWillMount() 不推荐,完全可以写在constructor中
render()
componentDidMount() render之后(DOM 可用)
componentWillUnmount() DOM移除之前
componentDidCatch(error, info) 捕获errors (16+)
更新阶段
当父类更改属性和. setstate()
时调用,这些在初始渲染时不被调用。
componentWillReceiveProps(nextProps) 接收到新的props时触发
shouldComponentUpdate (newProps, newState) return false 将阻断 render
componentWillUpdate (prevProps, prevState, snapshot) 此时可用 setState(), 勿忘比较新旧props
render()
componentDidUpdate (prevProps, prevState) 可操作DOM
JSX 一些写法
样式
// 行内样式
const style = { height: 10 }
return <div style={style}></div>
// 或
return <div style={{ margin: 0, padding: 0 }}></div>
// className
<div className={styles.container}>nodes</div>
<div className={`${styles.container} ${isClicked?styles.clicked:''}`}>nodes</div>
// className={`title ${index === this.state.active ? 'active' : ''}`}
// className={["title", index === this.state.active?"active":null].join(' ')}
// 引用 classnames 三方库
条件判断
<>
{showMyComponent
? <MyComponent />
: <OtherComponent />}
</>
短路判断
<Fragment>
{showPopup && <Popup />}
...
</Fragment>
InnerHTML
function markdownify() { return "<p>...</p>"; }
<div dangerouslySetInnerHTML={{__html: markdownify()}} />
List 遍历展示
class TodoList extends Component {
render () {
const { items } = this.props
// key 不能使用index简单设置,反优化措施
return <ul>
{items.map(item =>
<TodoItem item={item} key={item.key} />)}
</ul>
}
}
属性验证
非强制
import PropTypes from 'prop-types';
class MyComponent extends Component {
...
}
MyComponent.propTypes = {
email: PropTypes.string.isRequired, // 必需属性
seats: PropTypes.number,
callback: PropTypes.func,
isClosed: PropTypes.bool,
any: PropTypes.any,
// Elements
element: PropTypes.element,
node: PropTypes.node,
// array
list: PropTypes.array,
ages: PropTypes.arrayOf(PropTypes.number),
// object
user: PropTypes.object,
user: PropTypes.objectOf(PropTypes.number),
message: PropTypes.instanceOf(Message),
// 定义对象结构
user: PropTypes.shape({
name: PropTypes.string,
age: PropTypes.number
})
// 枚举 oneOfType
direction: PropTypes.oneOf([
'left', 'right'
]),
// 自定义
customProp: (props, key, componentName) => {
if (!/matchme/.test(props[key])) {
return new Error('Validation failed!')
}
}
}