React 全家桶-React基礎 用於構建用戶界面的JavaScript庫。 facebook開源、組件化、聲明式編碼、React Native移動端開發、虛擬DOM+Diffing演算法 官網:https://react.docschina.org/ 第一章:React的基本使用 1.相關js庫 ...
React 全家桶-React基礎
用於構建用戶界面的JavaScript庫。
facebook開源、組件化、聲明式編碼、React Native移動端開發、虛擬DOM+Diffing演算法
官網:https://react.docschina.org/
第一章:React的基本使用
1.相關js庫
- react.js:React核心庫
- React-dom.js:提供操作DOM的react擴展庫
- Babel.min.js:解析JSX語法代碼轉為JS代碼的庫
- ES6轉ES5
2.創建虛擬DOM的兩種方式
- JSX
- JS
3.JSX
React定義的一種類似於XML的JS擴展語法:JS + XML
它最終產生的結果不是字元串,也不是HTML/XML標簽,而是一個JS對象
語法規則:
-
標簽中混入JS表達式要用{}
-
表達式:一個表達式會返回一個值,而代碼塊不一定有值返回
-
-
樣式的類名指定不要用class屬性名,用className
-
內聯樣式,要用style={{key: value}}的形式去寫
-
只能有一個根標簽
-
標簽必須閉合
-
JSX標簽轉換規則
- 若小寫字母開頭,則將該標簽轉換為html中同名元素,若html中無該標簽對應的同名元素,則報錯
- 若大寫開頭,則渲染對應的組件,若組件未曾定義,則報錯
4.模塊化與組件化
模塊:向外提供特定功能的js程式,一般是一個js文件
組件:實現局部功能效果的代碼和資源的集合
第二章:React面向組件編程
1.基本理解和使用
1.1 React開發者工具
React Developer Tools 瀏覽器插件
1.2 效果
函數式組件
<body>
<div id="ctx"></div>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
// 1. 創建函數式組件
function Demo () {
console.log(this) // 此處的this是undefined,因為babel編譯後開啟了嚴格模式
return <h2>用函數定義的組件</h2>
}
// 2. 渲染組件到頁面
ReactDOM.render(<Demo/>, document.getElementById('ctx'))
/*
渲染步驟:
1. React解析組件標簽,找到了了Demo組件
2. 發現組件是使用函數定義的。隨後調用該函數,將返回的虛擬DOM轉為真實DOM,隨後呈現在頁面上
*/
</script>
</body>
類式組件
<body>
<div id="ctx"></div>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
// 1. 創建類式組件
class MyComponent extends React.Component {
render () {
console.log(this)
return <h2>用類定義的組件,適用於複雜組件的定義</h2>
}
}
ReactDOM.render(<MyComponent/>, document.getElementById('ctx'))
/*
渲染步驟:
1. React解析組件標簽,找到了了 MyComponent 組件
2. 發現組件是使用類定義的。隨後new出該類的實例,並通過該實例調用原型上的render方法,將返回的虛擬DOM轉為真實DOM,隨後呈現在頁面上
*/
</script>
</body>
2.組件三大核心屬性
2.1 state
<body>
<div id="ctx"></div>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
class Weather extends React.Component {
state = {
isHot: false
}
render () {
const {isHot} = this.state
return <h2 onClick={this.changeWeather}>天氣:{isHot ? '熱' : '涼' },風速:{isHot ? '一級' : '二級' }</h2>
}
// 自定義方法,要用賦值語句+箭頭函數(箭頭函數沒有自己的this)
changeWeather = () => {
this.state.isHot = !this.state.isHot
this.setState(this.state)
}
}
ReactDOM.render(<Weather/>, document.getElementById('ctx'))
</script>
</body>
2.2 props
類式組件使用props
<body>
<div id="ctx"></div>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
<!-- 引入prop-types,用於對組件標簽進行限制 -->
<script src="../js/prop-types.js" type="text/javascript"></script>
<script type="text/babel">
class Person extends React.Component {
// 構造器是否接收props,是否傳遞給super?問題取決於:是否希望在構造器中通過this訪問props
constructor(props) {
super(props)
console.log('c', this.props)
}
// 對標簽屬性進行類型、必要性的限制
static propTypes = {
name: PropTypes.string.isRequired
}
// 指定預設值
static defaultProps = {
sex: '未知'
}
render () {
const {name, age, sex} = this.props
return (
<ul>
<li>姓名:{name}</li>
<li>性別:{sex}</li>
<li>年齡:{age}</li>
</ul>
)
}
}
const p = {name: '逾期', age: 18, sex: '女'}
ReactDOM.render(<Person {...p}/>, document.getElementById('ctx'))
</script>
</body>
函數式組件使用props
<body>
<div id="ctx"></div>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
<!-- 引入prop-types,用於對組件標簽進行限制 -->
<script src="../js/prop-types.js" type="text/javascript"></script>
<script type="text/babel">
function Person (props) {
const {name, sex, age} = props
return (
<ul>
<li>姓名:{name}</li>
<li>性別:{sex}</li>
<li>年齡:{age}</li>
</ul>
)
}
// 對標簽屬性進行類型、必要性的限制
Person.propTypes = {
name: PropTypes.string.isRequired
}
// 指定預設值
Person.defaultProps = {
sex: '未知'
}
const p = {name: '逾期', age: 18, sex: '女'}
ReactDOM.render(<Person {...p}/>, document.getElementById('ctx'))
</script>
</body>
2.3 refs與事件處理
組件內的標簽可以定義ref屬性來標識自己
2.3.1 字元串形式的refs
<body>
<div id="ctx"></div>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
<!-- 引入prop-types,用於對組件標簽進行限制 -->
<script src="../js/prop-types.js" type="text/javascript"></script>
<script type="text/babel">
class Demo extends React.Component {
showData = () => {
const {input1} = this.refs
alert(input1.value)
}
showData2 = () => {
const {input2} = this.refs
alert(input2.value)
}
render() {
return (
<div>
<input ref="input1" type="text" placeholder="點擊按鈕提示數據"/>
<button onClick={this.showData}>點我提示左側數據</button>
<input ref="input2" onBlur={this.showData2} type="text" placeholder="失去焦點提示數據"/>
</div>
)
}
}
ReactDOM.render(<Demo/>, document.getElementById('ctx'))
</script>
</body>
2.3.2 回調函數形式的refs
<body>
<div id="ctx"></div>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
<!-- 引入prop-types,用於對組件標簽進行限制 -->
<script src="../js/prop-types.js" type="text/javascript"></script>
<script type="text/babel">
class Demo extends React.Component {
showData = () => {
const {input1} = this
alert(input1.value)
}
showData2 = () => {
const {input2} = this
alert(input2.value)
}
render() {
return (
<div>
<input ref={c => this.input1 = c} type="text" placeholder="點擊按鈕提示數據"/>
<button onClick={this.showData}>點我提示左側數據</button>
<input onBlur={this.showData2} ref={c => this.input2 = c} type="text" placeholder="失去焦點提示數據"/>
</div>
)
}
}
ReactDOM.render(<Demo/>, document.getElementById('ctx'))
</script>
</body>
2.3.3 createRef
<body>
<div id="ctx"></div>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
<!-- 引入prop-types,用於對組件標簽進行限制 -->
<script src="../js/prop-types.js" type="text/javascript"></script>
<script type="text/babel">
class Demo extends React.Component {
myRef = React.createRef()
showData = () => {
console.log(this.myRef)
alert(this.myRef.current.value)
}
render() {
return (
<div>
<input ref={this.myRef} type="text" placeholder="點擊按鈕提示數據"/>
<button onClick={this.showData}>點我提示左側數據</button>
</div>
)
}
}
ReactDOM.render(<Demo/>, document.getElementById('ctx'))
</script>
</body>
2.3.4 事件處理
2.4 收集表單數據
2.4.1 受控組件
<body>
<div id="ctx"></div>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
<!-- 引入prop-types,用於對組件標簽進行限制 -->
<script src="../js/prop-types.js" type="text/javascript"></script>
<script type="text/babel">
class Demo extends React.Component {
state = {
username: '',
password: ''
}
saveUsername = (e) => {
this.setState({username: e.target.value})
}
savePassword = (e) => {
this.setState({password: e.target.value})
}
handleSubmit = (e) => {
e.preventDefault() // 阻止form表單提交事件
const {username, password} = this.state
alert(`username: ${username.value}, password: ${password.value}`)
}
render() {
return (
<form onSubmit={this.handleSubmit}>
用戶名:<input onChange={this.saveUsername} type="text" name="username"/>
密 碼:<input onChange={this.savePassword} type="text" placeholder="password"/>
<button>login</button>
</form>
)
}
}
ReactDOM.render(<Demo/>, document.getElementById('ctx'))
</script>
</body>
2.4.2 非受控組件
<body>
<div id="ctx"></div>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
<!-- 引入prop-types,用於對組件標簽進行限制 -->
<script src="../js/prop-types.js" type="text/javascript"></script>
<script type="text/babel">
class Demo extends React.Component {
handleSubmit = (e) => {
e.preventDefault() // 阻止form表單提交事件
const {username, password} = this
alert(`username: ${username.value}, password: ${password.value}`)
}
render() {
return (
<form onSubmit={this.handleSubmit}>
用戶名:<input ref={c => this.username = c} type="text" name="username"/>
密 碼:<input ref={c => this.password = c} type="text" placeholder="password"/>
<button>login</button>
</form>
)
}
}
ReactDOM.render(<Demo/>, document.getElementById('ctx'))
</script>
</body>
2.4.3 函數的柯里化
<body>
<div id="ctx"></div>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
<!-- 引入prop-types,用於對組件標簽進行限制 -->
<script src="../js/prop-types.js" type="text/javascript"></script>
<script type="text/babel">
class Demo extends React.Component {
state = {
username: '',
password: ''
}
/**
* 高階函數:如果一個函數符合下麵兩個規範中的任一,那該函數就是高階函數
* 1. 若A函數接收的參數是一個函數,那麼A就可以稱之為高階函數
* 2. 若A函數調用的返回值依然是一個函數,那麼A就可以稱之為高階函數
* 函數的柯里化:通過函數調用繼續返回函數的方式,實現多次接收參數,最後統一處理的函數編碼形式
*/
saveFormData = (dataType) => {
return (e) => {
return this.setState({[dataType]: e.target.value})
}
}
handleSubmit = (e) => {
e.preventDefault() // 阻止form表單提交事件
const {username, password} = this.state
alert(`username: ${username.value}, password: ${password.value}`)
}
render() {
return (
<form onSubmit={this.handleSubmit}>
用戶名:<input onChange={this.saveFormData('username')} type="text" name="username"/>
密 碼:<input onChange={this.saveFormData('password')} type="text" placeholder="password"/>
<button>login</button>
</form>
)
}
}
ReactDOM.render(<Demo/>, document.getElementById('ctx'))
</script>
</body>
2.5 組件生命周期
2.5.1 舊版生命周期
<body>
<div id="ctx"></div>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
<!-- 引入prop-types,用於對組件標簽進行限制 -->
<script src="../js/prop-types.js" type="text/javascript"></script>
<script type="text/babel">
class Count extends React.Component {
constructor(props) {
console.log('Count-constructor')
super(props)
this.state = {
count: 0
}
}
add = () => {
const {count} = this.state
this.setState({
count: count+1
})
}
death = () => {
ReactDOM.unmountComponentAtNode(document.getElementById('ctx'))
}
force = () => {
this.forceUpdate()
}
componentWillMount() {
console.log('Count-componentWillMount')
}
componentDidMount() {
console.log('Count-componentDidMount')
}
shouldComponentUpdate() {
console.log('Count-shouldComponentUpdate')
return false
}
componentWillUpdate() {
console.log('Count-componentWillUpdate')
}
componentDidUpdate() {
console.log('Count-componentDidUpdate')
}
componentWillUnmount() {
console.log('Count-componentWillUnmount')
}
render() {
console.log('Count-render')
const {count} = this.state
return (
<div>
<h2>當前求和為: {count}</h2>
<button onClick={this.add}>點我+1</button>
<button onClick={this.death}>卸載組件</button>
<button onClick={this.force}>強制更新</button>
</div>
)
}
}
// 父組件A
class A extends React.Component {
state = {
carName: '賓士'
}
changeCar = () => {
this.setState({carName: '奧迪'})
}
render() {
return (
<div>
<div>A component</div>
<button onClick={this.changeCar}>換車</button>
<B carName={this.state.carName}/>
</div>
)
}
}
// 子組件B
class B extends React.Component {
// 第一次渲染不會調用這個鉤子
componentWillReceiveProps(props) {
console.log('B-componentWillReceiveProps', props)
}
render() {
return (
<div>
<div>B component: carName={this.props.carName}</div>
</div>
)
}
}
// ReactDOM.render(<Count/>, document.getElementById('ctx'))
ReactDOM.render(<A/>, document.getElementById('ctx'))
</script>
</body>
2.5.2 新版生命周期
<body>
<div id="ctx"></div>
<script src="../newjs/react.development.js"></script>
<script src="../newjs/react-dom.development.js"></script>
<script src="../js/babel.min.js"></script>
<!-- 引入prop-types,用於對組件標簽進行限制 -->
<script src="../js/prop-types.js" type="text/javascript"></script>
<script type="text/babel">
class Count extends React.Component {
constructor(props) {
console.log('Count-constructor')
super(props)
this.state = {
count: 0
}
}
add = () => {
const {count} = this.state
this.setState({
count: count+1
})
}
death = () => {
ReactDOM.unmountComponentAtNode(document.getElementById('ctx'))
}
force = () => {
this.forceUpdate()
}
// 在更新之前獲取快照,方法返回值將會作為參數傳遞給componentDidUpdate鉤子
getSnapshotBeforeUpdate () {
console.log('getSnapshotBeforeUpdate')
return 'liergou'
}
// getDerivedStateFromProps方法的返回值會作為state的值
static getDerivedStateFromProps (props, state) {
console.log('getDeriverdStateFromProps', props, state)
return null
}
componentDidMount() {
console.log('Count-componentDidMount')
}
shouldComponentUpdate() {
console.log('Count-shouldComponentUpdate')
return true
}
componentDidUpdate(preProps, preState, snapshotValue) {
console.log('Count-componentDidUpdate', preProps, preState, snapshotValue)
}
componentWillUnmount() {
console.log('Count-componentWillUnmount')
}
render() {
console.log('Count-render')
const {count} = this.state
return (
<div>
<h2>當前求和為: {count}</h2>
<button onClick={this.add}>點我+1</button>
<button onClick={this.death}>卸載組件</button>
<button onClick={this.force}>強制更新</button>
</div>
)
}
}
ReactDOM.render(<Count age={88}/>, document.getElementById('ctx'))
</script>
</body>