React 快速打开方式

生命周期

  • componentWillMount 在渲染前调用,在客户端也在服务端,比较少用。
  • componentDidMount : 在第一次渲染后调用,只在客户端。之后组件已经生成了对应的DOM结构,可以通过this.getDOMNode()来进行访问。 如果你想和其他JavaScript框架一起使用,可以在这个方法中调用setTimeout, setInterval或者发送AJAX请求等操作(防止异步操作阻塞UI)。
  • componentWillReceiveProps 在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用。
  • shouldComponentUpdate 返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。可以在你确认不需要更新组件时使用。
  • componentWillUpdate在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用。
  • componentDidUpdate 在组件完成更新后立即调用。在初始化时不会被调用。
  • componentWillUnmount在组件从 DOM 中移除之前立刻被调用。

注意点:WillMount ->组件渲染 -> DidMount

组件构造器

创建每个组件时,都应该有一个构造器,如下

import {Component} from 'react'
class Home extends Component {
  constructor(props) {
    super(props); // 接收
    this.state = {
      // .. 该组件定义的数据
    };
  }
}

父组件中调用该组件

import Home from './views/Home'
class App extends Compoent{

	constructor(props){
		super(props)
	}
	this.state = {
    	userList: {...},
    	userType: {...}
	}
	render(){
	  return(
	     <Home userList={userList} user> <Home>
	  )
	}
}

在Home组件中即可使用this.props.userList来获取该数据。

属性拓展

有时候你需要给组件设置多个属性,你不想一个个写下这些属性,或者有时候你甚至不知道这些属性的名称,这时候 spread attributes 的功能就很有用了。

class Dom extends React.Component{
    constructor(props){
        super(props);
        this.state = {
           params: {}
        }
    }
    componentWillMount(){
        this.state.params.foo = 'foo';
        this.state.params.bar = 'bar';
    }
	render(){
        return (
          <div ref="container">
                <Header ref="header" {...this.state.params}></Header>
          </div>
        )
    
    }
}

子组件打印props:
在这里插入图片描述

JSX

JSX简单地说就是一种把 html 插入 js 中的一种写法,写Vue或者以前传统的MVC框架时,都被 “表现层和逻辑层” 分离这个概念影响颇深。但 React 认为,对于一个组件,表现层和逻辑层本该就是密不可分的。拿上述的Home组件来举例。 JSX通常写在render函数的return ( ) 里面。 return之前是可以写js的。

首先定义父组件传过来的数据,一个是数组,一个是普通对象。

 userList: [
     {
         "userName": "fangMing", "text": "123333", "result": true
     }, 
     {
         "userName": "zhangSan", "text": "345555", "result": false
     }
 ],

 userType:{
   "1004":"vip",
   "1005":"pinglian",
   "1006":"xianxia"
 }
class Home extends React.Component{
    constructor(props){
        super(props);
        this.state = {
          userList : props.userList,
          userType : props.userType
        }
    }
	
	render(){
	   	// 这里可以写js代码,如定义变量提供给jsx使用
	   	// const role = this.props.role;
		return (
			 <div>
                <ul>
                    {
	                    this.state.userList.map((item,index)=>{
	                         return(
	                         <li key={index}>
	                             {item.userName}
	                         </li> 
	                         )
	                    })
                    }
                    {
                        bject.keys(this.state.userType).map(key=>{
                            return(
                                <li key={key}>
                                    {key} : {this.state.userType[key]}
                                </li>
                            )
                        })
                    }
                </ul>
            </div>
		)
    }
}

在这里插入图片描述

return( ) 中间写HTML模板,需要用到js表达式时用{ },js表达书中需要再嵌入HTML,只需再嵌入 return( )即可。

setState

当我们需要修改模板时,不能直接使用this.state.xxx, 这将不会使模板重新渲染,必须使用this.setState({})

例: 当我们需要把下列数组每一项的userName改掉

 userList: [
     {
    	"userName": "fangMing", "text": "123333", "result": true
     }, 
     {
         "userName": "zhangSan", "text": "345555", "result": false
     }
 ],

