如下內容,當具有ES6,JS語法,node環境,前端組件基礎概念,寫過java代碼,包你3天上手React項目,下面開始...css
https://gitee.com/tonysb/lear...
項目結構以下,Button的方式值得借鑑html
命令行使用 npx create-react-app my-app-name 便可建立項目前端
A: 父組件 B: 子組件
在A.js文件中使用<B name={name} getName={this.getName}>
其中name爲A文件中一個變量,getName爲A文件中一個方法
在B.js文件中,可直接使用this.props.name
或this.props.getName
或const { name, getName } = this.props
來獲得A中變量,或運行A中方法,最後一種最經常使用,這種方式是ES6中新增的解構賦值.
父->子 經過子標籤上加上屬性的方式,直接傳遞,在子重使用this.props來接住屬性
子->父 經過在子中調用父傳遞的方法來完成java
具體使用場景: 一個頁面右上角掛載一個三級聯動選項卡(三級數據從接口獲取),main做爲父組件主頁面,select做爲子組件三級選項卡頁面node
<React.Fragment> // 你的jsx代碼 </React.Fragment>
// ES6 ``,${}加三目運算符可處理複雜的css名字 <div className={`classA classB ${this.state.isSelect ? 'selected' : ''}`} /> // for循環遍歷請使用map方法,sortTableRows是state中一個變量 {sortTableRows && sortTableRows.map(item => ( <div key={item.id} className="table-row"> <span>{item.title}</span> <span>{item.author}</span> <span>{item.comments}</span> <span>{item.points}</span> <span> <CancelButton onClick={() => onMiss(item.id)}>miss</CancelButton> </span> </div> ))}
jsx合成事件綁定,js高階函數,綁定的是函數,不能讓函數立刻執行
不帶參數綁定,後面不能加(), 若是加,那函數會立刻執行,而不是事件發生時候回調執行
帶參數綁定,須要在一個匿名函數中寫綁定函數react
// 合成事件綁定,不帶參數 <li onClick={this.props.delItem}>{item}</li> // 合成事件綁定,帶參數 <li onClick={(index) => this.props.delItem(index)}>{item}</li>
1, state中設置searchTerm變量,用來填充input中value值
2, 綁定input中onChange事件,獲取event對象中value值,將該值set到searchTerm變量中git
state: 組件本身內部維護數據,每次更新只須要關係須要更改的數據
1, set數據不依賴以前的數據,直接調用setStateajax
this.setState({ foo: bar })
2, set數據依賴以前數據,必定要使用帶參數調用setStatechrome
this.setState((prevState, props) => ( // 你的代碼 )) // bad // setState是異步,代碼中多個set,有可能fooCount和barCount已經被改變 const { fooCount } = this.state const { barCount } = this.props this.setState({ count: fooCount + barCount }) // good this.setState((prevState, props) => ( count: prevState.fooCount + props.barCount ))
props: 父->子,全部傳遞過來的數據都附加在props中,子在props中能夠拿到全部父傳遞過來的數據
render: 只要state進行set操做,render必定會執行,包括父state進行set以後,父和子的render都會被執行redux
上述方式處理方式比較麻煩,推薦使用方式3
3, 父組件負責提供數據和處理處理的函數,子組件只負責獲取數據,渲染頁面,子組件事件交互,也是經過props來調用父組件中的函數(經常使用)
如下是使用場景和注意點
組件掛載階段(只會執行一次,render除外)
constructor(): 設置state,獲取父組件props,並初始化本身的state,並綁定函數中this指向
componentWillMount(): 不能獲取頁面dom元素,目前還沒用過
render():渲染頁面,不作運算,到這裏爲止,全部數據都應該是通過處理可直接使用的數據
componentDidMount(): 可獲取dom元素,ajax請求放這裏,調用setState,設置dom元素監聽,繪製canvas
組件更新階段(state或props發生變化)
componentWillReceiveProps(nextProps): nextProps爲更新新屬性,可進行新舊屬性對比,也能夠根據新數據來計算和設置本身的state
shouldComponentUpdate(nextProps, nextState): 返回布爾值,可作渲染優化,根據場景決定是否渲染該組件,不要調用setState
componentDidUpdate(prevProps, prevState): 操做 DOM 或者執行更多異步請求的機會
componentWillUnmount: 取消網絡請求,刪除監聽,一些收尾工做,不要調用setState
// 方式1 getTodoItem = () => { // 你的邏輯 } // 方式2 constructor(props) { super(props) this.inputOnChange = this.inputOnChange.bind(this) } inputOnChange() { // 你的邏輯 }
ES6類組件: 有this,props,有state,有生命週期,根據設計圖,通常看成父組件使用,從接口拿數據,計算成品數據,編寫事件函數來處理數據
無狀態組件(純函數): 接收輸入(props),輸出jsx組件實例,沒有this,沒有生命週期,沒有state,可根據props中的數據來計算符合本身要求的數據(組件中直接調用方法),
props中能夠傳遞數據,也能夠傳遞函數,通常當作子組件使用,demo以下
import React from 'react' /*查詢表單組件 * Search在使用的時候,標籤中間就是children * <Search value={searchTerm} onSubmit={this.onSubmit} onChange={this.onChange}>查詢</Search> children的值就是查詢 */ const Search = ({value, onChange, onSubmit, children}) => { return ( <div> <form onSubmit={onSubmit}> <input type='text' value={value} onChange={onChange}/> <button type='submit'>{children}</button> </form> </div> ) } export default Search
import React from 'react' import {Slider} from "antd" import moment from "moment" import './style.less' /* * 時間軸無狀態組件 * timeData: 時間數組列表 * timeChange: 時間軸change事件的回調 * worktime: 當前選中時間 * */ const TimeSlider = ({timeData, timeChange, worktime}) => { /* * 獲取時間軸當前選中值 * */ const getDefaultValue = () => { const { id } = times.find(item => { return item.dateTime === worktime }) return id } /* * 獲取時間軸的總長度 * */ const getMax = () => { return timeData.length } /* * 獲取時間軸顯示的time數據 * 格式: * { * 0: '2019-11-11' * 24: '2019-11-12' * 23: '2019-11-13' * } * */ let times = [] const getMarks = () => { let dates = [] console.log('timeData len', timeData.length) timeData.map((item, index) => { const time = {id: index, dateTime: item} times.push(time) dates.push(moment(item).format('YYYY-MM-DD')) }) const newDates = [...new Set(dates)] console.log('newDates', newDates) let marks = {} let datesAmount = [] newDates.map(item => { const amount = getDateAmount(item, timeData) const temp = {date: item, amount: amount} datesAmount.push(temp) }) for (let i = 0,length = datesAmount.length; i < length; i++) { const date = { style: { color: '#fff', marginLeft: 0 }, label: moment(datesAmount[i].date).format('MM/DD'), } if (i === 0) { //const mark = JSON.parse(`{"0":"${date}"}`) const mark = {0: date} Object.assign(marks, mark) } else { const index = i - 1 const lastAmount = getLastDateAmount(index, datesAmount) // const mark = JSON.parse(`{"${lastAmount}":"${date}"}`) const mark = { [lastAmount]: date } Object.assign(marks, mark) } } return marks } /* * 根據 2019-11-11來獲取 數據 ['2019-11-11 11:11:11'] 對應的小時數量 * */ const getDateAmount = (date, timeData) => { let amount = 0 for (let i = 0,length = timeData.length; i < length; i++ ) { const item = timeData[i] if (item.includes(date)) { amount = amount + 1 } } return amount } /* * 獲取當前index往前推一個的全部小時數量 * */ const getLastDateAmount = (index, datesAmount) => { let sum = 0 for (let i = 0; i <= index; i++) { sum = sum + datesAmount[i].amount } return sum } const formatter = (value) => { const time = times.find(item => { return item.id === value }) return moment(time.dateTime).format('HH:mm') } const onTimeChange = (value) => { const time = times.find(item => { return item.id === value }) timeChange(time.dateTime) } return ( <div className='time-slider'> <Slider max={getMax()} marks={getMarks()} defaultValue={getDefaultValue()} value={getDefaultValue()} tipFormatter={formatter} onChange={onTimeChange}/> </div> ) } export default TimeSlider
做用: 在當前組件中,建立dom,獲取dom
class createRefDemo extends Component { constructor(props) { super(props) this.myInput = React.createRef() } handleInputChange = () => { const value = this.myInput.current.value // 這裏經過current可獲取input的dom對象 } render() { return ( <input id="hello" className='input' type="text" value='hello' onChange={this.handleInputChange} ref={this.myInput}/> ) } }
參考連接: https://juejin.im/post/5c0dd4...
做用: 將refDom能夠傳遞給子孫組件,永遠傳遞下去,在HOC中經常使用
做用: 脫離父組件,將該組件掛載到dom的任何位置
// 將selectComp組件掛載到bodyDom下面 const selectComp = <Selectcj /> ReactDOM.createPortal( selectComp, document.querySelector('body'), )