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


    一、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请求

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

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

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

    解决:

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

    {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了
    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:
    import {BrowserRouter as Router,Route,Link,Redirect,withRouter} from "react-router-dom";
    
    1. 定义一个flag
    this.state = {loginFlag:false};
    
    1. render里面判断flag 来决定是否跳转:
    if(this.state.loginFlag){
        return <Redirect to={{ pathname: "/" }} />;
    }
    
    1. 要执行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;
    

    最后,效果:

    1. 在Home点登录,会跳转到Login页面:登录网站
    2. 登录页面输入:admin,admin后,将自动跳转到首页,输入其它弹出登录失败
      在这里插入图片描述
  • 相关阅读:
    2021.07.01 学习总结
    2021.06.30 学习总结
    2021.06.29 学习总结
    2021.06.28 学习总结
    ubuntu 安装nginx报错./configure: error: SSL modules require the OpenSSL library
    Docker 启动alpine镜像中可执行程序文件遇到 not found
    docker基于cenots7 制作nginx镜像
    【Linux报错】VM虚拟机的CentOS7系统启动时报Generating /run/initramfs/rdsosreport.txt
    Docker Swarm 集群概念扩展
    Docker Swarm 集群弹性、动态扩缩容
  • 原文地址:https://www.cnblogs.com/chenxi188/p/11943266.html
Copyright © 2020-2023  润新知