React知识简要

React

脚手架create-react-app XXX

JSX写法不同:
  1. class ->className
  2. 在 JSX 中不能使用 if else 语句,但可以使用 conditional (三元运算) 表达式来替代。
  3. JSX 允许在模板中插入数组,数组会自动展开所有成员;

创建组件的方式

1. 构造函数
function Cmp(props){
    //console.log(props)
    return <p>第一种方式--{props.name}</p>
}
ReactDOM.render(
    <Cmp name="zs" age={20}></Cmp>,  	//外部传入数据
    document.getElementById('app')
)
2. class关键字
class Person extends React.Component{
    //constructor(props){
    	//super(props)
    		//在此处props不能直接使用,须先定义;
	//}
    
    // 必须定义一个render函数(实例方法)
    render(){
        // 必须返回一个null或者虚拟DOM元素
        return <div>
            <h1>这是用 class 关键字创建的组件!</h1>
        </div>;
    }
}

两种方式的区别:

  • 构造函数在使用外部传入的数据时,props不能直接使用,需要先(参数位置)定义;class在使用外部数据时,可直接通过this.props.xx的方式使用props。

有状态组件VS无状态组件

有状态组件:用class关键字创建出来的组件;无状态组件:用构造函数创建出来的

两者之间的本质区别是:有无state私有属性! 有无生命周期!

问题:什么时候使用有状态组件?什么时候使用无状态的?

  1. 当组件需要存放自己的私有数据,或需要在不同状态下执行不同的业务逻辑,则适合第一种;
  2. 若只需要根据外界传递的props渲染固定的页面,则适合第二种;(相比第一种,少了生命周期)
State与Props

props是property的缩写,可以理解为HTML标签的attribute。只要是组件的props都是只读的;

props是用于整个组件树中传递数据和配置。

两者的区别:

  • state只存在于组件内部,只能从当前组件调用this.setState修改state值(不可以直接修改this.state!)。

一般更新子组件都是通过更新state值,然后更新子组件的props值。

通常用props传递大量数据,state用于存放组件内部一些简单的定义数据(状态值)。

容器组件VS展示组件

基本原则:容器组件负责数据获取,展示组件负责根据props展示信息。

受控组件VS非受控组件

组件通信

通信是单向的,数据必须由一方传到另一方。

父向子通信

通过 props 的方式

class Parent extends Component{
  state = {
    msg: 'start'
  };
  render() {
    return <Child msg={this.state.msg} />;
  }
}

class Child extends Component{
  render() {
    return <p>{this.props.msg}</p>
  }
}
子向父通信

子组件向父组件通讯,同样也需要父组件向子组件传递 props 进行通讯,但是父组件传递的是作用域为父组件自身的函数子组件调用该函数,将子组件想要传递的信息作为参数,传递到父组件的作用域中。

class Parent extends Component{  
    state = {    
        msg: 'start'  
    };    
	transferMsg(msg) {    
        this.setState({      
            msg    
        });  
    }  
	render() {    
        return <div>        
            <p>子组件传递过来的信息: {this.state.msg}</p>        
        	<Child change = {msg => this.transferMsg(msg)} />       	   
        </div>;  
        //使用箭头函数(使内部this仍指向父组件),将父组件的transferMsg函数通过props传递给子组件
	}
}
class Child extends Component{  
    componentDidMount() {    
        setTimeout(() => {      
           this.props.change('end') //子组件调用该函数,将子组件想要传递的信息作为参数   
        }, 1000);  
    }  
    // ....
}

组件的生命周期

defaultProps

在组件创建之前,会先初始化默认的props属性,这是全局调用一次,严格地来说,这不是组件的生命周期的一部分。在组件被创建并加载时,首先调用 constructor 构造器中的 this.state = {},来初始化组件的状态。

  • 组件生命周期分为三部分:

    • 组件创建阶段:特点,只执行一次;

    componentWillMount: 组件将要被挂载,此时还没有开始渲染虚拟DOM
    render:第一次开始渲染真正的虚拟DOM,当render执行完,内存中就有了完整的虚拟DOM了
    componentDidMount: 组件完成了挂载,此时,组件已经显示到了页面上,进入运行中的状态

    • 组件运行阶段:特点,根据组件的state和props的改变,有选择性的触发0次或多次;

    componentWillReceiveProps: 组件将要接收新属性,此时,只要这个方法被触发,就证明父组件为当前子组件传递了新的属性值;
    shouldComponentUpdate: 组件是否需要被更新,此时,组件尚未被更新,但是,state 和 props 肯定是最新的
    componentWillUpdate: 组件将要被更新,此时,尚未开始更新,内存中的虚拟DOM树还是旧的
    render: 此时,又要重新根据最新的 state 和 props 重新渲染一棵内存中的 虚拟DOM树,当 render 调用完毕,内存中的旧DOM树,已经被新DOM树替换了!此时页面还是旧的
    componentDidUpdate: 此时,页面又被重新渲染了,state 和 虚拟DOM 和 页面已经完全保持同步

    • 组件销毁阶段:特点,只执行一次;

    componentWillUnmount: 组件将要被卸载,此时组件还可以正常使用;

总结:

  • componentWillReceiveProps(nextProps)
  • shouldComponentUpdate(nextProps, nextState)
  • componentWillUpdate(nextProps, nextState)
  • render()
  • componentDidUpdate(prevProps, prevState)

路由管理Redux-router

1.装包;yarn add react-router-dom

使用教程:https://reacttraining.com/react-router/web/guides/quick-start

​ 特点: 1.路由也是组件;(视图的一部分)2.分布式配置;3.包含式匹配;(可匹配多个)

HashRouter表示一个路由的根容器,它包含了所有跟路由相关的内容,只需引入一次;(不跳转,不发送请求到后台)

