@bebal/preset-react
- create-react-app腳手架預設配置了@bebal/preset-react依賴
- 該babel外掛可以將jsx轉為React.createElement函式(有點像vue中的render函式)
- 然後呼叫react-dom庫中的render方法就可以將元素渲染至指定的DOM節點(有點像vue中的$mount方法)
// jsx
<div className={red} style={customStyle}>
<div>i am a child</div>
</div>
複製程式碼
// @babel/preset-react 轉譯後
"use strict";
React.createElement(
"div",
{ className: red, style: customStyle },
React.createElement(
"div",
null,
"i am a child"
)
);
複製程式碼
元件
特點:方便複用和管理;
- react中函式可以是元件(元件名大寫),和jsx元素、react元素來進行區分;
元件型別
- 函式型元件
- 函式型元件沒有this指向
- 函式型元件沒有生命週期
- 函式型元件沒有狀態
- 函式型元件有可以接收props物件
import React from 'react';
import reactDOM from 'react-dom';
function CustomElement(props) {
const data = {
name: 'function'
}
return(
<>
<h1>function component</h1>
<p>I have a somethings: {data.name}</p>
<span>I get somethings from my parent: {props.data}</span>
</>
)
}
reactDOM.render(<CustomElement data='data from parent'></CustomElement>, window.root);
複製程式碼
- 型別元件
- 型別元件必須有render方法,返回一個jsx元素
import React from 'react';
import reactDOM from 'react-dom';
class CustomElement extends React.Component {
state = {
name: 'class'
}
render() {
return (
// 必須有一個根元素對所有元素進行包裹
<>
<h1>class component</h1>
<p>I have a somethings: {this.state.name}</p>
<span>I get somethings from my parent: {this.props.data}</span>
</>
)
}
}
reactDOM.render(<CustomElement data='data from parent'></CustomElement>, window.root);
複製程式碼
常見繫結樣式方法
- class
import './custom.css'
class CustomButton extends Component {
render() {
return (
<button className='custom'>click</button>
);
}
}
複製程式碼
- style
const customStyle = {
color: 'red'
}
class CustomButton extends Component {
render() {
return (
<button style={customStyle}>click</button>
);
}
}
複製程式碼
常見的繫結事件方法
- bind
class CustomButton extends Component {
say() {
console.log(this);
}
render() {
return (
<button onClick={this.say.bind(this)}>click</button>
);
}
}
複製程式碼
- 箭頭函式
class CustomButton extends Component {
say() {
console.log(this);
}
render() {
return (
<button onClick={() => this.say}>click</button>
);
}
}
複製程式碼
- es2016繫結方式
class CustomButton extends Component {
say = () => {
console.log(this);
}
render() {
return (
<button onClick={this.say}>click</button>
);
}
}
複製程式碼
受控元件
受控元件可以實時校驗
class CustomElement extends React.Component {
state = {
username: 'neo',
password: '123456'
}
handle = (e) => {
this.setState({
[e.target.name]: e.target.value
})
}
handleSubmit = (e) => {
e.preventDefault();
console.log(JSON.stringify(this.state));
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input type="text" name="username" value={this.state.username} onChange={this.handle} />
<input type="text" name="password" value={this.state.password} onChange={this.handle} />
<button>submit</button>
</form>
)
}
}
複製程式碼
非受控元件
- 如果不需要實時取值,優先使用非受控元件,容易配合第三方庫使用
- 通過createRef方法或者ref屬性可以拿到元件的值(推薦使用createRef方法)
class CustomElement extends React.Component {
password = React.createRef();
handleSubmit = (e) => {
e.preventDefault();
console.log(this.username.value);
console.log(this.password.current.value);
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input type="text" name="username" ref={(dom) => {this.username = dom}} />
<input type="text" name="password" ref={this.password} />
<button>submit</button>
</form>
)
}
}
複製程式碼
元件間資料傳輸共享
我們寫一個小栗子,建立三個元件,在三個元件中傳輸資料。
使用creat-react-app腳手架初始化一個專案,刪掉src資料夾中的所有檔案,建立下面的檔案結構,如圖:
我們要實現的需求:
- Display元件顯示點贊數
- Like元件點選增加點贊數
效果如圖(這圖有BUG,大家假裝看到的是每次資料改變按鈕都是有點選的):
- 通過父元件共享資料
把共享資料放在父元件中,實現了兄弟元件的資料共享;
// index.jsx
import React from 'react';
import reactDOM from 'react-dom';
import Like from './Like';
import Display from './Display';
class CustomElement extends React.Component {
state = {
countNum: 0
}
increament = () => {
this.setState({
countNum: this.state.countNum + 1
})
}
render() {
return (
<div>
<Like increament = {this.increament} />
<Display countNum = {this.state.countNum} />
</div>
)
}
}
reactDOM.render(<CustomElement/>, window.root);
複製程式碼
// Like.jsx
import React from 'react';
export default class like extends React.Component {
render() {
return (
<div>
<button onClick={this.props.increament}>點贊</button>
</div>
)
}
}
複製程式碼
// Display.jsx
import React from 'react';
export default class Count extends React.Component {
render() {
return (
<div>
點贊數總數: {this.props.countNum}
</div>
)
}
}
複製程式碼
- 通過react中的context API跨元件傳值
// index.jsx
import React from 'react';
import reactDOM from 'react-dom';
import { Provider } from './Context';
import Like from './Like';
import Display from './Display';
class CustomElement extends React.Component {
state = {
countNum: 0
}
increament = () => {
this.setState({
countNum: this.state.countNum + 1
})
}
render() {
return (
<Provider value={{ countNum: this.state.countNum, increament: this.increament }}>
<div>
<Like />
<Display />
</div>
</Provider>
)
}
}
reactDOM.render(<CustomElement/>, window.root);
複製程式碼
// like.jsx
import React from 'react';
import { Consumer } from './Context';
export default class like extends React.Component {
render() {
return (
<Consumer >
{
({increament}) => (
<div>
<button onClick={increament}>點贊</button>
<button>取消</button>
</div>
)
}
</Consumer>
)
}
}
複製程式碼
// Display.jsx
import React from 'react';
import { Consumer } from './Context';
export default class Count extends React.Component {
render() {
return (
<Consumer>
{
({ countNum }) => (
<div>
點贊數總數: {countNum}
</div>
)
}
</Consumer>
)
}
}
複製程式碼
// Context.js
import React from 'react';
const { Provider, Consumer } = React.createContext();
export { Provider, Consumer }
複製程式碼
元件傳值tips:
- 父傳子可以靠props屬性
- 平級可以靠共同的父元件
- 跨級可以靠context api
- 通過react-redux在元件中傳值
這是個有很長故事的庫,大家可以看一下官方文件,這裡我就不詳述了:
最後balalala
個人平時使用vue,花了幾天時間學習了一下react。覺得react和vue都是很優秀的框架,我都喜歡。但是為什麼我要取這個標題呢?因為我就是傳說中的標題黨啊:)