利用Array.map,处理每一项并返回一个新的数组。

 componentWillMount(){
    setTimeout(()=>{
         this.setState({
             userList: this.state.userList.map((item,index,arr)=>{
                 item.userName = '嘻嘻嘻';
                 return item;
             })
         })
    },2000)
}

⭐Router路由

路由分为HashRouter 和 BrowserRouter。BrowserRouter 较为简介,但线上环境需要服务端配置支持,下面以BrowserRouter为例。

import {
	Route,
	Switch,
	BrowserRouter as Router} 
from 'react-router-dom';

import Home from './views/home'
import User from './views/user'

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  render(){
    return (
      <Router>
         <Switch>
          <Route path="/user" component={User}></Route>
          <Route path="/" component={Home}></Route>
        </Switch>
      </Router>
     
    );
  }
}

注意点:

  1. Switch 作用是出现重复path时只匹配第一个。
  2. path=’/’ 要放到最后,任何path都能与 ‘/’ 匹配。

路由跳转
方法1:js控制跳转 , /user中通过this.props.location.query 即可获取参数,但要注意保存数据,刷新后不再获取该数据。

 onGo(pathName){
     this.props.history.push({
         pathname:pathName,
         query:{
             "uid": '112',
             "uname": 'jenson'
         }
     })
 }
 // react中类的方法默认是不会绑定 this 的。
 //如果你忘记绑定 this.handleClick 并把它传入 onClick
 //当你调用这个函数的时候 this 的值会是 undefined。
<button onClick={this.onGo.bind(this,'/user')}>
  去User承载页面
</button>

方法2:Link跳转,/user中通过this.props.location.query 即可获取参数,但要注意保存数据,刷新后不再获取该数据。

<Link to={{pathname:"/user",query:{"type":"link跳转"}} }>
    <button>gogogo</button>
</Link>

条件渲染

if/else渲染

jsx中是不允许在{}中插入if/else表达式的,因此只能在return之前先判断,这就带来一个弊端,没办法写一些公共部分,如不管是不是vip都要显示的部分,这部分只能在if/else两个return中都写上,代码冗余严重。

render(){
  const role  = this.state.role;
    if(role !== 'vip'){
        return (
            <h1>不是Vip</h1>
            <h1>Home</h1>
        )
    }
    else{
        return (
            <div>
                <h1>欢迎Vip</h1>
                <h1>Home</h1>
            </div>
        )
    }
}

Render(IF) 组件

这种方式可以针对单一元素判断渲染,如下,<h1>home<h1>无论如何都会被渲染。

render(){
        function Render ({ if: cond, children }) {
            return cond ? children : null
        }
        const role  = this.state.role;

        return (
            <div>
                <Render if={role!=='vip'}>
                    <h1>不是VIP</h1>
                </Render>
                 <Render if={role =='vip'}>
                    <h1>欢迎VIP</h1>
                </Render>
                
                <h1>Home</h1>
            </div>
        )
    
    }

立即执行函数(IF)

虽然表达式中不能使用if/else,但可以使用立即执行函数啊!在函数中再使用if/else判断,发现是行得通的。


render(){
	return (
	    <div>
	        {
	            (function vip(){
	                if(role !== 'vip'){
	                    return <h1>不是VIP</h1>
	                }else{
	                    return <h1>欢迎VIP</h1>
	                }
	            })()
	        }
	        <h1>Home</h1>
	    </div>
	)
}

React中的条件渲染没有Vue那么方便,但给了开发者很多种拓展的方式实现,可根据不同的业务场景来选择合适的方案。

DOM操作

refs操作

注意,ref要等到render完成后才能取到引用,因此至少在componentDidMount中使用。

操作组件内的div,ref获得的是真实DOM节点

componentDidMount(){
     setTimeout(()=>{
         this.refs.title.innerHTML = "DOMDOM"
     },1000)
 }
 render(){
    return (
      <div>
            <h1 ref="title">DOM</h1>
      </div>
    )
}

操作子组件,ref获得的是一个reactDom,并且可以调用子组件的方法

import Header from '../header'
componentDidMount(){
     let header = this.refs.header;
     console.log(header)
	 header.speak() // header中定义的speak方法
}
render(){
    return (
      <div ref="container">
            <Header ref="header"></Header>
      </div>
    )
}

