又一篇來自平常開發的彙總:各位客官請對號入席,店小二逐一上菜。
react數組循環,基本都會設置一個惟一的key,表格的對象數組循環通常沒什麼問題,數據基本都會有一個id。那有種狀況就比較坑了,出如今表單形式的頁面結構中,對某個數組進行增刪改操做,通常對於非對象數組而言,沒有id,可能不少人會偷懶,循環的時候,直接設置數組的下標index做爲key,當出現增刪改時候,就會出現數據對不上或者從新渲染組件的問題等。解決方案有不少種,例如把字符串數組等重組對象數組,每一個元素設置一個惟一id等。另外有個方式:推薦使用shortid生成惟一key的數組,和數據數組一塊兒使用,省去提交數據時再重組數組。html
import React from 'react'; import shortid from 'shortid'; class Demo extends React.Component { constructor(props) { super(props); this.state = { data: ['a', 'b', 'c'] } this.dataKeys = this.state.data.map(v => shortid.generate()); } deleteOne = index => { // 刪除操做 const { data } = this.state; this.setState({ data: data.filter((v, i) => i !== index) }); this.dataKyes.splice(index, 1); } render() { return ( <ul> { data.map((v, i) => <li onClick={i => this.deleteOne(i)} key={this.dataKeys[i]} > {v} </li> ) } </ul> ) } } // 稍微抽取,能夠封裝一個通用的組件
經過判斷值是否存在來控制元素是否顯示,通常三目運算能夠達到此效果,最簡單的仍是用短路的寫法:react
// 不錯 const flag = 'something'; flag && <div></div> // 很好 // 注意通常可能上面寫法多一些,但當flag爲0 的時頁面上會顯示0,用!!將其轉爲boolean避免坑, // 代碼也更規範 const flag = 'something'; !!flag && <div></div>
使用組件,傳遞props:git
const { data, type, something } = this.state; <Demo data={data} type={type} something={something} />
也許另一種傳遞方式更簡潔:github
const { data, type, something } = this.state; <Demo {...{ data, id, something }} />
組件的props有時候會定義不少,可是調用組件傳遞props的時候又想一個個傳,不想一次性傳遞一個option對象,經過擴展運算符和解構賦值能夠簡化此操做:數組
const Demo = ({ prop1, prop2, prop3, ...restProps }) => ( <div> xxxx { restProps.something } </div> ) // 父組件使用Demo <Demo prop1={xxx} prop2={xxx} something={xxx} />
通常改變state值的一種方式:性能優化
const { data } = this.state; this.setState({ data: {...data, key: 1 } });
另一種能夠經過callback的方式改變state的值antd
this.setState(({ data }) => ({ data: {...data, key: 1 } }));
還能夠:app
this.setState((state, props) => { return { counter: state.counter + props.step }; });
React 性能優化有不少種方式,那常見的一種就是在生命週期函數shouldComponentUpdate裏面判斷某些值或屬性來控制組件是否從新再次渲染。ide
判斷通常的字符串,數字或者基礎的對象,數組都仍是比較好處理,那嵌套的對象或者數組就比較麻煩了,對於這種,能夠轉成字符串處理,但屬性值的位置不一樣時,那就無效了。函數
推薦使用lodash(或者其餘的相似庫)的isEqual對嵌套數組或對象進行判斷(相比其餘方式更簡單些)
shouldComponentUpdate(nextProps, nextState) { if (_.isEqual(nextState.columns, this.state.columns)) return false; return true; }
建立彈層的三種方式:
// 彈層 const Dialog = () => <div>彈層</div> // 某組件 render() { return ( this.state.showDialog && <Dialog /> ) }
2.經過Portals建立通道,在根節點外部掛載組件-但仍是須要每次引入而且在render裏面調用
// 彈層 class Dialog extends React.Component { constructor(props) { super(props); this.el = document.createElement('div'); } componentDidMount() { modalRoot.appendChild(this.el); } componentWillUnmount() { modalRoot.removeChild(this.el); } render() { return ReactDOM.createPortal( this.props.children || <div>xxxx</div>, this.el, ); } } // 某組件 render() { return ( this.state.showDialog && <Dialog /> ) }
3.推薦使用ReactDom.render建立彈層-掛載根節點外層,使用也更方便
// demo let dialog; class Dialog { show(children) { // 顯示 this.div = document.createElement('div'); document.body.appendChild(this.div); ReactDom.render(children || <div>xxxx</div>, this.div); } destroy() { // 銷燬 ReactDom.unmountComponentAtNode(this.div); this.div.parentNode.removeChild(this.div); } } export default { show: function(children) { dialog = new Dialog(); dialog.show(children); }, hide: xxxxx }; // 某組件 import Dialog from 'xxx'; alert = () => { Dialog.show(xxxx); } render() { return ( <button onClick={this.alert}>點擊彈層</button> ) }
render props是如今很流行的一種渲染方式,經過回調函數,渲染子組件,參數可爲父組件的任意屬性值(官網也有相應的介紹)新版的contextApi也採用了這個模式。
不少種場景使用此方式的作法:
// 權限控制組件,只須要封裝一次connect, // 經過render props向子組件傳遞權限 class AuthWidget extends Component { render() { return this.props.children(this.props.auth); } } const mapStateToProps = state => { const { auth } = state; return { auth: state.auth }; }; export default connect(mapStateToProps)(AuthWidget); // 其餘組件使用 <AuthWidget children={auth => auth.edit && <a>編輯</a>} /> // 使用antd的form時 const Test = ({ form, children }) => { return children(form); }; const FormTest = Form.create()(Test); class Demo extends Component { render() { return ( <div> xxxxx <FormTest> { form => { this.form = form; return ( <Form> <Form.Item> {getFieldDecorator('field', xxx)( <Input placeholder="請輸入連接地址" /> )} </Form.Item> </Form> ) }} </FormTest> </div> ) } }
子組件改變父組件的state方式有不少種,能夠在父組件設置一個通用函數,相似:setParentState,經過子組件回調處理時,就能夠更方便的統一處理:
// 父組件 state = { data: {} } setParentState = obj => { this.setState(obj); } // 子組件 onClick = () => { this.props.setParentState({ data: xxx }); }
永遠不要直接設置state的值:this.state.data = { a: 1 }。這個會致使幾個問題:
1:組件不會從新渲染 2:shouldComponentUpdate(nextProps, nextState) 函數裏面 this.state的值是已經改變了,和nextState的值相同。
舉個栗子:
// wrong const { data } = this.state; data.a = 1; // 等價於this.state.data.a = 1; this.setState({ data }); // shouldComponentUpdate裏面觀察到 this.state 和nextState的值是相同的 // 此時函數裏面性能相關的優化是無效的 // correct 須要用到當前state值的寫法 this.setState(state => ({ data: {...state.data, a: 1} }))
各位客官,菜已上齊,請慢用react相關討論,請加Q羣:743490497