tips: jsx把如下語法的程式碼編譯成虛擬DOM物件:
<h1 title="red">hello world<span>I am span</span></h1>
等價<=>
{
"props": {
"title": "red",
"children": [
"hello world",
{
"props": {
"children": "I am span"
},
"type": "span"
}
]
},
"type": "h1"
}
複製程式碼
babel會在jsx編譯完成後,呼叫ReactDOM.render(jsxObject, rootElement),並把jsx編譯出來的物件傳進去.開始解析這個虛擬的DOM,並渲染到rootElement.
1.基本使用
屬性中有些不是原來的屬性名: class => className,for => htmlFor,dangerouslySetInnerHTML(相當於v-html)
取值的時候:{}表示的是js < 表示的是jsx
let str = '<h1>kkkk</h1>'
function fn() {
return <h1>ooooooooooo</h1>
}
//React.Fragment相當於vue的temmplate,沒有實際意義
let h1 = <React.Fragment>
<div className="abc">hello world<br />
<label htmlFor="username">usssssssss</label>
<input type="text" id="username" />
<!--style新增樣式寫法-->
<div style={{ color: 'red' }}>xixixixixixixixixi</div>
<div>{str}</div>
<!--執行函式寫法-->
<div>{fn()}</div>
<!--熟悉vue的知道,相當於v-html-->
<div dangerouslySetInnerHTML={{ __html: str }}></div>
</div>
</React.Fragment>
ReactDOM.render(h1, window.root)
複製程式碼
2.遍歷寫法
//key的要求最好不要用陣列的索引一般用id dom-diff
let arr = [1,2,3]
let el2 = (
arr.map((item,key) => {
return <li key={key}>{item}</li>
})
)
ReactDOM.render(el2, window.root)
複製程式碼
3.元件寫法
// 繼承React.Component
class Clock extends Component {
state = {
time: new Date().toLocaleString()
}
componentDidMount() {
this.timer = setInterval(() => {
this.setState({ time: new Date().toLocaleString() })
}, 1000)
}
componentWillUnmount() {
clearInterval(this.timer)
}
des = () => {
ReactDOM.unmountComponentAtNode(window.root)
}
//主要是繫結事件的函式this會丟失,要麼bind(this),要麼箭頭函式解決
render() {
return (
<div>
<span>{this.state.time}</span>
<button onClick={this.des} >destroy</button>
</div>
)
}
}
複製程式碼
4.屬性校驗寫法
//安裝prop-types包
class Person extends Component {
//constructor能拿到props屬性~
constructor(props) {
super()
console.log(props);
}
/* 寫法難看*/
// Person.propTypes = {}
// es新寫法~
static propTypes = {
name: PropTypes.string,
age: PropTypes.number.isRequired,
gender: PropTypes.oneOf(['male', 'femal']),
hobby: PropTypes.arrayOf(PropTypes.string),
pos: PropTypes.shape({
x: PropTypes.number.isRequired,
y: PropTypes.number.isRequired,
}),
salary(obj, key, p) {
console.log(arguments);
if (obj[key] < 4000) {
throw new Error('工姿太低')
}
}
}
//使用屬性值的的時候直接this.props.xxx
render() {
return <div>
<p>{this.props.name}</p>
<p>{this.props.age}</p>
<p>{this.props.hobby}</p>
<p>{this.props.pos.x},{this.props.pos.y}</p>
<p>{this.props.salary}</p>
</div>
}
}
let obj = {
name: 'zfpx',
age: 9,
gender: 'male',
hobby: ['游泳, 跑步'],
pos: { x: 433, y: 822 },
salary: 3000
}
//傳屬性的方便寫法~
render(<Person {...obj} />, window.root)
複製程式碼
5.生命週期
元件生命週期有點像洋蔥,遇到render就開始了~
class Person extends Component {
state = {
num: 0
}
static defaultProps = {
a: 1,
}
constructor() {
console.log('parent-constructor');
super()
}
// 16.3被廢棄了,constructor可以替代
componentWillMount() {
console.log('parent-componentWillMount');
}
// 當state變化的時候回撥用,直接決定render是否呼叫
shouldComponentUpdate() {
return true;
}
componentWillUpdate() {
console.log('parent-componentWillUpdate');
}
render() {
console.log('parent-render');
return <div><button onClick={() => {
this.setState({ num: this.state.num + 1 })
}}>add</button>{this.state.num}
<ChildComponent n={this.state.num}></ChildComponent>
</div>
}
componentDidUpdate() {
console.log('parent-componentDidUpdate');
}
componentDidMount() {
console.log('parent-componentDidMount');
}
componentWillUnmount() {
console.log('parent-componentWillUnmount');
}
}
class ChildComponent extends Component {
constructor() {
console.log('child-constructor');
super()
}
// 但是16.3被廢棄了,constructor可以替代
componentWillMount() {
console.log('child-componentWillMount');
}
// 第一次不執行。這個也在16.3廢棄了
componentWillReceiveProps() {
console.log('兒子收到新屬性');
}
// 當state變化的時候回撥用,直接決定render是否呼叫
shouldComponentUpdate() {
return true;
}
componentWillUpdate() {
console.log('child-componentWillUpdate');
}
render() {
console.log('child-render');
return (
<div>child {this.props.n}</div>
)
}
componentDidUpdate() {
console.log('child-componentDidUpdate');
}
componentDidMount() {
console.log('child-componentDidMount');
}
componentWillUnmount() {
console.log('child-componentWillUnmount');
}
}
// componentWillReceiveProps(不應該在這裡面調setState,但是大家都這麼呼叫。。。)
// componentWillMount
// componentDidMount
// 只有這三個才能呼叫setState,其他生命週期方法呼叫的話就直接死迴圈了
render(<Person />, window.root)
複製程式碼
6.新版生命週期16.3
class ChildComponent extends Component {
//componentWillMount() 移除
//componentWillReceiveProps 移除
// getSnapshotBeforeUpdate必須return一個值
// 而且getSnapshotBeforeUpdate必須配合componentDidMount用,componentDidMount會接收到它return的引數
// getDerivedStateFromProps
// 1.必須要求有state
// 2.必須不能用componentWillReceiveProps
// 3.必須不能用componentWillupdate(替代getSnapshotBeforeUpdate)
// 4.必須不能用componentWillMount
state = {}
// 第一次就呼叫了,這個方法返回的就是state
static getDerivedStateFromProps(newProps) {
console.log(newProps);
return {
a: 11
}
}
}
複製程式碼
7.DOM元素相關用法一
// 非受控元件 - 方便,可以和第三方庫結合使用
class Uncontrol extends Component {
handleClick = () => {
// 寫法一
console.log(this.a.value);
// 寫法二
console.log(this.abc.current.value);
}
// 寫法二
abc = React.createRef();
render() {
return (
<div>
<input type="text" ref={(dom) => { this.a = dom }} />
<input type="text" ref={this.abc} />
<button onClick={this.handleClick}>click</button>
</div>
)
}
}
// 大寫認為是元件,自動new這個Control,呼叫render 把render返回的結果 作為要渲染的內容
ReactDOM.render(<Uncontrol />, window.root)
複製程式碼
DOM元素相關用法二
- 通過onChange事件來更新state
- name的巧妙用
class Control extends Component {
state = {
a: 1
}
handleClick = () => {
// 寫法一
console.log(this.a.value);
// 寫法二
console.log(this.abc.current.value);
}
changeHandler = (e) => {
console.log(e.target.value, e.target.name);
this.setState({
[e.target.name]: e.target.value
})
}
// 寫法二
abc = React.createRef();
render() {
return (
<div>
<input type="text" name="a" defaultValue={this.state.a} onChange={this.changeHandler} />
<input type="text" name="b" defaultValue={this.state.b} onChange={this.changeHandler} />
<button onClick={this.handleClick}>click</button>
</div>
)
}
}
// 大寫認為是元件,自動new這個Control,呼叫render 把render返回的結果 作為要渲染的內容
ReactDOM.render(<Control />, window.root)
複製程式碼
8.元件間的通訊
- 通過屬性傳遞(這個跟屬性傳遞一樣的,只不過屬性變成了function)
<List delById={this.delById} />
<Item delById={this.props.delById}></Item>
複製程式碼
- 使用React.createContext()
使用Provider包住所有
<Provider value={{ delById: this.delById }}>
</Provider>
在要跨元件通訊的地方
render() {
return (
<Consumer>
{
(value) => {
return <div>{this.props.ctt.a}
<button onClick={() => this.handleClick(this.props.ctt.id)}>delete props methods</button>
<button onClick={() => value.delById(this.props.ctt.id)}>delete provider methods</button>
</div>
}
}
</Consumer>
)
}
複製程式碼