AJAX 及 APIs
ajax请求在 componentDidMount 发起或者useEffect空依赖
Babel, JSX, 及构建过程
{/* 注释写在这里 */}
{/* 多行注释
也同样有效。 */}
在组件中使用事件处理函数
-
事件处理器传递给组件
事件处理器作为props
-
函数绑定组件实例
this.handleClick = this.handleClick.bind(this); handleClick = () => {}; <button onClick={this.handleClick.bind(this)}>Click Me</button>;(影响性能) <button onClick={() => this.handleClick()}>Click Me</button>;(影响性能) -
传递函数本身
<button onClick={this.handleClick}>Click Me</button> <button onClick={this.handleClick()}>Click Me</button> wrong -
传递参数
-
<button onClick={() => this.handleClick(id)} />
id第一个参数 -
<button onClick={this.handleClick.bind(this, id)} />
e第一个参数,id第二个参数 -
通过 data-attributes 传递参数
e第一个参数<li key={letter} data-letter={letter} onClick={this.handleClick}></li> handleClick(e) { this.setState({ justClicked: e.target.dataset.letter }); }
-
-
函数被调用太快或者太多次
-
节流:1s内调用一次 (例如 _.throttle)
import throttle from 'lodash.throttle'; class LoadMoreButton extends React.Component { constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); this.handleClickThrottled = throttle(this.handleClick, 1000); } componentWillUnmount() { this.handleClickThrottled.cancel(); } render() { return <button onClick={this.handleClickThrottled}>Load More</button>; } handleClick() { this.props.loadMore(); } } -
防抖:确保函数不会在上一次被调用之后一定量的时间内被执行 (例如 _.debounce)
鼠标滚动或键盘事件
import debounce from 'lodash.debounce'; class Searchbox extends React.Component { constructor(props) { super(props); this.handleChange = this.handleChange.bind(this); this.emitChangeDebounced = debounce(this.emitChange, 250); } componentWillUnmount() { this.emitChangeDebounced.cancel(); } render() { return ( <input type="text" onChange={this.handleChange} placeholder="Search..." defaultValue={this.props.value} /> ); } handleChange(e) { this.emitChangeDebounced(e.target.value); } emitChange(value) { this.props.onChange(value); } } -
requestAnimationFrame:一个函数被requestAnimationFrame放入队列后将会在下一帧触发 (例如 raf-schd)import rafSchedule from 'raf-schd'; class ScrollListener extends React.Component { constructor(props) { super(props); this.handleScroll = this.handleScroll.bind(this); // Create a new function to schedule updates. this.scheduleUpdate = rafSchedule( point => this.props.onScroll(point) ); } handleScroll(e) { // When we receive a scroll event, schedule an update. // If we receive many updates within a frame, we'll only publish the latest value. this.scheduleUpdate({ x: e.clientX, y: e.clientY }); } componentWillUnmount() { // Cancel any pending updates since we're unmounting. this.scheduleUpdate.cancel(); } render() { return ( <div style={{ overflow: 'scroll' }} onScroll={this.handleScroll} > <img src="/my-huge-image.jpg" /> </div> ); } }
-
组件状态
-
setState// this.setState({count: this.state.count + 1}); this.setState((state) => { // 重要:在更新的时候读取 `state`,而不是 `this.state`。 return {count: state.count + 1} }); -
异步更新
事件处理函数内部的
setState是异步的- 避免不必要的重新渲染
- 会破坏掉
props和state之间的一致性,造成一些难以 debug 的问题 - 影响新功能的实现
样式与 CSS
使用className,依赖 props 或 state 使用 classnames
className性能更好
项目文件结构
-
按功能或路由组织
common/ Avatar.js Avatar.css APIUtils.js APIUtils.test.js feed/ index.js Feed.js Feed.css FeedStory.js FeedStory.test.js FeedAPI.js profile/ index.js Profile.js ProfileHeader.js ProfileHeader.css ProfileAPI.js -
按文件类型组织
api/ APIUtils.js APIUtils.test.js ProfileAPI.js UserAPI.js components/ Avatar.js Avatar.css Feed.js Feed.css FeedStory.js FeedStory.test.js Profile.js ProfileHeader.js ProfileHeader.css -
根据组件在应用程序中的角色将组件文件组织到不同的目录中
-
避免多层嵌套(最多三到四个层级)