0%

十六、React 渲染数据注意事项、以及react-router4.x中使用js跳转路由(登录成功自动跳转首页)

详情请点阅读全文

一、React加载数据流程回顾

先看上一节的产品详情代码:https://blog.csdn.net/u010132177/article/details/103184176

【Pcontent.js】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
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错误原因

上一节加载详情时,控制台将发现会报错:

1
GET http://a.itying.com/undefined 404 (Not Found) undefined

【原因】:

  • 分析源码发现,只有图片才会发起一个get请求

  • 这涉及到之前讲的生命同期函数加载顺序问题顺序:

    1. 先:componentWillMount(){}
    2. 再:render(){}
    3. 再:componentDidMount(){}
    4. 再:render(){} 一次
  • 原来,我们把获取Api数据放在第 3 步里,当第一次render(){}渲染时,Api数据还没获取到,因此会出现报错
    当第2次render之后,数据已获取,所以就能正常加载图片了。

  • 那么:放在willmount()里呢,一样拿不到,原因是,willmount可能会加载非常快

解决:

只要把图片加个判断,有图片,加载,没——渲染成空,写成这样即可:
此处语法三目:条件 ? true :false

1
{this.state.detail_list.img_url?<img alt={this.state.detail_list.title} src={`${this.state.domain}${this.state.detail_list.img_url}`}/>:''}

为什么在列表那里图片【home.js】就不会有404呢

原因:

  • 列表页用的是this.state.list.map函数,它首先会判断list是否有数据,有才会渲染图片
  • 没数据,不会渲染图片,也就不会有get 请求,也不会有404了
    1
    2
    3
    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
  1. 要引入Redirect:
    1
    import {BrowserRouter as Router,Route,Link,Redirect,withRouter} from "react-router-dom";
  2. 定义一个flag
    1
    this.state = {loginFlag:false};
  3. render里面判断flag 来决定是否跳转:
    1
    2
    3
    if(this.state.loginFlag){
    return <Redirect to={{ pathname: "/" }} />;
    }
  4. 要执行js跳转:
    - 通过js改变loginFlag的状态
    - 改变以后从新render 就可以通过Redirect自己来跳转

    代码示例

    第1步:在首页加入登录按钮[home.js]

    重点:
    1
    2
    import {Link} from 'react-router-dom';
    <Link to='Login'>登陆网站</Link>
    【Home.js】
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    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】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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加到路由里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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;

最后,效果:

  1. 在Home点登录,会跳转到Login页面:登录网站
  2. 登录页面输入:admin,admin后,将自动跳转到首页,输入其它弹出登录失败
    在这里插入图片描述