React

笔记来自
github实例
immutable的学习
面试题
手写实现react

需要学的知识有

  • 脚手架安装启动
  • JSX组件基础使用,修改数据,for,if,事件...
  • JSX组件传参通信
  • 生命周期
  • 路由
  • Redux
  • React-Hooks
  • 打包发布
  • 首屏优化,Next服务器渲染

安装脚手架

  • 普通的命令
# 一个电脑安装一次就好
cnpm install -g create-react-app
# 创建项目
create-react-app 【name】

cnpm install
npm start
  • 脚手架有什么
// 自带了Ject测试插件
// eslint代码规范检查
// PWA功能的 manifest.json 和 serviceWorker.js 文件

// 入口文件 index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
// 这是一个组件
import App from './App';
// import * as serviceWorker from './serviceWorker';

// 这个就是jsx写法
// 后面等引入了路由和redux后得修改,具体往下看
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

// PWA没用注释了
// serviceWorker.unregister();

脚手架设置

  • 跨域请求
// 安装
npm i http-proxy-middleware --save

// 在src下创建setupProxy.js,名字固定
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
    app.use('/api', 
        createProxyMiddleware({ 
            target: 'http://xxx.pdt1997.top/', 
            changeOrigin: true 
        })
    );
}

// axios安装设置查看【axios和fetch】笔记
  • 打包文件的配置查看【React打包配置】笔记

基础使用

  • 组件的结构
// vue是一个template+script+style组成的
// 而react是一个js文件加一个css文件,建议创建一个文件夹装起来使用,再一起装进pages文件夹里比较规范

// app.js
import React from 'react';
import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

// 上面的写法不规范,应该改成下面的写法
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

// 这里面的一级属性都不需要逗号结束
class App extends Component{
    // 这个就是vue的data
    state = {
        msg: "测试",
    }
    render(){
        return (
            <div className="App">
                <header className="App-header">
                    <div>{this.state.msg}</div>
                    <img src={logo} className="App-logo" alt="logo" />
                    <p>
                        Edit <code>src/App.js</code> and save to reload.
                    </p>
                    <a
                        className="App-link"
                        href="https://reactjs.org"
                        target="_blank"
                        rel="noopener noreferrer"
                    >
                        Learn React
                    </a>
                </header>
            </div>
        );
    }
}

export default App;
  • 修改数据,在react应该叫修改状态state
// 不要直接修改 state(状态)
// this.state.comment = 'Hello';
// 上述代码并不会重新渲染组件,需要使用this.setState()代替:
// 正确操作
this.setState({
  comment: 'Hello'
});

//  state(状态) 更新可能是异步的
// React 为了优化性能,有可能会将多个 setState() 调用合并为一次更新。
// 因为this.props和this.state 可能是异步更新的,你不能依赖他们的值计算下一个state(状态)
// this.setState({
  // counter: this.state.counter + this.props.increment,
// });
 

// 我们并不能通过上述代码得到想要的值
// 为了弥补这个问题,使用另一种 setState() 的形式,接受一个函数
// 这个函数将接收前一个状态作为第一个参数,应用更新时的 props 作为第二个参数,代码如下:
this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment
}));
  • 事件绑定
