使用 ES6 class 声明,可不严格遵守该属性声明次序
但如有 propTypes 则必须写在顶部, lifecycle events 必须写到一起
数组遍历,map,必须要用 key属性
在一个函数里面,改变传入的对象本身是不好的写法
- propTypes
- defaultPropTypes
- constructor
- event handlers (如不使用类属性语法可在此声明)
- event handlers (如不使用类属性语法可在此声明)
- lifecycle events
- event handlers
- getters
render
class App extends React.Component {static propTypes = {firstName: PropTypes.string.isRequired,lastName: PropTypes.string.isRequired}static defaultPropTypes = {firstName: '',lastName: '',}constructor(props) {super(props)this.state = { visible: false }/* 若不能使用 babel-plugin-transform-class-propertiesthis.handleClick = () => {this.setState({visible: !this.state.visible})}*/}componentWillMount() { }componentDidMount() { }handleClick = () => {this.setState({ visible: !this.state.visible })}get fullName() {const { firstName, lastName } = this.propsreturn `${firstName} ${lastName}`}render() {return (<div onClick={this.handleClick}>{this.fullName} {this.state.visible ? 'is visible' : ''}</div>)}}
get计算属性
使用 getters 封装 render 所需要的状态或条件的组合
对于返回 boolean 的 getter 使用 is- 前缀命名,例如 isVisible
class App extends React.Component {get isVIP() {const { age } = this.stateconst { level } = this.propsconst vips = ['A', 'B']return age > 18 && (vips.includes(level))}render() {return (<div>{this.isVIP ? <VipComponent /> : <NormalComponent />}</div>)}}
不推荐的用法
// badrender () {return (<div>{this.state.age > 18&& (this.props.level === 'A'|| this.props.level === 'B')? <VipComponent />: <NormalComponent />}</div>)}
事件回调命名规范
Handler 命名风格:
- 使用
handle开头,使用一般现在时 - 以事件类型作为结尾 (如
Click,Change) - handleClick,handleChange ```jsx closeAll = () => {},
// good render () { return
}// bad render () { return
}
如果你需要区分同样事件类型的 handler(如 `handleNameChange` 和 `handleEmailChange`)时,<br />可能这就是一个拆分组件的信号<a name="lLQjn"></a>## 组件化代替多个render当组件的 jsx 只写在一个 render 方法显得太臃肿时,就拆分出一个个小组件<br />采用 class component 或 stateless component 无状态组件Table表格组件,用的 render方法比较多- renderAction- renderStatus- RenderTime```jsxclass App extends React.Component {render() {return (<div className="menu"><ul>{this.props.items.map(item => <Items {...item} />)}</ul></div>)}}// Items子组件负责渲染逻辑function Items ({name}) {return (<li>{name}{/* ... */}</li>)}
不推荐的写法
// badclass App extends React.Component {renderItem({ name }) {return (<li>{name}{/* ... */}</li>)}render() {return (<div className="menu"><ul>{this.props.items.map(item => this.renderItem(item))}</ul></div>)}}
state状态提升
state状态上移优于公共方法
把公共数据放在父组件里面
Lifting State Up https://reactjs.org/docs/lifting-state-up.html
更细颗粒的组件化,状态应集中在远离渲染的地方处理,
- 比如应用级别的状态就在 redux 的 store 里
- 也能使兄弟组件更方便地共享
- 一般组件不应提供公共方法,这样会破坏数据流只有一个方向的原则 ```jsx // parent import DropDownMenu from ‘./DropDownMenu’
class App extends React.Component { constructor (props) { super(props) this.state = { visible: false } }
showMenu () { this.setState({visible: true}) }
hideMenu () { this.setState({visible: false}) }
render () {
return
child子组件```jsxclass DropDownMenu extends Component {static propsType = {visible: PropTypes.boolean.isRequired}render () {if(!this.props.visible) return nullreturn (<div className="dropdown-menu">{/* ... */}</div>)}}
不推荐的写法
class App extends React.Component {showMenu () {this.refs.menu.show()}hideMenu () {this.refs.menu.hide()}render () {return <DropDownMenu ref="menu" />}}// child 子组件class DropDownMenu extends Component {constructor (props) {super(props)this.state = {visible: false}}show () {this.setState({visible: true})}hide () {this.setState({visible: false})}render () {return this.state.visible && (<div className="dropdown-menu">{/* ... */}</div>)}}
容器组件
容器组件主要负责 维护状态和 数据的计算
- 本身并没有界面逻辑,只把结果通过 props 传递下去
- 把组件的状态和渲染解耦开来
改写界面时不用关注数据的实现,顺便得到了可复用性 ```jsx class MessageContainer extends Component { constructor(props) { super(props) this.state = {
onlyUnread: false,messages: []
} }
// 父组件获取数据,处理副作用 componentDidMount() { $.ajax({
url: "/api/messages",
}).then(({ messages }) => this.setState({ messages })) }
handleClick = () => this.setState({ onlyUnread: !this.state.onlyUnread })
render() { return <MessageList
messages={this.state.messages.filter(msg => this.state.onlyUnread ? !msg.asRead : true)}toggleUnread={this.handleClick}
/> } }
// child子组件 MessageList.propTypes = { messages: propTypes.array.isRequired, toggleUnread: propTypes.func.isRequired }
function MessageList({ messages, toggleUnread }) { return (
) }
bad,不推荐的写法,<br />组件的状态和渲染没有分开```jsxclass MessageList extends Component {constructor (props) {super(props)this.state = {onlyUnread: false,messages: []}}componentDidMount () {$.ajax({url: "/api/messages",}).then(({messages}) => this.setState({messages}))}handleClick = () => this.setState({onlyUnread: !this.state.onlyUnread})render () {return (<div class="message"><ul>{this.state.messages.filter(msg => this.state.onlyUnread ? !msg.asRead : true).map(({content, author}) => {return <li>{content}—{author}</li>})}</ul><button onClick={this.handleClick}>toggle unread</button></div>)}}
