React的一些事


# 在简单的页面使用 react (开发环境)


 <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
 <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
 

# 生产环境 官方建议通过cdn引入react时、最好设置 crossorigin 属性、即允许该请求跨域访问

<script src="https://unpkg.com/react@16/umd/react.production.min.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js" crossorigin></script>

# 引入 babel 解析 jsx 语法

<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
# 官网入门案例 不使用 JSX

class Hello extends React.Component {
  render() {
    return React.createElement('div', null, `Hello ${this.props.toWhat}`);
  }
}

ReactDOM.render(
  React.createElement(Hello, {toWhat: 'World'}, null),
  document.getElementById('root')
);

# 使用 jsx

class Hello extends React.Component {
  render() {
    return <div>Hello {this.props.toWhat}</div>;
  }
}

ReactDOM.render(
  <Hello toWhat="World" />,
  document.getElementById('root')
);

# 每个 JSX 元素只是调用 React.createElement(component, props, ...children) 的语法糖。

jsx 的简介


# jsx 语法规则
- 定义虚拟 DOM 时、不要写引号
- 标签中混入 js 表达式时要用 {}
- 样式的类名指定不要用 class 要用 className
- 内联样式、要用 style={{key: value}} 的形式去写
- 只能有一个根标签
- 标签必须闭合
- 标签首字母
	- 若小写字母开头、则将标签转换为 html 中的同名元素、如果 html 没有该标签对应的同名元素、则报错
	-若以大写字母开头、React 则去渲染对应的组件、没有组件则报错

# 模块化只是 js 的模块化、而组件化则是 html + css + js + 静态资源的模块化
	 

React 的函数式组件

 function Hello() {
   return <h1>hello react</h1>;
 }
 ReactDOM.render(<Hello/>, document.getElementById("root"));

React 的类式组件

class Hello extends React.Component {

 render() {
        return (
            <div>
                <h1>hello react</h1>
            </div>
        );
    }
    
}

ReactDOM.render(<Hello />, document.getElementById("root"));

# 什么是简单组件与复杂组件
- 复杂组件:有 state 的组件
- 简单组件:没有 state 的组件

# 组件的三大属性
- state
- props
- refs

# state
- state 是组件对象最重要的属性、值是对象
- 组件被称为状态机、通过更新组件的 state 来更新对应页面的显示(重新渲染组件)

# 注意:
- 组件中 render() 方法中定义的 this 为组件实例对象
- 组件自定义方法中的 this 为 undefined、如何解决?
- 1、强制绑定 this 2、箭头函数
- 状态数据不能直接修改或更新、而要通过 this.setState() 方法更新

# props 
- props 属性在组件的构造函数中传入、并绑定到实例对象上
- props 是只读属性

# refs
- 

函数式组件使用 props

 function Person(props) {

    let {name, age, gender} = props;

    return (
        <ul>
            <li>{name}</li>
            <li>{age}</li>
            <li>{gender}</li>
        </ul>
    )
}
ReactDOM.render(<Person name="vivi" age={19} gender="男" />, document.getElementById("root"))

Ref

class Hello extends React.Component {

   // 一个容器只能存放一个 dom 节点
    myRef = React.createRef();

    showData = () => {
        let { hello } = this.refs;
        console.log(hello.value);
        console.log(this.hello.value);
        console.log(this.myRef.current.value);
    }

    render() {
        return (
            <div>
                {/*字符串形式的 ref*/}
                <input type="text" ref="hello" onBlur={this.showData} />
                {/*回调形式的 ref c 就是 input 的真实 dom 节点对象*/}
                <input type="text" ref={c => this.hello = c} />
                {/*createRef 形式的 ref*/}
                <input ref={this.myRef} type="text"/>
            </div>
        );
    }

}

ReactDOM.render(<Hello />, document.getElementById("root"));

React 中的事件

# 可以通过 event.target 获得发生事件的 dom 对象

# 不要过度使用 ref

class Hello extends React.Component {

    showDOM = (event) => {
        console.log(event.target);
        //  <input type="text" />
    }

    render() {
        return (
            <div>
                <input type="text" onClick={this.showDOM}/>
            </div>
        );
    }
}

React 收集表单数据

class Login extends React.Component {

	toLogin = (event) => {
	    // 阻止表单默认提交
	    // event.preventDefault();
	    let {username, password} = this;
	    console.log(username.value, password.value);
	    return false;
	}
	
	render() {
	    return (
	        <div>
	            <form action="" method="get" onSubmit={(event) => event.preventDefault()}>
	                <input ref={c => this.username = c} type="text" placeholder="请输入用户名" name="username" />
	                <input ref={c => this.password = c} type="text" placeholder="请输入密码" name="password" />
	                <button onClick={this.toLogin}>提交</button>
	            </form>
	        </div>
	    );
	}
}

