寫這篇文章初衷是整理一下本身這兩個多月的心路歷程,從剛開始 「入坑」
react
時的一臉懵,不知如何下手,到如今能夠寫簡單的業務。之因此定義名字爲「爬坑記錄」,並非由於中介跌入不少坑,而是在講述本身從徹底不瞭解這個框架 ,而後又一步步上道兒,我這裏就稱之爲「爬坑」,哈哈。因此想把本身的學習過程以及爬坑記錄下來,給本身往後翻閱,若有也在寫react
,想交流的小夥伴,文末有微信哦,哈哈。其實從很早就想研究下react
了,只是時間上的不容許,如今終於能夠騰出時間來(其實平時工做較飽和,也只能擠業餘時間了)。html
------文中的示例都是本身通過實踐的,如理解有誤,還請告知哦!😂------vue
部分純
react
組件示例,部分來自umi
腳手架配合dva
的項目組件示例,ui
組件是ant-design
,模版使用的是antdesign的pro-layout
現成的模版。react
具體版本號以下:ios
"@ant-design/pro-layout": "4.7.0",
"@antv/g2": "^3.5.11",
"antd": "^3.25.2",
"array-move": "^2.2.0",
"umi": "2.12.3",
"umi-plugin-react": "1.14.7",
"uuid": "^3.3.3",
"axios": "^0.19.0",
"bizcharts": "^3.5.6",
"classnames": "^2.2.6",
"copy-to-clipboard": "^3.2.0",
"dayjs": "^1.8.17",
"immutable": "^4.0.0-rc.12",
"lodash": "^4.17.15",
"moment": "^2.24.0",
"mz-modules": "^2.1.0",
"parameter": "^3.6.0",
"prop-types": "^15.7.2",
"qrcode": "^1.4.4",
"qs": "^6.9.1",
"rc-form-hooks": "^0.0.1-alpha.22",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"swr": "^0.1.12",
複製代碼
react
的生命週期如同
vue
同樣,react
也是有本身的生命週期,方便咱們根據加載順序來執行相應的操做。json
經常使用的生命週期以下:axios
在渲染前調用:
componentWillMount
數組在第一次渲染後調用:
componentDidMount
bash在組件完成更新前調用:
componentWillUpdate
微信在組件完成更新後當即調用:
componentDidUpdate
babel在組件接收到一個新的 prop (更新後)時被調用:
componentWillReceiveProps
在組件從 DOM 中移除以前馬上被調用:
componentWillUnmount
加載渲染過程:
父 bcomponentWillMount => 父 render => 子 componentWillMount =>子 render => 子 componentDidMount => 父componentDidMount
複製代碼
子組件經過props取值並更新過程:
子 componentWillUpdate => 父 render => 子 componentWillReceiveProps => 父 componentWillUpdate => 子 render => 子 componentDidUpdate => 父 componentDidUpdate
複製代碼
單一父 / 子組件(不依賴props)更新過程:
componentWillUpdate => render => componentDidUpdate
複製代碼
銷燬過程:
componentWillUnmount
複製代碼
let root = document.getElementById('example');
/*
* 相似vue的template ,第一個參數是插入的模版,第二個是插入的跟元素
* 在react中樣式中的 class 要重命名爲 className
* render 是必不可少的,用來渲染到頁面上
*/
ReactDOM.render(
<h1 className="box">Hello, world!</h1>,
root
);
複製代碼
效果展現:
在react中定義變量是很方便的,能夠定義數組,數組中能夠包含咱們的
html
標籤,而後能夠將變量直接帶入到頁面上。
<body>
<div id="example"></div>
<script type="text/babel">
let root = document.getElementById('example')
let arr = [
<h1 >Hello world!</h1>,
<h2 >Hello React!</h2>,
];
// 注意,react 的變量使用的是單花括號 {}
ReactDOM.render(
<div>{arr}</div>,
root
);
</script>
複製代碼
效果展現:
在React裏組件都是用class來寫的,React來寫組件無疑是很爽的,下面咱們就來試試。
<body>
<div id="example"></div>
<script type="text/babel">
let root = document.getElementById('example');
// class 的名字必須大寫,並繼承自 React.Component
class HelloMessage extends React.Component {
constructor(...args){
super(...args);
this.name=this.props.name
this.job=this.props.job
this.age = this.props.age
}
fn(){
return "Aaa"
}
render() {
// 變量還能夠直接定義標籤,style後面需跟一個{},而裏面的內容須要是一個json,因此此處看起來是兩個{{}}
let div =<div style={{color:'red'}}>我是div</div>
return (
<div>
// 花括號中的值還能夠參與計算
姓名: {this.name}<br/>
工做: {this.job}<br/>
年齡: {this.age+3}<br/>
// 花括號不只能夠輸出變量,還能夠輸出方法
{this.fn()} <br/>
// 將標籤輸出到頁面
{div}
</div>
);
}
}
ReactDOM.render(
<HelloMessage name="John" job="teacher" age="18"/>,
root
);
</script>
</body>
複製代碼
JSX語法容許咱們html 和 js 穿插來寫,咱們來看看最經常使用的循環怎麼寫。
在普通(非class)組件中添加循環:
<body>
<div id="example"></div>
<script type="text/babel">
let root = document.getElementById('example')
let names = ['Alice', 'Emily', 'Kate'];
ReactDOM.render(
<div>
{
names.map(function (name, index) {
// 循環中須要添加key值,用來保證惟一性
return <div key={index}>Hello, {name}!</div>
})
}
</div>,
root
);
</script>
</body>
複製代碼
效果展現:
在class 裏面寫循環:
<body>
<div id="example"></div>
<script type="text/babel">
let root = document.getElementById('example');
class HelloMessage extends React.Component {
constructor(...args){
super(...args)
}
render() {
let arr =[];
for(let i =0;i<5;i++){
// 注意:這裏須要給每一個li 添加一個key
arr.push(<li key={i}>{i}</li>)
}
return (
<div>
<ul>{arr}</ul>
</div>
);
}
}
ReactDOM.render(
<div>
<HelloMessage />
</div>,
root
);
</script>
</body>
複製代碼
效果展現:
咱們日常的開發中,有時候須要用到些公共組件,那咱們就應對其進行封裝提取出來,如下是粗略版的父子組件嵌套寫法
<body>
<div id="example"></div>
<script type="text/babel">
// 父組件
class Parent extends React.Component{
constructor(...args){
super(...args)
}
render(){
return(
<ul>
// 將寫好的子組件嵌套進來便可
<Child/>
<Child/>
<Child/>
<Child/>
</ul>
)
}
}
// 子組件
class Child extends React.Component{
constructor(...args){
super(...args)
}
render(){
return(
<li>111</li>
)
}
}
ReactDOM.render(
<Parent />
,
document.getElementById('example')
);
</script>
</body>
複製代碼
通常狀況下,render 裏面只會有一個最大的標籤包含,若是你有兩個標籤,請在外面添加一個包裹標籤,正確寫法:
ReactDOM.render(
<div>
<Parent></Parent>
<Child></Child>
</div>,
document.getElementById('example')
);
複製代碼
錯誤寫法:
ReactDOM.render(
<Child></Child>
<Parent></Parent>
,
document.getElementById('example')
);
複製代碼
在腳手架中還可用
react
中的Fragment
去充當咱們最外層的包裹層,它的好處是不會多生成一個div
import { Component, Fragment } from 'react'
class ConfigContent extends Component {
constructor(...args){
super(...args)
}
render(){
return(
<Fragment>
<Parent></Parent>
<Child></Child>
</Fragment>
)
}
}
export default ConfigContent
複製代碼
組件能夠寫成單標籤或者雙標籤兩種形式。以下:
// 雙標籤
<Parent></Parent>
// 單標籤
<Parent/>
複製代碼
props
父組件給子組件傳遞參數,子組件接收,並渲染子組件: 父組件=>子組件
父組件
import { PureComponent } from "react";
import Child from "./child";
class Parent extends PureComponent {
constructor(props) {
super(props);
this.state = { id: 1 };
}
render() {
return (
<Child id={this.state.id} />
);
}
}
export default Parent;
複製代碼
子組件:
import { PureComponent } from "react";
class Child extends PureComponent {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h1>child-page</h1>
<p>{this.props.id}</p>
</div>
);
}
}
export default Child;
複製代碼
效果展現:
子組件經過事件將子組件的值傳到父組件: 子組件=>父組件
子組件:
import { Button } from "antd";
import { PureComponent } from "react";
class Child extends PureComponent {
constructor(props) {
super(props);
this.state = { a: 1 };
}
action = {
handleChange: () => {
this.props.changeEvent(`子組件定義的值:${this.state.a}`);
}
};
render() {
return (
<div>
<h1>child-page</h1>
<Button type="primary" onClick={this.action.handleChange}>
改變父組件
</Button>
</div>
);
}
}
export default Child;
複製代碼
父組件:
import { PureComponent } from "react";
import { Button } from "antd";
import Child from "./child";
class Parent extends PureComponent {
constructor(props) {
super(props);
}
action = {
changeEvent: mode => {
console.log("父組件收到的值:", mode);
}
};
render() {
return (
<div>
<Child changeEvent={mode => this.action.changeEvent(mode)} />
</div>
);
}
}
export default Parent;
複製代碼
點擊後的效果展現:
事件是咱們在交互過程當中必不可少的,那麼咱們試試看,
在react
中如何添加事件。
(1)咱們原生的添加事件的方式,採用的是小寫onclick
:
<button onclick="activateLasers()">
Activate Lasers
</button>
複製代碼
(2)react的添加事件,採用駝峯的方式定義onClick
:
<button onClick={activateLasers}>
Activate Lasers
</button>
複製代碼
下面介紹幾種在項目中添加事件的方式,你們可根據狀況選擇:
<body>
<div id="example"></div>
<script type="text/babel">
class Child extends React.Component {
constructor(...args){
super(...args)
this.a=[123]
}
// 直接在標籤上添加
render() {
return (
<div onClick={function(){
console.log("eee")
}}>{this.a}</div>
)
}
}
ReactDOM.render(
<Child/>,
document.getElementById('example')
)
</script>
</body>
複製代碼
class
組件中添加方法(須要從新綁定this):<body>
<div id="example"></div>
<script type="text/babel">
class Cmp1 extends React.Component{
constructor(...args){
super(...args)
}
fn(){
// props只讀的,這裏的值是不可改的,是從外面傳進來的
console.log(this.props.a) // 0
}
// onClick 相似原生事件,此處bind就是把咱們的fn的this緊緊綁在組件上,此時的內部也能拿到咱們組件的this
render(){
return(
<div>
{this.props.a}
<input type="button" value="+1" onClick={this.fn.bind(this)}/>
</div>
)
}
}
ReactDOM.render(
<div>
<Cmp1 a={0}/>
</div>,
document.getElementById('example')
);
</script>
</body>
複製代碼
<body>
<div id="example"></div>
<script type="text/babel">
class Child extends React.Component {
constructor(...args){
super(...args)
this.a=[123]
}
// 定義變量
action ={
fn(){
console.log(23)
}
}
// 在這裏直接調用,就不用綁定this了
render() {
return (
<div onClick={this.action.fn}>{this.a}</div>
)
}
}
ReactDOM.render(
<Child/>,
document.getElementById('example')
)
</script>
</body>
複製代碼
<body>
<div id="example"></div>
<script type="text/babel">
class Child extends React.Component {
constructor(...args){
super(...args)
this.a=[123]
}
fn=()=>{
console.log(23)
}
render() {
return (
<div onClick={this.fn}>{this.a}</div>
)
}
}
ReactDOM.render(
<Child/>,
document.getElementById('example')
)
</script>
</body>
複製代碼
備註一下,關於事件傳參的寫法:
import { PureComponent } from "react";
import { Button } from "antd";
class App extends PureComponent {
constructor(props) {
super(props);
this.state = { arr: [1, 2, 3, 4] };
}
action = {
handleClick: i => {
console.log(i.target.innerHTML);
}
};
render() {
return (
<div>
{this.state.arr.map((item, index) => {
return (
<Button
key={index}
onClick={index => this.action.handleClick(index)}
>
{item}
</Button>
);
})}
</div>
);
}
}
export default App;
複製代碼
效果展現:
state
製做一個 input ++ 功能
state
構造函數是惟一可以初始化this.state
的地方,接收一個對象,是可變的,能夠是內部加的,也能夠從外部傳進來,this.setSate
是惟一改變state
的方式。
// 製做一個input ++ 功能
<body>
<div id="example"></div>
<script type="text/babel">
class Cmp1 extends React.Component{
constructor(...args){
super(...args)
this.state={a:0}
}
fn(){
// this.setSate是惟一改變state的方式
this.setState({a:this.state.a+1})
}
render(){
return(
<div>
{this.state.a}
<input type="button" value="+1" onClick={this.fn.bind(this)}/>
</div>
)
}
}
ReactDOM.render(
<div>
<Cmp1/>
</div>,
document.getElementById('example')
);
</script>
</body>
複製代碼
頁面效果:
咱們在跳轉路由時,有時須要給跳轉到到頁面攜帶一些參數來定位頁面的顯示或回顯數據,此小節咱們就來看看如何傳參,以及入股取參。
首先咱們先拿一下props,看看都有哪些參數:
console.log(this.props);
複製代碼
參數以下:
咱們來具體解析一下:
history:包含了路由push replace goBack 等方法,以及可拿到query state 等參數
history:{
location:{
pathname:'/dashboard/workplace', // url地址
search:'?name='xiaoxiao', // 拿到的是完整的參數字符串 hash:'', query:{name:'xiaoxiao'}, // 拿到參數的對象格式 state:undefined // 拿到經過state傳入的參數 }, push:function push(path,state){} , // 跳轉到指定路徑 replace:function replace(path,state){} , // 跳轉到指定路徑,不會保留history goBack:function goBack(path,state){} , // 返回上一個路由地址 } 複製代碼
這個location 同上面的location,可拿到query參數 以及state 參數
location:{
pathname:'/dashboard/workplace',
search:'?name='xiaoxiao', query:{name:'xiaoxiao'}, state:undefined } 複製代碼
包含了具體的 url 信息,並能夠拿到params的參數的值。
match:{
path:'/dashboard/workplace',
url:'/dashboard/workplace',
params:{}
}
複製代碼
接下來咱們就使用:this.props.history.push
來模擬跳轉,並攜帶參數:
經過
url
來進行傳參,地址欄是可見的
⚠️注意️:刷新頁面後,參數不會丟失,可傳對象
A 頁面:
this.props.history.push({
pathname: "/dashboard/workplace",
query: { name: "xiaoqiu" }
});
複製代碼
B頁面 (參數在url
裏問號後顯示)
http://localhost:8000/#/dashboard/workplace?name=xiaoqiu
複製代碼
打印一下咱們接收到的參數:
state傳參,同query差很少,只是屬性不同,並且state傳的參數是加密的,不會在地址欄顯示
注意️:刷新頁面後,參數就會丟失,可傳對象
A頁面:
this.props.history.push({
pathname: "/dashboard/workplace",
state: { name: "xiaoqiu" }
});
複製代碼
B頁面: (參數並無出如今地址欄哦!)
http://localhost:8000/#/dashboard/workplace
複製代碼
打印一下咱們接收到的參數:
search
同query
參數同樣是經過url
進行傳輸
⚠️注意️:刷新頁面後,參數不會丟失,但只可傳字符串,不能傳輸對象
A頁面:
this.props.history.push({
pathname: "/dashboard/workplace",
search: "a=1&b=2"
});
複製代碼
B頁面
http://localhost:8000/#/dashboard/workplace?a=1&b=2
複製代碼
打印一下咱們接收到的參數:
此時咱們注意到不管是經過
query
或是search
傳參,返回參數時二者也同時都能取到,只是展示方式不一樣。query
是以對象形式展示,search
是以字符串展示,若是你想在地址欄顯示,那就用query
,若是想加密傳輸,那就用state
,但要注意使用state
傳遞參數刷新後就會丟失哦!
ref
獲取組件實例經過給組件綁定ref 能夠獲取到整個子組件的實例,進而可傳參數並調用其方法
ref
,獲取當前組件的參數以及事件import { Button } from "antd";
import { PureComponent } from "react";
class Child extends PureComponent {
constructor(props) {
super(props);
this.state = { a: 1 };
}
action = {
handleChange: () => {
console.log(this.refs["button"]);
}
};
render() {
return (
<div>
<h1>child-page</h1>
<Button type="primary" onClick={this.action.handleChange} ref="button">
改變父組件按鈕
</Button>
</div>
);
}
}
export default Child;
複製代碼
控制檯打印ref
拿到的組件參數以及方法:
react
的createRef
,拿到子組件的參數和方法import { PureComponent, createRef } from "react";
import { Button } from "antd";
import Child from "./child";
class Parent extends PureComponent {
constructor(props) {
super(props);
this.children = createRef();
this.state = { id: 1, arr: [1, 2, 3, 4] };
}
action = {
handleClick: () => {
console.log(this.children);
}
};
render() {
return (
<div>
<Button onClick={() => this.action.handleClick()}>
按鈕
</Button>
子組件:
<Child ref={this.children} />
</div>
);
}
}
export default Parent;
複製代碼
控制檯輸出子組件的值:
寫到此處,並無結束哦!接下來我還會持續追加,看文章的小夥伴們能夠添加一下關注哦!
做者:Christine
出處:https://juejin.im/post/5a125827518825293b4fea8a
版權全部,歡迎保留原文連接進行轉載:)
複製代碼
若是你對我對文章感興趣或者有些建議想說給我聽👂,也能夠添加一下微信哦!
郵箱:christine_lxq@sina.com
若是親感受個人文章還不錯的話,能夠一下添加關注哦!最後:
祝各位工做順利!
-小菜鳥Christine
複製代碼