提升可讀性、可維護性javascript
把相關聯的東西放一塊兒(按功能、業務)java
只有render方法、簡單的交互事件處理和state管理。好比Input/CheckBox等。redux
劃分標準: 根據UI稿,不一樣的展現模塊分爲不一樣的組件。好比頂部、底部、導航、列表等網絡
與數據源(redux/後臺/本地存儲)進行數據傳輸操做(不止是IO)架構
劃分標準: 根據業務功能劃分。好比登陸、登出、支付、表單校驗等函數
鏈接業務組件和展現組件, 主要用於處理數據後傳給展現組件。優化
展現組件內能夠有容器組件,容器組件內也能夠有展現組件this
把渲染和功能拆分紅不一樣組件,提升複用性spa
登陸組件處理了2件事情:code
class Login extends Component { constructor(props) { super(props) this.state = { account: '', password: '', status: 'init', } } handleAccountChange(e) { this.setState({account: e.target.value}) } handlePasswordChange(e) { this.setState({password: e.target.value}) } handleLoginClick() { this.setState({ status: 'ing' }) request('/login', { params: { account: this.state.account, password: this.state.password, } }).then(() => { this.setState({status: 'succ'}) }).catch(() => { this.setState({status: 'fail'}) }) } render() { return ( <div> <input placeholder="帳號" value={this.state.account} onChange={(...args) => this.handleAccountChange(...args)} /> <input placeholder="密碼" value={this.state.password} onChange={(...args) => this.handlePasswordChange(...args)} /> <button onClick={() => this.handleLoginClick()}>登陸</button> </div> ) } }
容器組件負責實現登陸功能,展現組件負責渲染內容。
若是要實現另外一套登錄組件時,可直接複用容器組件,只須要實現新的展現組件便可。
// 業務組件 可複用性比較高 function withLogin(config) { const { mapStateToProps, mapDispatchToProps } = config return (Comp) => { class Container extends Component { constructor(props) { super(props) this.state = { account: '', password: '', status: 'init', } } handleAccountChange = (e) => { this.setState({account: e.target.value}) } handlePasswordChange = (e) => { this.setState({password: e.target.value}) } handleLoginClick = () => { this.setState({ status: 'ing' }) request('/login', { params: { account: this.state.account, password: this.state.password, } }).then(() => { this.setState({status: 'succ'}) }).catch(() => { this.setState({status: 'fail'}) }) } render() { const propsFromState = mapStateToProps(this.state, this.props) const propsFromDispatch = mapDispatchToProps({ onAccountChange: this.handleAccountChange, onPasswordChange: this.handlePasswordChange, onSubmit: this.handleLoginClick, }, this.props) return ( <Comp {...this.props} {...propsFromState} {...propsFromDispatch} /> ) } } return LoginContainer } } // 展現組件 class Login extends Component { render() { const { account, password, onAccountChange, onPasswordChange, onSubmit } return ( <div> <input placeholder="帳號" value={account} onChange={(...args) => onAccountChange(...args)} /> <input placeholder="密碼" value={password} onChange={(...args) => onPasswordChange(...args)} /> <button onClick={() => onSubmit()}>登陸</button> </div> ) } } // 鏈接組件 const LoginContainer = withLogin({ mapStateToProps: (state, props) => { return { account: state.account, password: state.password, } }, mapDispatchToProps: (dispatch, props) => { return { onAccountChange: dispatch.onAccountChange, onPasswordChange: dispatch.onPasswordChange, onSubmit: dispatch.Submit, } } })
把UI上相互獨立的部分,劃分紅不一樣組件,防止渲染時相互影響。最多見的是列表組件。
點擊一個li, 其餘li全都從新渲染
class List extends Component { state = { selected: null } handleClick(id) { this.setState({selected: id}) } render() { const { items } = this.props return ( <ul> { items.map((item, index) => { const {text, id} = item const selected = this.state.selected === id return ( <li key={id} className={selected ? 'selected' : ''} onClick={() => this.handleClick(id)} > <span>{text}</span> </li> ) }) } </ul> ) } }
子組件使用PureComponent
或memo
,而且click事件回調函數直接使用this.handleClick
,而不是每次都建立新函數。
點擊li,最多隻會有2個子組件渲染。
// onClick時須要的參數,要傳進來 class Item extends PureComponent { render() { const { id, text, selected, onClick } = this.props return ( <li className={selected ? 'selected' : ''} onClick={onClick(id)} > <span>{text}</span> </li> ) } } class List extends Component { state = { selected: null } handleClick(id) { this.setState({selected: id}) } render() { const { items } = this.props return ( <ul> { items.map((item, index) => { const {text, id} = item return ( <Item key={id} id={id} // 傳進去 selected={this.state.selected === id} text={text} onClick={this.handleClick} /> ) }) } </ul> ) } }