BrowserRouter会跳转、使用HTML5历史API

MemoryRouter>在内存让你的“URL”的历史记录

Switch包裹着路由,只选择其中一个

Route路由规则,有两个属性:path、component

Link表示路由的链接,类似Vue中的、此外在 vue 中有个 router-view 的路由标签,专门用来放置匹配到的路由组件,但在 react-router 中,并没有类似于这样的标签,而是直接把 Route 标签,当作 占位符

Redirect重定向

基本使用:
import {HashRouter,Route,Link,Switch,Redirect} from 'react-router-dom'
<HashRouter>
    <div>
    	<Link to="/">首页</Link>
		<Link to="/news/1">新闻1</Link>
        <Link to="/news/2">新闻2</Link>
        //配置路由规则;添加 exact 属性,表示启用精确匹配模式
        <Switch>
    		<Route path="/" exact component={Cmp1} />
        	<Route path="/news/:id" component={Cmp2} />
        	//404
        	<Route component={NoMatch}></Route>	
            <Redirect to="/"></Redirect>
    	</Switch>
    </div>
    
    function News({match,history,location}){
        //match-参数获取等路由信息;history-导航;location-url定位
        return <div>
        	{match.params.id}
            <button onClick={history.goBack}>后退</button>
            <button onClick={()=>history.push('/')}>回到首页</button>
        </div>
    }
</HashRouter>

路由守卫:定义可以验证的高阶组件

function PrivateRoute({component:Component,...rest}){
    return(
    	<Route {...rest} 
			render={props=>auth.isLogin ? 
                    (<Component {...props}/>):
                    (<Redirect to={pathname:"/login",
                     			   state:{from:props.location.pathname}
					})
				  }
    	   )
}
//模拟接口;
auth={
    isLogin:false,
    login(cb){
        this.isLogin:true;
        setTimeout(cb,300)
    }
}
//登录组件;
class Login extends Component{
    state={isLogin:false};

	login=()=>{
        auth.login(()=>{
            this.setState({isLogin:true})
        })
	}
}

数据交互

1. fetch
用法如下:
async componentDidMount(){
    let res = await fetch('/data/1.json');
    let data = await res.json();
    ...//业务逻辑
}
2. axios

装包–>引入

async componentDidMount(){
    try{
        let {data} = await axios.get('/data/1.json');
        ...//业务逻辑
    }catch(e){
        alert('..')
    }
}

【重点】高阶组件

高阶组件:定义一个函数,传入一个组件,返回另外一个组件,返回的另外一个组件包裹了传入的组件。

分类:属性代理高阶组件,反向继承高阶组件。

作用:代码复用,渲染节时。

// 例1:高阶函数
function hello(){
    console.log('hello I love React')
}

function WrapperHello(fn){
    return function(){
        console.log('before say hello')
        fn()
        console.log('after say hello')
    }
}
hello = WrapperHello(hello)
hello()

//例2:属性代理
function WrapperHello(Comp){
    class WrapComp extends React.Component{
        render(){
            return (<div>
                <p>这是HOC高阶组件特有的元素</p>
                <Comp name='text' {...this.props}></Comp>
            </div>)
        }
    }
    return WrapComp
}
WrapperHello(
  class Hello extends React.Component{
      render(){
          return <h2>hello I love React&Redux</h2>
      }
  }
)

//例3:反向继承
function WrapperHello(Comp){
    class WrapComp extends Comp{
            componentDidMount(){
                console.log('高阶组件新增的生命周期,加载完成')
            }
            render(){
                return <Comp></Comp>
            }
    }
    return WrapComp
}
WrapperHello(
  class Hello extends React.Component{
      render(){
          return <h2>hello I love React&Redux</h2>
      }
  }
)

装饰器(Decorator)

//定义一个函数,也就是定义一个Decorator,target参数就是传进来的Class。
//这里是为类添加了一个静态属性
function testable(target) {
  target.isTestable = true;
}

//语法:只要Decorator后面是Class,默认把Class当成参数隐形传进Decorator,
//类似testable(MyTestableClass)
@testable
class MyTestableClass {}

console.log(MyTestableClass.isTestable) // true

//定义一个组件
class Home extends React.Component {
    //....
}
//以往从状态树取出对应的数据,让后通过props传给组件使用通过react-redux自带的connect()方法
export default connect(state => ({todos: state.todos}))(Home);

//使用装饰器后如下:
@connect(state => ({ todos: state.todos }))
class Home extends React.Component {
    //....
}

中间件redux-sage

处理异步请求;

import { takeEvery , put} from 'redux-saga/effects'
import axios from 'axios';
import { GET_INIT_LIST } from './actionType';
import { initListAction} from './actionCreator';
 
function* todolist() {
    //异步获取数据
    try{
        const res = yield  axios.get('api/list');
        const action=initListAction(res.data);
        yield put(action);
    }catch(e){
        console.log('list.json 网络请求失败')
    }
}
//当type为GET_INIT_LIST的action触发时,调用todolist函数--类似是个监听器
function* mySaga() {
  yield takeEvery(GET_INIT_LIST, todolist);
}
 
export default mySaga;

//创建store时配置redux-sage
import { createStore, applyMiddleware ,compose} from 'redux';
import reducer from './reducer'
import createSagaMiddleware from 'redux-saga'     //核心函数
import mySaga from './sagas'

//1.创建中间件
const sagaMiddleware = createSagaMiddleware();
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?   		window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;
const enhancer = composeEnhancers(applyMiddleware(sagaMiddleware));
//2.应用中间件
const store = createStore(reducer, enhancer);
sagaMiddleware.run(mySaga)
export default store;

//组件中和之前一样;
componentDidMount(){
    const action=getInitListAction();
    store.dispatch(action);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值