# 什么是高阶函数?
- 函数的参数是一个函数
- 函数的返回值是一个函数
- 满足以上条件的任意函数都可以称为高阶函数

# 函数柯里化:
- 通过函数继续返回函数的形式、实现多次接收参数、最后统一处理的编码形式
- 比如 axios

高阶函数收集表单数据

class Login extends React.Component {

  toLogin = (dataType) => {
       // 高阶函数的柯里化
       return (event) => {
           if (dataType === 'username') {
               console.log('username', event.target.value);
               return;
           }
           if (dataType === 'password') {
               console.log(event.target.value);
           }
       }

   }


   render() {
       return (
           <div>
           <form action="" method="get" onSubmit={event => event.preventDefault()}>
               <input onChange={this.toLogin('username')} type="text" placeholder="请输入用户名"/>
               <input onChange={this.toLogin('password')} type="text" placeholder="请输入密码"/>
               <button>提交</button>
           </form>
           </div>
       );
   }
}

ReactDOM 卸载组件

 ReactDOM.unmountComponentAtNode(document.getElementById("root"));

React 生命周期钩子

// 组件将要接受新的 props
componentWillReceiveProps(nextProps) {
    
}

// 构造器
constructor(props) {
    super(props);
    this.state = {};
}

// 组件将要挂载、render() 还未调用
componentWillMount() {
    
}

// 渲染组件
render() {
}

// 组件挂载完毕、render() 调用完毕
componentDidMount() {
    
}

// 组件将要卸载
componentWillUnmount() {
    
}

# this.setState() 一调用就会调用父类的 shouldComponentUpdate(nextProps, nextState) 方法

# 强制更新的方法 this.forceUpdate();

# 注意:React 17.0 废弃了三个生命周期函数
- componentWillMount()
- componentWillUnmount()
- componentWillUpdate()

# 新增了两个生命周期函数
- static getDerivedStateFromProps(props);
- static getSnapshotBeforeUpdate();

React 脚手架配置代理实现跨域

# src 下新建一个文件、文件名必须叫 setupProxy.js
const proxy = require('http-proxy-middleware')

module.exports = function (app) {
    app.use(
        proxy('/api1', {
            target: 'http://localhost:5000',
            changeOrigin: true,
            pathRewrite: { '^api1': '' },
        })
    )
}

兄弟组件间的通信方式

消息的订阅与发布

- yarn add pubsub-js

import PubSub from 'pubsub-js';
// A 组件发布消息
PubSub.publish('hello', {name: 'vivi', age: 20});
// B 组件接收消息
PubSub.subscribe('hello', (_, data) => {
    console.log(data); // {name: 'vivi', age: 20}
});
// 取消订阅
PubSub.unsubscribe(this.token);

相关理解

# SPA 的理解
- 单页 web 应用 (single page web application)
- 整个应用置于一个完整的页面
- 点击页面中的链接不会刷新页面、只会做页面的局部更新
- 数据都需要通过 ajax 请求获取、并在前端异步展现

# 什么是路由?
- 一个路由就是一个映射关系(key: value)
- key 为路径、value 可能是 function 或 component


React 路由传参

# 嵌套路由
- 注册子路由写上父路由的 path 值
- 路由匹配是按照路由的注册顺序进行的


// params 组件传参
<Link to={`/home/page/${user.id}`}>首页</Link>
// 声明接受参数
<Route path="/home/page/:id" component={Home}/>

// 在 Home 组件中获取路由参数
let {params} = this.props.match;
console.log(params); // {id: 1}

// 向路由组件传递search 参数
<Link to={`/home/page?id=${user.id}`}></Link>
// search 参数无需声明接收参数
<Route path="/home/page/" component={Home}/>

// 向路由组件传递 state {} 参数
<Link replace to={{pathname: '/home/page', state: {id: user.id, name: user.name}}}>首页</Link>
// 无需声明接收
<Route path="/home/page" component={Home}/>
// Home 组件中接受 state 参数
let {id, name} = this.props.location.state;

编程式路由导航

- history.push('/home/page', {id: user.id, name: user.name});
- history.replace();
- history.goBack();
- history.goForward();
- history.go(n);

包装普通组件为路由组件

import {withRouter} from 'react-router-dom';

export default withRouter(Header);

# BrowserRouter 与 HashRouter 的区别

- 底层原理不一样
* BrowserRouter 使用的是 H5 的 history API 不兼容IE9以下的版本
* HashRouter使用的 URL 的哈希值
- url 表现形式不一样
* BR 路径中没有 # 号 而 HR 的路径中存在 # 号
- 刷新后对路由 state 参数的影响
* BR 不会有任何影响 因为 state 保存在 history对象中
* HR 刷新后会导致路由参数 state 的丢失
- HR 可以用于解决一些路径错误相关的问题


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值