React
React 是一個用于構建用戶頁面的JavaScript庫妻坝,專注于視圖,實現(xiàn)組件化開發(fā)。
組件化概念
將一個復雜的頁面分成若干個獨立的組件叔扼,每個組件都包含自己的邏輯和樣式,在將這些組件組合成一個完整的頁面漫雷。這樣的操作即減少了邏輯復雜度又實現(xiàn)了代碼的重用瓜富。
React
React是基于class(類)
react 包是核心
react-dom 包是 dom 渲染
jsx語法
JavaScript + xml 都結合體,可以理解為 html + js
jsx-transform 可以把jsx語法轉為js語法
生成一個react項目構架
create-react-app
create-react-app官方的一個生成react項目,安裝時后面跟一個項目名稱
需要在一個空的文件夾下安裝
create-react-app 安裝的時候會自動幫我們下載react(需要的react)降盹,react-dom(主要是渲染)与柑,react-script(可以認為繼承了webpack的腳手架)
加-g是全局安裝
npm install create-react-app myApp
//mac 安裝需要加 sudo
sudo npm install create-react-app myApp
1
2
3
4
啟動服務
npm start 開啟本地服務
npm build 打包
npm test jest進行單元測試
npm eject 可以把webpack命令打包出來,方便我們修改webpack文件,但此操作不能回退
React的例子
import React from "react";
import {render}? from "react-dom";
let name = "哈哈";
let ele =(
<>
<h1>你好{name}</h1>
<div>嘻嘻</div>
</>
)
render(ele,window.root);
React的注意事項
一般采用import的方式引入React价捧,React首字母規(guī)定大些丑念,因為jsx會默認使用大寫的React
會根據(jù)尖括號(<)來判斷是一個html,根據(jù)花括號({)來判斷是一個js
js中的保留字 關鍵字會進行轉化 class=>className for=>htmlFor
react相鄰的jsx元素结蟋,react元素脯倚,必須被一個標簽包裹 <></>
style標簽 必須是一個對象 style={{}} //{}表示js里面的{}表示是一個對象
注釋 要用{}包裹
dangerouslySetInnerHTML 危險的,解析html用innerHtml的方式把內容塞進元素中
<div dangerouslySetInnerHTML={{_html:"<span>你好</span>"}}></div>
可以在頁面中使用三元運算
事件方法 之前的οnclick=> onClick …
babel會把jsx語法進行轉化的
<h1 a=1>你好</h1> =>React.createElement('h1',{a:1}沒有屬性null,子元素)
模擬的React 和 render
react渲染的流程
react會把jsx語法渲染成React.createElement()格式
React.createElement() 會轉為 vnode(虛擬節(jié)點)
vnode 渲染到頁面上
let React = {
createElement(type,props,...children){//可以組成一個對象嵌屎,用來描述dom元素
return {type,props,children}推正;//虛擬dom
}
}
let ele = <h1>哈哈</h1>;
console.log(ele);//返回一個對象
let render=(obj,container)=>{
if(typeof obj === "string") return container.appenChild(document.createTextNode(obj));
let {type,props,children} = obj;
let ele = document.createElement(type);
for(let key in props){
ele.setAtteributte(key,props[key])
}
children.forEach(item=>{
render(item,ele);//遞歸,渲染子節(jié)點
})
children.appendChild(ele);
}
React數(shù)組迭代的時候應該給每一項都加上一個屬性key
key 就是用來表示身份的
React如果想渲染對象需要轉化為字符串格式
import React from "react";
import ReactDOM from "react-dom";
ReactDOM.render(<div>{JSON.stringify({a:1})}</div>,window.root);
render
是優(yōu)化過的宝惰,會把元素進行比對植榕,把有變化的存儲起來,更新有變化的內容
React組件
組件的優(yōu)點
方便復用
方便維護
方便重構
組件的定義可分為2種
函數(shù)聲明組件
類聲明組件
函數(shù)組件
函數(shù)就是組件
組件名稱規(guī)定首字母大寫,小寫認為是一個標簽元素
組件在元素中應用<組件名/> or <組件名></組件名>
組件傳遞的屬性或方法(<組件名 title={“222”}>)會把傳入的屬性包成一個對象({title:“222”})傳給這個組件函數(shù)props,在組件內取值時就是掌测,{props.title}
函數(shù)組件會在內部添加一個render方法内贮,把函數(shù)的返回結果作為render方法的返回結果
函數(shù)組件的不足
沒有狀態(tài) 新版本有增加
沒有生命周期的鉤子 新版本有增加
函數(shù)組件中沒有this
類組件
類組件在渲染時會默認調用render方法
import React from "react";
import ReactDOM from "react-dom";
class Clcok extends React.Component{
render(){
return <h1>哈哈</h1>
}
}
類組件內有狀態(tài)和鉤子函數(shù)
需要繼承React.Component
React.Component 是一個基類,有生命周期汞斧,更改狀態(tài)的方法
繼承React.Component 之后才算是一個React類夜郁。
import React from "react";
import ReactDOM from "react-dom";
class Clcok extends React.Component{
constructor(props){//會接受組件傳入的屬性or方法
super(props);
//this.state 是規(guī)定死的,表示給這個組件生命狀態(tài)
this.state={ }
}
//es7語法 簡單粗暴 和上面的一樣
// state={}
render(){
return <h1>哈哈</h1>
}
}
React 的數(shù)據(jù)源(props(外部傳入粘勒,不可修改) ,state(內部自帶竞端,可修改))
props 會把組件傳入的屬性or方法放在this上 ---- 取值時:this.props.name1
this.state 狀態(tài) ---- 取值時:this.state.name1
this.setState
是父類提供的,用于修改狀態(tài),這種更新狀態(tài)的方式庙睡,不會覆蓋之前的事富,只會進行比較把更新的狀態(tài)進行合并
this.setState 會刷新頁面,如果不用this.setState乘陪。直接修改state 會改狀態(tài)還是頁面不會刷新
需要改屬性的話只能把屬性(props)變?yōu)闋顟B(tài)(state)
this.setState 可以執(zhí)行多次么统台? 面試題
React 生命周期(鉤子函數(shù))
componentDidMount(){} 當前組件掛在完成,在render方法加載完之后執(zhí)行
unmountComponentAtNode() 卸載組件
//用法
ReactDOM.unmountComponentAtNode(window.root)
componentWillUnmount(){} 將要卸載,在此階段中刪掉所有的監(jiān)聽和卸載異步方法
componentDidMount(){
this.itemer = setInterval=()=>{
//this.setState 可以導致頁面刷新
this.setState({time:new Date().toLocalString()})
}
}
componetWillUnmount(){
clearInterval(this.timer);
}
React Event 中的this問題
this問題
通常在元素中給事件綁定一個函數(shù) (onClick = this.btnclick) this是undefined的
在es6 類中啡邑,如果把原型上的方法拿出來贱勃,這是一個錯誤的操作,this是undefined
btnclick(){}
1
如果解決this指向問題
在元素中綁定時加入bind(onClick = this.btnclick.bind(this)) 每次點擊都產生一個新的函數(shù)
在constructor中設置一下谤逼,然后在元素中用(οnclick={this.btnclick}) 官網推薦
consttuctor(){
super();
this.btnclick = this.btnclick.bind(this); //這樣每次點擊的時候都是用的一個函數(shù)贵扰。
}
采用箭頭函數(shù)可以完美解決,只要是在原型中的方法采用箭頭函數(shù)就可以
在元素中直接用(οnclick=this.btnclick) es7方式
btnclick=()=>{} //這里采用箭頭函數(shù)方式
1
prop-types
React 內置了類型檢測的功能流部,在組件中檢測戚绕,可以賦值propTypes屬性
格式校驗
需下載
propTypes 屬性
.array 數(shù)組
.bool 布爾值
.func 函數(shù)
.number 數(shù)字
.object 對象
.string 字符串
.symbol 符號
.node 任何東西都可以被渲染:numbers, strings, elements,或者是包含這些類型的數(shù)組(或者是片段)。
.element React元素
.instanceOf(Message) 類的一個實例
.oneOf([‘News’, ‘Photos’]) 枚舉值
.oneOfType([PropTypes.string,PropTypes.number,PropTypes.instanceOf(Message)]) 多種類型其中之一
.arrayOf(PropTypes.number) 某種類型的數(shù)組
.objectOf(PropTypes.number) 某種類型的對象
.shape({color: PropTypes.string,fontSize: PropTypes.number}) 特定形式的對象
.func.isRequired 可以使用 `isRequired’ 鏈接上述任何一個枝冀,以確保在沒有提供 prop 的情況下顯示警告
.any.isRequired 任何數(shù)據(jù)類型的值
function(props, propName, componentName) { return new Error()} 自定義的驗證器
.arrayOf(function(propValue, key, componentName, location, propFullName) {}
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
class Person extends React.Component{
? static defaultProps = {
? ? name:'Stranger'
? }
? ? static propTypes={
? ? ? ? name: PropTypes.string.isRequired,
? ? ? ? age: PropTypes.number.isRequired,
? ? ? ? gender: PropTypes.oneOf(['male','famale']),
? ? ? ? hobby: PropTypes.array,
? ? ? ? postion: PropTypes.shape({
? ? ? ? ? ? x: PropTypes.number,
? ? ? ? ? ? y:PropTypes.number
? ? ? ? }),
? ? ? ? age(props,propName,componentName) {
? ? ? ? ? ? let age=props[propName];
? ? ? ? ? ? if (age <0 || age>120) {
? ? ? ? ? ? ? ? return new Error(`Invalid Prop ${propName} supplied to ${componentName}`)
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? render() {
? ? ? ? let {name,age,gender,hobby,position}=this.props;
? ? ? ? return (
? ? ? ? ? ? <table>
? ? ? ? ? ? ? ? <thead>
? ? ? ? ? ? ? ? <tr>
? ? ? ? ? ? ? ? ? ? <td>姓名</td>
? ? ? ? ? ? ? ? ? ? <td>年齡</td>
? ? ? ? ? ? ? ? ? ? <td>性別</td>
? ? ? ? ? ? ? ? ? ? <td>愛好</td>
? ? ? ? ? ? ? ? ? ? <td>位置</td>
? ? ? ? ? ? ? ? </tr>
? ? ? ? ? ? ? ? </thead>
? ? ? ? ? ? ? ? <tbody>
? ? ? ? ? ? ? ? <tr>
? ? ? ? ? ? ? ? ? ? <td>{name}</td>
? ? ? ? ? ? ? ? ? ? <td>{age}</td>
? ? ? ? ? ? ? ? ? ? <td>{gender}</td>
? ? ? ? ? ? ? ? ? ? <td>{hobby.join(',')}</td>
? ? ? ? ? ? ? ? ? ? <td>{position.x+' '+position.y}</td>
? ? ? ? ? ? ? ? </tr>
? ? ? ? ? ? ? ? </tbody>
? ? ? ? ? ? </table>
? ? ? ? )
? ? }
}
let person={
? ? age: 100,
? ? gender:'male',
? ? hobby: ['basketball','football'],
? ? position: {x: 10,y: 10},
}
ReactDOM.render(<Person {...person}/>, document.getElementById('root'));
受控與非受控組件
在表單中有受(狀態(tài))控組件和非受控組件
受控組件就是需要添加 onChange
受控好處:- 可以給輸入框賦予默認值 - 實時校驗
受控壞處:- 每次輸入都會調用setState
非受控
非受控好處:- 簡單舞丛,也不寫狀態(tài)
非受控壞處:- 不能實時校驗
ref 相當于別名
ref設值or取值
import React,{Component} from "react";
import ReactDOM from "react-dom";
class Control extends Component{
password = React.createRef();//新版本 16.3采用的
handleClick=()=>{
//取值
console.log(this.username.value);//
console.log(this.refs.aaa)// 廢棄的
//this.password.current 才是真實的dom
console.log(this.password.current.value);
}
render(){
return <div>
<input type="text" name="username" ref={(dom)=>{this.username = dom}} />
<input type="text" name="password" ref="aaa" />
<input type="text" name="username" ref={this.password}/>? //新版本
</div>
}
}
React 是單向數(shù)據(jù)流
方法1
Q:子輩不能修改父的值耘子,那如果修改呢?
A:通過由父輩傳遞給子輩一個函數(shù)瓷马,函數(shù)回調里放的就是修改的功能拴还,當子輩執(zhí)行這個函數(shù)的時候就會觸發(fā)父輩的回調就可以更改這個值在傳入下去。
方法2
context Api React提供的欧聘,定義一些數(shù)據(jù)片林,由子孫直接消費,不必一層層下傳