一、React加載資料流程回顧
先看上一節的産品詳情代碼:https://blog.csdn.net/u010132177/article/details/103184176
【Pcontent.js】
import React, { Component } from 'react';
import axios from 'axios';
import '../css/pcontent.css';
import '../css/basic.css';
import {Link} from 'react-router-dom';
class Pcontent extends Component {
constructor(props){
super(props);
this.state={
detail_list:[], //此處要注意格式,如果Api是字典,就要設定成 {}
domain:'http://a.itying.com/'
}
}
//【1】此處和上節稍有差別:把接口擷取單獨寫成一個函數
requestData(id){
var api=this.state.domain+'api/productcontent?id='+id;
axios.get(api)
.then((response)=>{
console.log(response);
this.setState({
list:response.data.result[0]
})
})
.catch(function (error) {
console.log(error);
})
}
//【2】在生命周期函數内調用擷取api接口資料函數
componentDidMount(){
//id
console.log(this.props.match.params.id)
let id=this.props.match.params.id;
this.requestData(id);
}
render() {
return (
<div className='pcontent'>
<div className="back"><Link to='/'>傳回</Link></div>
<div className="p_content">
<div className="p_info">
<img alt={this.state.detail_list.title} src={`${this.state.domain}${this.state.detail_list.img_url}`}/>
<h2>{this.state.detail_list.title}</h2>
<p className="price">{this.state.detail_list.price}元</p>
</div>
<div className="p_detial">
<h3>
商品詳情
</h3>
{/*html解析寫法*/}
<div className="p_content" dangerouslySetInnerHTML={{__html: this.state.detail_list.content}}>
</div>
</div>
</div>
<footer className="pfooter">
<div className="cart">
<strong>數量:</strong>
<div className="cart_num">
<div className="input_left">-</div>
<div className="input_center">
<input type="text" readOnly="readonly" value="1" name="num" id="num" />
</div>
<div className="input_right">+</div>
</div>
</div>
<button className="addcart">加入購物車</button>
</footer>
</div>
);
}
}
export default Pcontent;
控制台:産品詳情頁get 404 undefined錯誤原因
上一節加載詳情時,控制台将發現會報錯:
GET http://a.itying.com/undefined 404 (Not Found) undefined
【原因】:
- 分析源碼發現,隻有圖檔才會發起一個get請求
- 這涉及到之前講的生命同期函數加載順序問題順序:
- 先:componentWillMount(){}
- 再:render(){}
- 再:componentDidMount(){}
- 再:render(){} 一次
-
原來,我們把擷取Api資料放在第 3 步裡,當第一次render(){}渲染時,Api資料還沒擷取到,是以會出現報錯
當第2次render之後,資料已擷取,是以就能正常加載圖檔了。
- 那麼:放在willmount()裡呢,一樣拿不到,原因是,willmount可能會加載非常快
解決:
隻要把圖檔加個判斷,有圖檔,加載,沒——渲染成空,寫成這樣即可:
此處文法三目:條件 ? true :false
為什麼在清單那裡圖檔【home.js】就不會有404呢
原因:
- 清單頁用的是this.state.list.map函數,它首先會判斷list是否有資料,有才會渲染圖檔
- 沒資料,不會渲染圖檔,也就不會有get 請求,也不會有404了
this.state.list.map((value,key)=>{
...
<img alt={v.title} src={`${this.state.domain}${v.img_url}`} />
二、react-router中用js跳轉路由
實作js跳轉路由:https://reacttraining.com/react-router/web/example/auth-workflow
- 要引入Redirect:
- 定義一個flag
- render裡面判斷flag 來決定是否跳轉:
if(this.state.loginFlag){
return <Redirect to={{ pathname: "/" }} />;
}
-
要執行js跳轉:
- 通過js改變loginFlag的狀态
- 改變以後從新render 就可以通過Redirect自己來跳轉
代碼示例
第1步:在首頁加入登入按鈕[home.js]
重點:
import {Link} from 'react-router-dom';
<Link to='Login'>登陸網站</Link>
【Home.js】
import React,{Component} from 'react';
import {Link} from 'react-router-dom';
import '../css/index.css';
import axios from 'axios'; //也可寫成:const axios = require('axios');
class Home extends Component{
constructor(props){
super(props);
this.state={
list:[],
domain:'http://a.itying.com/'
}
}
//擷取Api接口的資料
getDataApi=()=>{
//拼裝得到完整的Api接口連結
var api=this.state.domain+"api/productlist";
axios.get(api)
.then((response)=>{
console.log(response);
this.setState({
list:response.data.result
})
})
.catch(function(error){
console.log(error);
})
}
//生周函數:頁面渲染完成後加載
componentDidMount(){
//調用函數得到api接口資料
this.getDataApi();
}
render(){
return(
<div>
{/*★★★本頁面新加登陸按鈕*/}
<Link to='Login'>登陸網站</Link>
<header className="index_header">
<div className="hlist">
<img alt='熱銷榜' src={require('../images/rexiao.png')} />
<p>熱銷榜</p>
</div>
<div className="hlist">
<img alt='點過的菜' src={require('../images/caidan.png')} />
<p>點過的菜</p>
</div>
<div className="hlist">
<img alt='猜你喜歡' src={require('../images/sousuo.png')} />
<p>猜你喜歡</p>
</div>
</header>
<div className="content">
{
this.state.list.map((value,key)=>{
return(
<div className="item" key={key}>
<h3 className="item_cate">{value.title}</h3>
<ul className="item_list">
{
value.list.map((v,k)=>{
return(
<li key={k}>
<div className="inner">
<Link to={`/Pcontent/${v._id}`}>
<img alt={v.title} src={`${this.state.domain}${v.img_url}`} />
</Link>
<p className="title">{v.title}</p>
<p className="price">{v.price}元</p>
</div>
</li>
)
})
}
</ul>
</div>
)
})
}
</div>
</div>
)
}
}
export default Home;
第2步:login.js
重點:【1-5】
import React, { Component } from 'react';
import {
BrowserRouter as Router,
Redirect, //【1】引入Redirect
} from "react-router-dom";
class Login extends Component {
constructor(props){
super(props);
this.state={
loginFlag:false //【2】設定登入标志
}
}
//【4】登入函數
login=(e)=>{
e.preventDefault(); //阻止submit預設有個重新整理的動作
let username=this.refs.username.value; //擷取使用者登入的使用者名
let pwd=this.refs.pwd.value; //擷取使用者輸入的密碼
console.log(username,pwd)
if(username=='admin' && pwd=='admin'){ //如果使用者名、密碼都正确,把登入标志成 ture。
this.setState({loginFlag:true})
}else{alert('登入失敗')}
}
render() {
//【5】判斷登入标志是否是ture,是就跳轉到首頁
if(this.state.loginFlag){
return <Redirect to='/' />;
}
return (
<div>
{/* 【3】登入表單,此處用ref擷取值 */}
<form onSubmit={this.login}>
<input type='input' ref='username' /><br/>
<input type='password' ref='pwd' /><br/>
<input type='submit' value='登入' />
</form>
</div>
);
}
}
export default Login;
第3步:App頁面把login.js加到路由裡
import React from 'react';
//import './App.css';
import { BrowserRouter as Router, Route } from 'react-router-dom'; //引入路由子產品
import Home from './components/Home';
import Pcontent from './components/Pcontent';
import Login from './components/Login';
function App() {
return (
<Router>
<div>
<Route exact path="/" component={Home} />
<Route path="/Pcontent/:_id" component={Pcontent} />
{/*★★★把登入路由加到此處*/}
<Route path="/Login" component={Login} />
</div>
</Router>
);
}
export default App;
最後,效果:
- 在Home點登入,會跳轉到Login頁面:登入網站
- 登入頁面輸入:admin,admin後,将自動跳轉到首頁,輸入其它彈出登入失敗