1、安裝
1、必須安裝nodejs穩定版本,exe直接安裝即可,安裝完既有npm;
2、安裝cnpm/yarn淘寶鏡像:
npm install -g cnpm --registry=https://registry.npm.taobao.org
cnpm install -g yarn
3、安裝vscode;
2、建立項目:
1、安裝腳手架:
cnpm install -g create-react-app
2、cd進入想要建立項目的目錄,建立項目:
create-react-app reactdemo
3、運作項目:
cnpm start /yarn start
4、生成項目:
cnpm run build / yarn build
3、目錄結構分析
1、node_modules:安裝子產品目錄
2、public:公共目錄,一般無需修改,裡面有index.html入口檔案;
3、重點關注src目錄!
3.1、index.js:react入口檔案,React是react核心庫,ReactDOM是提供與DOM相關的功能;
3.2、index.css:react項目公共css,可以删掉;
3.3、registerServiceWorker.js 加快react運作速度的js檔案;
3.3、App.js 組建
4、項目配置檔案:package.json
5、yarn.lock yarn臨時檔案,不用管;
預設生成的結構比較亂,可手動整理目錄結構:
1、建立components組建檔案夾,用于存放組建,組建名稱首字母大寫!
2、建立assets檔案夾,用于存放靜态檔案;
2.1、建立assets/image檔案夾,放圖檔;
2.2、建立assets/css檔案夾,放靜态檔案;
4、代碼編寫
1、引入組建,無需寫字尾名js:
import Home from './components/Home'
快速建構組建架構代碼:
1、在vscode應用商店中安裝插件 :
React-Native/React/Redux snippets for es6/es7
2、在vscode中輸入cccs,按enter即可;
2、資料定義,寫在構造函數裡面:
import React from 'react'
class Home extends React.Component{
constructor(props){
super(props); //固定寫法,用于父子組建傳值;
this.state={
name:"111",
age:'20'
}
}
render(){
return(
<div>
name:{this.state.name} //引用資料;
</div>
)
}
}
3、綁定css屬性用
class--->className
for---->htmlFor
style屬性和以前的寫法有些不一樣:
<div style={{'color':'blue'}}>{this.state.title}</div>
<div style={{'color':this.state.color}}>{this.state.title}</div>
4、引入圖檔,要用子產品化方式
法1:
import image1 from '../assets/image/1.jpg'
<img src={image1}/>
法2:
<img src = {require('../assets/image/1.jpg')}/>
引入遠端圖檔,直接src寫位址即可;
5、寫事件
run=()=> {
alert(this.state.name)
}
<button onClick={this.run}>按鈕</button>
事件傳值:
<button onClick={this.setName.bind(this,'張三')}>執行方法傳值</button>
setName=(str)=>{
this.setState({
username:str
})
}
6、事件對象
<button aid="123" onClick={this.run}>事件對象</button>
run=(event)=>{
event.target.style.background='red';
alert(event.target.getAttribute('aid'))//擷取dom的屬性
}
7、表單事件
法1:
{/* 擷取表單的值
1、監聽表單的改變事件 onChange
2、在改變的事件裡面擷取表單輸入的值 事件對象
3、把表單輸入的值指派給username this.setState({})
4、點選按鈕的時候擷取 state裡面的username this.state.username
*/}
<input onChange={this.inputChange}/>
<button onClick={this.getInput}>擷取input的值</button>
inputChange=(e)=>{
this.setState({
username:e.target.value
})
}
getInput=()=>{
alert(this.state.username);
}
法2:
{/* 擷取表單的值
1、監聽表單的改變事件 onChange
2、在改變的事件裡面擷取表單輸入的值 ref擷取
3、把表單輸入的值指派給username this.setState({})
4、點選按鈕的時候擷取 state裡面的username this.state.username
*/}
<input ref="username" onChange={this.inputChange}/>
<button onClick={this.getInput}>擷取input的值</button>
inputChange=()=>{
let val=this.refs.username.value;
this.setState({
username:val
})
}
getInput=()=>{
alert(this.state.username);
}
8、鍵盤事件
<input onKeyUp={this.inputKeyUp}/>
//鍵盤事件
inputKeyUp=(e)=>{
if(e.keyCode==13){
alert(e.target.value);
}
}
9、限制性和非限制性元件
限制性和非限制性元件:
非限制性元件:
<input type="text" defaultValue="a" /> 這個 defaultValue 其實就是原生DOM中的 value 屬性。
這樣寫出的來的元件,其value值就是使用者輸入的内容,React完全不管理輸入的過程。
限制性元件:
<input value={this.state.username} type="text" onChange={this.handleUsername} />
這裡,value屬性不再是一個寫死的值,他是 this.state.username, this.state.username 是由 this.handleChange 負責管理的。
這個時候實際上 input 的 value 根本不是使用者輸入的内容。而是onChange 事件觸發之後,由于 this.setState 導緻了一次重新渲染。不過React會優化這個渲染過程。看上去有點類似雙向資料綁定
10、資料持久化
//執行緩存資料
localStorage.setItem('todolist',JSON.stringify(tempList));
//擷取緩存的資料
var todolist=JSON.parse(localStorage.getItem('todolist')); /*字元串*/
11、React的子產品化封裝Storage
建立檔案夾model,存放自定義子產品,建立model/storage.js子產品:
var storage={
set(key,value){
localStorage.setItem(key,JSON.stringify(value));
},
get(key){
return JSON.parse(localStorage.getItem(key));
},remove(key){
localStorage.removeItem(key)
}
};
export default storage;
引用:
//引入自定義子產品
import storage from '../model/storage';
//執行緩存資料
storage.set('todolist',tempList);
//擷取緩存的資料
var todolist=storage.get('todolist');
11、React中父子組建傳值
React中的元件: 解決html 标簽建構應用的不足。
使用元件的好處:把公共的功能單獨抽離成一個檔案作為一個元件,哪裡裡使用哪裡引入。
父子元件:元件的互相調用中,我們把調用者稱為父元件,被調用者稱為子元件
父元件給子元件傳值
1.在調用子元件的時候定義一個屬性 <Header msg='首頁'></Header>
2.子元件裡面 this.props.msg
說明:父元件不僅可以給子元件傳值,還可以給子元件傳方法,以及把整個父元件傳給子元件。
父元件主動擷取子元件的資料
1、調用子元件的時候指定ref的值 <Header ref='header'></Header>
2、通過this.refs.header 擷取整個子元件執行個體
12、預設值和類型檢驗
defaultProps:父子元件傳值中,如果父元件調用子元件的時候不給子元件傳值,可以在子元件中使用defaultProps定義的預設值
propTypes:驗證父元件傳值的類型合法性
1、引入import PropTypes from 'prop-types';
2、類.propTypes = {
name: PropTypes.string
};
都是定義在子元件裡面
//defaultProps 如果父元件調用子元件的時候不給子元件傳值,可以在子元件中使用defaultProps定義的預設值
Header.defaultProps={
title:'标題'
}
//同行propTypes定義父元件給子元件傳值的類型
Header.propTypes={
num:PropTypes.number
}
13、擷取資料
react擷取伺服器APi接口的資料:
react中沒有提供專門的請求資料的子產品。但是我們可以使用任何第三方請求資料子產品實作請求資料
1、axios https://github.com/axios/axios
axios的作者覺得jsonp不太友好,推薦用CORS方式更為幹淨(後端運作跨域)
1、安裝axios子產品npm install axios --save / npm install axios --save
2、在哪裡使用就在哪裡引入import axios from 'axios'
3、看文檔使用
var api='http://www.phonegap100.com/appapi.php?a=getPortalList&catid=20';
axios.get(api)
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
import React, { Component } from 'react';
import axios from 'axios';
class Axios extends Component {
constructor(props) {
super(props);
this.state = {
list:[]
};
}
getData=()=>{
//通過axios擷取伺服器資料
var api='http://www.phonegap100.com/appapi.php?a=getPortalList&catid=20'; //接口背景允許了跨域
axios.get(api)
.then((response)=> {
console.log(response.data.result);
//用到this要注意this指向
this.setState({
list:response.data.result
})
})
.catch(function (error) {
console.log(error);
});
}
render() {
return (
<div>
<h2>axios擷取伺服器資料</h2>
<button onClick={this.getData}>擷取伺服器api接口資料</button>
<hr />
<ul>
{
this.state.list.map((value,key)=>{
return <li key={key}>{value.title}</li>
})
}
</ul>
</div>
);
}
}
export default Axios;
2、fetch-jsonp https://github.com/camsong/fetch-jsonp
1、安裝 npm install fetch-jsonp --save
2、import fetchJsonp from 'fetch-jsonp'
3、看文檔使用
fetchJsonp('/users.jsonp')
.then(function(response) {
return response.json()
}).then(function(json) {
console.log('parsed json', json)
}).catch(function(ex) {
console.log('parsing failed', ex)
})
import React, { Component } from 'react';
import fetchJsonp from 'fetch-jsonp';
class FetchJsonp extends Component {
constructor(props) {
super(props);
this.state = {
list:[]
};
}
getData=()=>{
//擷取資料
var api="http://www.phonegap100.com/appapi.php?a=getPortalList&catid=20";
fetchJsonp(api)
.then(function(response) {
return response.json()
}).then((json)=> {
// console.log(json);
this.setState({
list:json.result
})
}).catch(function(ex) {
console.log('parsing failed', ex)
})
}
render() {
return (
<div>
<h2>FetchJsonp 擷取伺服器jsonp接口的資料</h2>
<button onClick={this.getData}>擷取伺服器api接口資料</button>
<hr />
<ul>
{
this.state.list.map((value,key)=>{
return <li key={key}>{value.title}</li>
})
}
</ul>
</div>
);
}
}
export default FetchJsonp;
3、其他請求資料的方法也可以...自己封裝子產品用原生js實作資料請求也可以...
14、生命周期函數
React生命周期函數:
元件加載之前,元件加載完成,以及元件更新資料,元件銷毀。
觸發的一系列的方法 ,這就是元件的生命周期函數
元件加載的時候觸發的函數:
constructor 、componentWillMount、 render 、componentDidMount
元件資料更新的時候觸發的生命周期函數:
shouldComponentUpdate、componentWillUpdate、render、componentDidUpdate
你在父元件裡面改變props傳值的時候觸發的:
componentWillReceiveProps
元件銷毀的時候觸發的:
componentWillUnmount
必須記住的生命周期函數:
*加載的時候:componentWillMount、 render 、componentDidMount(dom操作)
更新的時候:componentWillUpdate、render、componentDidUpdate
*銷毀的時候: componentWillUnmount
15、路由配置
/*
react路由的配置:
1、找到官方文檔 https://reacttraining.com/react-router/web/example/basic
2、安裝 cnpm install react-router-dom --save
3、找到項目的根元件引入react-router-dom
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
4、複制官網文檔根元件裡面的内容進行修改 (加載的元件要提前引入)
<Router>
<Link to="/">首頁</Link>
<Link to="/news">新聞</Link>
<Link to="/product">商品</Link>
<Route exact path="/" component={Home} />
<Route path="/news" component={News} />
<Route path="/product" component={Product} />
</Router>
exact表示嚴格比對
react動态路由傳值
1、動态路由配置
<Route path="/content/:aid" component={Content} />
2、對應的動态路由加載的元件裡面擷取傳值
this.props.match.params.aid
跳轉:<Link to={`/content/${value.aid}`}>{value.title}</Link>
react get傳值
1、路由配置
<Route path="/productcontent" component={ProductContent} />
2、擷取 this.props.location.search,其值為: ?aid=4
然後使用url子產品解析字元串,安裝 cnpm install url --save
import url from 'url'
var aid = url.parse(this.props.location.search,true).query.aid
跳轉:<Link to={`/productcontent/?aid=${value.aid}`}>{value.title}</Link>
*/
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import './assets/css/index.css'
import Home from './components/Home';
import News from './components/News';
import Product from './components/Product';
import Content from './components/Content';
import ProductContent from './components/ProductContent';
class App extends Component {
render() {
return (
<Router>
<div>
<header className="title">
<Link to="/">首頁</Link>
<Link to="/news">新聞</Link>
<Link to={`/productcontent/?aid=${value.aid}`}>{value.title}</Link>
</header>
<br />
<hr />
<br />
<Route exact path="/" component={Home} />
<Route path="/news" component={News} />
<Route path="/product" component={Product} />
<Route path="/productcontent" component={ProductContent} />
<Route path="/content/:aid" component={Content} />
</div>
</Router>
);
}
}
export default App;
16、react-router4.x中使用js跳轉路由
/*
實作js跳轉路由:https://reacttraining.com/react-router/web/example/auth-workflow
1、要引入Redirect
import {
BrowserRouter as Router,
Route,
Link,
Redirect,
withRouter
} from "react-router-dom";
2、定義一個flag
this.state = {
loginFlag:false
};
3、render裡面判斷flag 來決定是否跳轉
if(this.state.loginFlag){
return <Redirect to={{ pathname: "/" }} />;
}
4、要執行js跳轉
通過js改變loginFlag的狀态
改變以後從新render 就可以通過Redirect自己來跳轉
*/
import React, { Component } from 'react';
import {Redirect} from "react-router-dom";
class Login extends Component {
constructor(props) {
super(props);
this.state = {
loginFlag:false
};
}
doLogin=(e)=>{
e.preventDefault();
let username=this.refs.username.value;
let password=this.refs.password.value;
console.log(username,password)
if(username=='admin' && password=='123456'){
//登入成功 跳轉到首頁
this.setState({
loginFlag:true
})
}else{
alert('登入失敗')
}
}
render() {
if(this.state.loginFlag){
// return <Redirect to={{ pathname: "/" }} />;
return <Redirect to='/' />;
}
return (
<div>
<br /> <br /> <br />
<form onSubmit={this.doLogin}>
<input type="text" ref="username" /> <br /> <br />
<input type="password" ref="password" /> <br /> <br />
<input type="submit" value="執行登入"/>
</form>
</div>
);
}
}
export default Login;
17、路由的嵌套
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import Info from './User/Info';
import Main from './User/Main';
class User extends Component {
constructor(props) {
super(props);
this.state = {
msg:'我是一個User元件'
};
}
render() {
return (
<div className="user">
<div className="content">
<div className="left">
<Link to="/user/">個人中心</Link>
<br />
<br />
<Link to="/user/info">使用者資訊</Link>
</div>
<div className="right">
<Route exact path="/user/" component={Main} />
<Route path="/user/info" component={Info} />
</div>
</div>
</div>
);
}
}
export default User;
18、路由子產品化代碼分離
建立model/router.js檔案:
import Home from '../components/Home';
import User from '../components/User';
import Shop from '../components/Shop';
import News from '../components/News';
let routes = [
{
path: "/",
component: Home,
exact:true
},
{
path: "/shop",
component: Shop
},
{
path: "/user",
component: User
},
{
path: "/news",
component: News
}
];
export default routes;
App.js中聲明路由:
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import './assets/css/index.css';
import routes from './model/router.js';
class App extends Component {
render() {
return (
<Router>
<div>
<header className="title">
<Link to="/">首頁元件</Link>
<Link to="/user">使用者頁面</Link>
<Link to="/shop">商戶</Link>
<Link to="/news">新聞</Link>
</header>
{
routes.map((route,key)=>{
if(route.exact){
return <Route key={key} exact path={route.path} component={route.component}/>
}else{
return <Route key={key} path={route.path} component={route.component}/>
}
})
}
</div>
</Router>
);
}
}
export default App;
19、路由子產品化嵌套路由
import Home from '../components/Home';
import User from '../components/User';
import UserList from '../components/User/UserList';
import UserAdd from '../components/User/UserAdd';
import UserEdit from '../components/User/UserEdit';
import Shop from '../components/Shop';
import News from '../components/News';
let routes = [
{
path: "/",
component: Home,
exact:true
},
{
path: "/shop",
component: Shop
},
{
path: "/user",
component: User,
routes:[ /*嵌套路由*/
{
path: "/user/",
component: UserList
},
{
path: "/user/add",
component: UserAdd
},
{
path: "/user/edit",
component: UserEdit
}
]
},
{
path: "/news",
component: News
}
];
export default routes;
App.js,給嵌套路由傳遞路由參數:
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import './assets/css/index.css';
import routes from './model/router.js';
class App extends Component {
render() {
return (
<Router>
<div>
<header className="title">
<Link to="/">首頁元件</Link>
<Link to="/user">使用者頁面</Link>
<Link to="/shop">商戶</Link>
<Link to="/news">新聞</Link>
</header>
{
routes.map((route,key)=>{
if(route.exact){
return <Route key={key} exact path={route.path}
// route.component value.component <User {...props} routes={route.routes} />
render={props => (
// pass the sub-routes down to keep nesting
<route.component {...props} routes={route.routes} />
)}
/>
}else{
return <Route key={key} path={route.path}
render={props => (
// pass the sub-routes down to keep nesting
<route.component {...props} routes={route.routes} />
)}
/>
}
})
}
</div>
</Router>
);
}
}
export default App;
User.js根據傳遞的路由參數實作路由:
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
class User extends Component {
constructor(props) {
super(props);
this.state = {
msg:'我是一個User元件'
};
}
componentWillMount(){
console.log(this.props.routes);
}
render() {
return (
<div className="user">
<div className="content">
<div className="left">
<Link to="/user/">使用者清單</Link>
<br />
<br />
<Link to="/user/add">增加使用者</Link>
<br />
<br />
<Link to="/user/edit">編輯使用者</Link>
</div>
<div className="right">
{
this.props.routes.map((route,key)=>{
return <Route key={key} exact path={route.path} component={route.component} />
})
}
{/* <Route path="/user/add" component={UserAdd} /> */}
</div>
</div>
</div>
);
}
}
export default User;