在这里插入图片描述

findDOMNode

ref操作子组件仅仅能获取一个reactDom, 那么如果我们需要操作子组件的Width,Height等属性,就需要获取子组件的真实DOM节点,可用findDOMNode。

import Header from '../header'
componentDidMount(){
     let header = this.refs.header;
     console.log(header)
	 header.speak() // header中定义的speak方法
     
     let headerDom = findDOMNode(header) // header的引用ref为参数
     console.log(headerDom)
}
render(){
    return (
      <div ref="container">
            <Header ref="header"></Header>
      </div>
    )
}

在这里插入图片描述

异步挂载组件

有时候我们会遇到一个问题,给子组件传递的数据是需要异步请求得来的,如果异步请求还没完成子组件就挂上去了,容易造成报错。

解决方案:

render(){
	return(
	 	{this.state.type == 1 && <Header type={this.state.type}></Header>}
	)
}

http.get(url).then(res=>{
	if(res.code == 0){
		this.setState({
			type:1
		})
	}
})

在Route中依然可以使用该方法, 当this.state.matchRoute变为为true时才回去匹配路由。

class Data extends Component {
  constructor(props) {
    super(props);
    this.state = {
      matchRoute:false,
    };
	render(){
	 return (
	   <div> 
	      {this.state.matchRoute &&
	        <Switch>
	          <Route path="/manage/data/" component ={ props => <Data {...props} />}>
	          </Route>
	        </Switch>
	      }
	    </div>
		);
	}
	componentDidMount() {
		http.get(url).then(res=>{
			if(res.code == 0){
				this.setState({
					matchRoute : true
				})
			}
		})
	}
}

子组件传值的注意点

1.在使用路由时,当setState执行,传给子组件的todos也更新,此时整个子组件会重新挂载!


componentDidMount(){
	 this.setState({
         todos: this.state.todos.push(...)
     })
}

<Router>
   <Switch>
      <Route  path="/" exact component={ () => <TodoList todos={this.state.todos} />}>
       </Route>
    </Switch>
</Router>

2.不适用路由,单纯使用子组件时,当setState执行,传给子组件的todos更新,但子组件不会重新挂载。


componentDidMount(){
	 this.setState({
         todos: this.state.todos.push(...)
     })
}

<TodoFooter todos={this.state.todos}></TodoFooter>

Context

用于父组件和子组件及其子孙组件的数据共享,避免数据需要通过Props一层一层传递下去的麻烦。

父组件定义Provider

// ...
// 子组件
import Header from '../header'
import Footer from '../footer'
// 定义Context对象,里面包括Context.Provider和Context.Consumer
export const Context = React.createContext({});

class Home extends React.Component{
    constructor(props){
        super(props);
        this.state = {}
    }
    
    render(){
        let title = 'title from Home'
        let footerText = 'footer text from Home'
        return (
	        <Context.Provider value={{
	        	title:title,
            	footerText:footerText
            }}>
	            <div ref="container">
	                <Header ref="header"></Header>
	                <Footer></Footer>
	            </div>
	        </Context.Provider>
        )
    }
}
export default Home

子组件使用Consumer获取数据

// .. 
// 导入父组件导出的Context
import {Context} from '../Home/index.js'
class Header extends React.Component{
    constructor(props){
        super(props);
        this.state = {}
    }
    render(){
        return (
            <div>
            	// 使用Context的Consumer获取数据
                <Context.Consumer>
                {
                    (obj) =>
                        <h1>{obj.title}</h1>
                }
                </Context.Consumer>
                
                <div>other</div>
            </div> 
        )
    
    }
}

export default Header

如果子组件是一个pure component(hook,如下面的Footer), 可以用useContext获取数据, 父组件定义Context同上

import React,{useState,useEffect,useContext} from 'react'

// 导入Context
import {Context} from '../Home/index.js'

function Footer(props){

    // 获取数据
    const context = useContext(Context)

    return (
        <div>
          <h1>{context.footerText}</h1>
        </div>
      );
}


export default Footer;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值