class Toggle extends React.Component {
  state = {
    isToggleOn: true,
  }
  // 一定要箭头函数,否则没有this
  handleClick = (e) => {
    // 这就是修改state方法
    this.setState({
      isToggleOn: !this.state.isToggleOn
    });
  }
  // event永远在最后一位参数
  handleClick2 = (msg,e) => {
    console.log(msg)
  }
  render() {
    return (
      <button onClick={this.handleClick('test')}>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
      // 如果要传参就得加上bind(this,参数)
      <button onClick={this.handleClick2.bind(this,'test')}>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}
  • 条件渲染
// 三元
render() {
  return (
    <div>
      { this.state.isLoggedIn ? (
        <LogoutButton onClick={this.handleLogoutClick} />
      ) : (
        <LoginButton onClick={this.handleLoginClick} />
      ) }
    </div>
  );
}

// 是否 &&
render() {
  return (
    <div>
      <h1>Hello!</h1>
      { unreadMessages.length > 0 &&
        <h2>
          您有 {unreadMessages.length} 条未读信息。
        </h2>
      }
    </div>
  );
}
  • 列表渲染
render() {
  return (
    <div>
      { 
        this.state.selectedProList.map((item, index) => {
          return <li key={index} className="selected-pro-item ellipsis">{item.product_name}x{item.selectNum}</li>
        })
      }
    </div>
  );
}

JSX组件传参通信

  • 所有的数据和方法都在this.props对象里
  • 父传子
// 父
render(){
   return(
         <Child {...person} />
         <Child txt={this.state.message}/>
   )
}
// 子
render(){
   return(
         <div>{this.props.name}</div>
         <div>{this.props.age}</div>
         <div>{this.props.message}</div>
   )
}
  • 子传父,子组件调用父组件的方法进行数据的传递
// 父
getDatas(msg){
    //把子组件传递过来的值赋给this.state中的属性
    this.setState({
      mess: msg
    });
}
render(){
    return (
         <Son getdata={this.getDatas.bind(this)}></Son>
         <div>展示数据:{this.state.mess}</div>
    );
}

// 子
handleClick(){
    //通过props属性获取父组件的getdata方法,并将this.state值传递过去
    this.props.getdata(this.state.inputValue);
}
render(){
    return (
        <button onClick={this.handleClick.bind(this)}>点击获取数据</button>
    );
}
  • 兄弟,组件A传值父组件,父组件传值组件B,就是把上面的
// 父
getDatas(msg){
    //把子组件传递过来的值赋给this.state中的属性
    this.setState({
      mess: msg
    });
}
render(){
    return (
         <SonA getdata={this.getDatas.bind(this)} />
         <SonB mess={mess} />
    );
}
  • 组件传值可以使用prop-type这个插件进行格式判断和默认值使用
  • 跟vue一样,数据之间的传递非常的麻烦,应该是用第三方的数据储存插件redux

生命周期

  • 核心 constructor 》componentWillMount 》render 》componentDidMount
class Button extends Component {
  state = { 
     data: 0 
  }
  setNewNumber() {
    this.setState({data: this.state.data + 1})
  }
  render() {
      return (
         <div>
            <button onClick = {this.setNewNumber.bind(this)}>INCREMENT</button>
            <Content myNumber = {this.state.data}></Content>
         </div>
      );
    }
}
 
 
class Content extends Component {
  componentWillMount() {
      // 在渲染前调用,在客户端也在服务端
      console.log('Component WILL MOUNT!')
  }
  componentDidMount() {
      //  在第一次渲染后调用,只在客户端
      //  初始化请求写在这
      //  为什么不写在componentWillMount 
      //  因为componentWillMount方法的调用在constructor之后,在render之前,在这方法里的代码调用setState方法不会触发重渲染,所以它一般不会用来作加载数据之用,它也很少被使用到
      console.log('Component DID MOUNT!')
  }
  componentWillReceiveProps(newProps) { 
      console.log('Component WILL RECEIVE PROPS!')
  }
  shouldComponentUpdate(newProps, newState) {
      // 这个是数据更新前会执行的方法,如果返回false,页面不会更新
      // 这个的用处特别的大,如果你在render里打印一下666,会发现每次数据更新实际都调用了无数次的render,非常的损耗性能
      // 当然必须要的不能阻止,如果是前后一样的数据应该避免render的更新,所以在这里可以对两个参数进行一致性判断,一样则返回false
      // 可是这个数据的判断就是深拷贝,深拷贝的性能也是非常的离谱,也不好完成
      // 所以在这里应该使用插件,也就是最上的那个immutable插件
      // 引用这个插件后,整个项目的数据都应该改用插件里使用的【List和Map和Set和其他】,按照他要求的方法进行数据变化
      // 具体自行学习
      return true;
  }
  componentWillUpdate(nextProps, nextState) {
       console.log('Component WILL UPDATE!');
  }
  componentDidUpdate(prevProps, prevState) {
       // 数据更新调用
       console.log('Component DID UPDATE!')
  }
  componentWillUnmount() {
       // 销毁前
       console.log('Component WILL UNMOUNT!')
  }
 
  render() {
     return (
        <div>
          <h3>{this.props.myNumber}</h3>
        </div>
     );
  }
}
posted @ 2020-06-09 10:01  一个年轻淫  阅读(154)  评论(0编辑  收藏  举报