起步
react 特點
- 不使用模板
- 不是一個mvc框架
- 響應式
- 輕量級的js庫
原理
- 虛擬dom 將dom抽象成js對象
- diff算法
搭建開發環境
react.js 核心文件
react-dom.js 面向web端 渲染頁面的dom 依賴於react核心文件
react-native 面向移動端app
babel.js 將es6 轉換成es5 jsx轉化成javascript
腳手架
npm install -g create-react-app
create-react-app -version 查看版本
create-react-app [projectName] //構建項目
npm start //啓動
jsx語法
- js+xml的組合
ReactDOM.render(<h1> hello world </h1>, document.getElementById("root"));
// document.getElementById("root")獲取插入的容器
// jsx語法 <h1>hello world</h1> 遇到 <> 按照xml語法解析,遇到{} 按照js 語法解析
元素的渲染
function tick() {
const element = ( //括號--->需要顯示多行標籤時使用括號
<div>
<h1>Hello, world!</h1>
<h2>It is {new Date().toLocaleTimeString()}.</h2>
</div>
);
ReactDOM.render(element, document.getElementById('root'));
}
setInterval(tick, 1000);
組件
//新建文件封裝
import React from "react";
class App extends React.Component {
render() {
return ( //多行標籤用()
<div>
<h1> Hello, world!!!!!!! </h1>
<h2> It is {new Date().toLocaleTimeString()}. </h2>
</div>
);
}
}
export default App;
import App from './App'
ReactDOM.render(<App />, document.getElementById("root"));
props
//父組件中傳入 des字段
ReactDOM.render(<App des="這是react框架" />, document.getElementById("root"));
//子組件中通過 this.props[字段名]獲取數據
class App extends React.Component {
render() {
return (
<div>
<h1> Hello, world!!!!!!! {this.props.des}</h1>
<h2> It is {new Date().toLocaleTimeString()}. </h2>
</div>
);
}
}
state
constructor(props) {
super(props);
this.state = { //構造函數中定義state
count: 10,
};
}
render() {
return (
<div>
<h1> Hello, world!!!!!!! {this.props.des}</h1>
<h2> It is {this.state.count}. </h2> //使用state中的變量
</div>
);
}
生命週期
-
componentWillMount:在組件渲染之前使用(beforeMount) conponentDidMount:渲染完成(mounted) componentUnMount:銷燬組件 (beforeDestory)清除定時器等
import React from "react";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 10,
};
}
componentWillMount() {
console.log("componentWillMount");
}
componentDidMount() {
console.log("componentDidMount");
}
componentWillUnmount() {
console.log("componentWillUnmount");
}
shouldComponentUpdate() {
return true;
}
componentWillUpdate() {
console.log("componentWillUpdate");
}
componentDidUpdate() {
console.log("componentDidUpdate");
}
// componentWillReceiveProps() {
// console.log("componentWillReceiveProps");
// }
addCount = () => {
console.log(this.state)
//this.state.count += 1;
this.setState({
count: (this.state.count += 1),
});
};
render() {
return (
<div>
<h1> Hello, world!!!!!!! {this.props.des}</h1>
<h2> It is {this.state.count}. </h2>
<button onClick={this.addCount}>增加</button>
</div>
);
}
}
export default App;
-
由上圖可知:
-
單純渲染組件時 componentWillMount--->componentDidMount
-
改變state時:shouldComponentUpdate(返回true允許改變,否則不繼續運行)---> componentWillUpdate--->componentDidUpdate
-
由於props是單向傳遞,當父組件改變props時,觸發子組件componentWillReceiveProps函數,
componentWillReceiveProps-->shouldComponentUpdate(返回true允許改變,否則不繼續運行)---> componentWillUpdate--->componentDidUpdate
-
-
注:this.state.count += 1;這種直接改變state不會去刷新組件,自然也不會觸發生命週期函數,使用setState函數改變state纔會重新渲染組件
數據的子傳父與父傳子
父傳子
//父組件
import App from "./App.jsx";
ReactDOM.render(<App des="這是react框架" />, document.getElementById("root")); //組件中自定義屬性
//子組件
//構造器
constructor(props) {
super(props); //super接受props對象
this.state = {
count: 10,
};
}
//
render() {
return (
<div>
<h1> Hello, world!!!!!!! {this.props.des}</h1> 通過this.props調用對應的屬性
<h2> It is {this.state.count}. </h2>
<button onClick={this.addCount}>增加</button>
</div>
);
}
子傳父
- (利用事件的回傳,類似vue中的$emit自定義事件)
//父組件中
//構造器中定義變量
constructor() {
super();
this.state={
title:'123'
}
}
//定義所要觸發的事件
changeCount = (data) => {
this.setState({
title: data,
});
};
//組件中傳遞props
<Mycomponent title={this.state.title} clickChange={this.changeCount}></Mycomponent>
子組件可以看到父組件傳遞的props:
//子組件中
//定義事件
addCount = () => {
this.props.clickChange('子組件傳遞來的參數');//形參傳遞給父組件,父組件接收後改變state,然後回傳給子組件,子組件重新渲染
};
//渲染
render() {
return (
<div>
<h1> Hello, world!!!!!!! {this.props.title}</h1>
<button onClick={this.addCount}>增加</button> //傳入子組件中定義的事件,然後再觸發該事件裏面父組件自定義的clickChange事件
</div>
);
}
條件渲染
//構造器state中定義isLogin變量
this.state = {
count: 10,
isLogin: false,
};
//渲染的時候
changeLogin = () => {
this.setState({
isLogin: true,
});
};
render() {
const { isLogin } = this.state;
let login = isLogin ? <div>已登陸</div> : <div>未登陸</div>;
return (
<div>
{login} //
<button onClick={this.changeLogin}>改變登陸狀態</button>
</div>
);
}
列表渲染
//state中定義一個數組對象
userInfo: [
{
name: "張三",
age: 12,
},
{
name: "李四",
age: 13,
},
{
name: "王五",
age: 14,
},
],
//render中遍歷數組對象進行渲染
render() {
return (
<div>
<ul>
{this.state.userInfo.map((el,index) => {
return (
<li key={index}> //注意在最外層添加key,否則會產生警告
<span>{el.name}</span>
<span>{el.age}</span>
</li>
);
})}
</ul>
</div>
);
}
ref
//構造器中創建ref
constructor(props) {
super(props);
this.myRef = React.createRef();
}
//訪問ref 通過current屬性獲取dom對象
this.myRef.current.style.color="red"
受控組件與非受控組件
受控組件
//state動定義
this.state = {
value: "",
value2: "",
value3: "",
};
//改變時通過e.target獲取值
changeVaue = (e) => {
this.setState({
value: e.target.value,
});
};
changeVaue2 = (e) => {
this.setState({
value2: e.target.value,
});
};
changeVaue3 = (e) => {
this.setState({
value3: e.target.value,
});
};
//對input的值進行更新
<input
type="text"
value={this.state.value}
onChange={this.changeVaue}
/>
<input
type="text"
value={this.state.value2}
onChange={this.changeVaue2}
/>
<input
type="text"
value={this.state.value3}
onChange={this.changeVaue3}
/>
非受控組件
- 當表單的重複工作太多,數據變化的每種方式都編寫事件處理函數,比如上面受控組件的情況,這個時候用非受控組件可以很好的解決
//構造器中創建變量,和ref來操作dom
this.state = {
value1: "",
value2: "",
value3: "",
};
this.myValue1 = React.createRef();
this.myValue2 = React.createRef();
this.myValue3 = React.createRef();
//將值與ref節點一一對應
<input type="text" ref={this.myValue1} />
<input type="text" ref={this.myValue2} />
<input type="text" ref={this.myValue3} />
//提交時獲取state的值
this.myValue1.current.value //
狀態提升
- 通過一個父組件來管理多個子組件中的數據
//父組件
import React from "react";
import MyComponent from "./component";
import MyForm from "./form";
import Child1 from "./component/child1";
import Child2 from "./component/child2";
class App extends React.Component {
constructor() {
super();
this.state = {
money: 8,
};
}
handleChange = (e) => {
this.setState({
money: e.target.value,
});
};
render() {
return (
<div>
<input type="text" value={this.state.money} onChange={this.handleChange} />
¥:<Child1 money={this.state.money}></Child1>
$:<Child2 money={this.state.money}></Child2>
</div>
);
}
}
export default App;
//自組件
import React from "react";
export default class Child1 extends React.Component {
constructor() {
super();
}
render() {
return (
<p>{this.props.money }</p>
);
}
}
組件的組合
- 類似vue的slot插槽
//父組件
<Child1 money={this.state.money}>
<span>組件的組合</span>
</Child1>
//子組件 通過this.props.children調用
<p>
{this.props.children}
</p>