react学习

简介

  • 起源于Facebook
  • 与传统mvc的关系:轻量级的视图层库,将视图抽象成组件

特点

  • 声明式设计
  • 高效  通过虚拟dom,减少真实dom交互
  • 灵活  适配已知的库或框架
  • jsx     js语法扩展
  • 组件  代码可复用
  • 单向响应数据流  减少重复代码,比传统绑定简单

虚拟dom

  • 真实dom操作消耗性能,react把真实dom转化为js对象树(就是个对象)

ps:真实的dom属性太多了,而且频繁的操作视图重绘回流,而且进行了diff算法之后,将部分真正要改变的dom重绘,避免了大幅度修改。我们的目的是更快!更快!

安装

npx不能用的话,升级nodejs版本

npx create-react-app my-app
 npm start //启动项目
 npm test //测试
 npm run build //打包上线

目录

  • README.md            项目说明文档
  • node_modules          所有的依赖安装的目录
  • package-lock.json     锁定安装时的包的版本号,保证团队的依赖能保证一致。
  • package.json             配置文件
  • public                         静态公共目录
  • src                              开发用的源代码目录
//src-index.js
//创建小demo

import React from "react"; //jsx 17版本之后默认引入,可不写
import ReactDom from "react-dom";//react渲染到页面

//render方法 将组件渲染指定节点
//参1:用jsx语法写的html
//参2:指定节点
ReactDom.render(
1111
, document.getElementById('root'))

然后就报错啦!!!

因为我安装的是18.2.0版本,已经不支持 react-dom

 警告:ReactDOM。渲染在React 18中不再被支持。请使用createRoot。在你切换到新的API之前,你的应用程序会像运行React 17一样运行。

然后就去官网尝试新的写法

import { createRoot } from "react-dom/client";

// 清除现有的 HTML 内容
document.body.innerHTML = '
'; // 渲染你的 React 组件 const root = createRoot(document.getElementById("app")); root.render(

Hello, world

);

页面就成功出现想要内容啦

jsx

所谓的JSX其实就是Javacript 对象,所以使用 React 和JSX的时候一定要经过编译的过程:
JSX一使用react构造组件,bable进行编译->JavaScript对象 - ReactDom.render中->DOM元素一>插入页面

//将jsx语法转化为react对象
ReactDom.render(React.createElement("div",{
    id:"aaa",
    class:"bbb",
},"111111111"),document.getElementById("root"))

组件

React 组件必须以大写字母开头

函数组件

function FunComponent() {
  return (
    

Welcome to my app

); } export default FunComponent;

class类组件 

  • this为undefined (babel翻译时自动开启了严格模式组件

//新建js文件
import React from "react";
class App extends React.Component {
  render() {
    return 
hello,react
; } } export default App;
  • this为实例对象
  • render在类的原型对象上,实例使用

引入在index.js,进行渲染 

import { createRoot } from "react-dom/client";
import App from './01-base/01-class类组件'
document.body.innerHTML = '
'; const root = createRoot(document.getElementById("app")); root.render();

执行root.render(<组件/>)之后发生了什么呢?

  1. react解析该组件标签,找到该组件
  2. 发现组件时类创建,new该实例,调用实例上的render方法
  3. 将render返回的虚拟dom转为真实dom渲染在页面上

组件实例三大属性 

三大属性一般用在有实例的类组件身上,由于函数可以接受参数,函数组件可以通过传参的方式接受props

state

存储数据,数据改变,页面随着数据改变。

import React from "react";
class App extends React.Component {
  constructor(props) {
    super(props);
    //初始化状态
    this.state = {
      isHot: false,
      wind: "大风",
    };
    //解决函数this问题
    this.changeWeather=this.changeWeather.bind(this)
  }
  //调用的时候通过原型链查找
  changeWeather() {
    // const { isHot } = this.state;
    console.log(this);//局部函数开启了严格模式 undefined
  }
  render() {
    const { isHot } = this.state;
    return (
      
今天的天气是
); } } export default App;

简写

import React from "react";
class App extends React.Component {
  state = {
    isHot: false,
    wind: "大风",
  };
  //直接使用父层的this
  changeWeather = () => {
    const { isHot } = this.state;
    this.setState({ isHot: !isHot });
  };
  render() {
    const { isHot } = this.state;
    return (
      
今天的天气是
); } } export default App;

props

  • 只读
//父组件传值
root.render();
//简写
//const p = { data: "2023-5-17", data1: "2023-5-18" };
//root.render();

//子组件接收
render() {
    const { data,data1 } = this.props;
    return (
      
今天 {data} 明天 {data1}
); }

限定props

//父组件
function speak() {
  console.log("你好呀");
}
const p = { data: "2023-5-17", data1: "2023-5-18", sun: true };
root.render();

//子组件
import PropTypes from "prop-types";
//限定标签类型,必要性
  static propTypes = {
    data: PropTypes.string.isRequired, //isRequired 必传
    data1: PropTypes.string,
    speak: PropTypes.func, //函数类型
    sun: PropTypes.bool, //布尔类型
  };
  //标签属性的默认值
  static defaultProps = {
    data1: "明天就是明天啊",
  };

函数组件

import PropTypes from "prop-types";

function FunComponent(props) {
  const { name, sex, age } = props;
  return (
    

Welcome to my app

name: {name}

sex: {sex ? "女" : "男"}

age: {age}

); } //限定标签类型,必要性 FunComponent.propTypes = { name: PropTypes.string.isRequired, //isRequired 必传 sex: PropTypes.bool, age: PropTypes.number, }; //标签属性的默认值 FunComponent.defaultProps = { name: "明天就是明天啊", }; export default FunComponent;

refs

字符串形式

获取到的是真实dom元素(虚拟dom转化成真实dom的节点)

//使用refs


//获取refs
 changeWeather = () => {
    const { but } = this.refs;
    console.dir(but.innerText);
  };

官网不建议使用字符串形式,可能会影响性能

回调形式(箭头函数)

//箭头函数this指向父元素,指向类的实例  
(this.weather = e)}> //内联函数 今天的温度是
changeWeather = () => { console.log(this.weather); };

ref回调函数是以内联函数方式定义的,在更新过程中执行两次,第一次传入参数null,第二次传入参数dom元素,因为每次渲染会创建一个新的函数实例,react清空旧的ref并创建新的。通过ref回调函数定义成class绑定函数避免这种问题

//绑定函数 
今天的温度是
//绑定节点 saveElement=(e)=>{ this.input1=e } //使用节点 console.log(this.input1);

createRef

//本身是个函数,调用后返回一个容器,该容器可以访问存储器ref标识的节点 
myRef=React.createRef()

//绑定ref
今天的温度是
//使用 console.log(this.myRef.current);

事件处理

  1. 通过onXxx属性指定事件处理(注意大小写)
    1. React使用的是自定义(合成)事件,而不是使用的原生DOM事件
    2. React中的事件是通过事件委托方式处理的(委托给组件最外层的元素),元素会冒泡到父元素身上,用父元素监听多个子元素更加高效
  2. 通过event.target得到发生事件的DOM元素对象
    
    
    changeWeather = (e) => {
        console.log(e);
    }

受控组件&非受控组件 

非受控组件 

页面中所有输入类的dom,现用现取。

现用现取:比如说点击事件之后,通过回调函数我获取e.属性,获取的是最新的值

class Login extends React.Component {
  loginFromSubmit = (e) => {
    //表单提交跳到新地址,或者刷新页面
    e.preventDefault();
    const { username, password } = this;
    console.log(username, password);
  };
  render() {
    return (
      
username: (this.username = r)} />
password: (this.password = r)} />
); } }

受控组件 

页面中所有输入类的dom,将输入内容直接维护到状态中,取值的话直接到状态里取

不就是v-model嘛~,不过值要自己监听触发onChange事件

import React from "react";
class Login extends React.Component {
  state = {
    username: "",
    password: "",
  };
  loginClick = (e) => {
    e.preventDefault();
    let { username, password } = this.state;
    console.log(username, password);
  };
  nameChange = (e) => {
    this.setState({ username: e.target.value });
  };
  passwordChange = (e) => {
    this.setState({ password: e.target.value });
  };
  render() {
    return (
      
username:
password:
); } } export default Login;

高阶函数&函数柯里化

高阶函数

如果一个函数符合下面2个规范中的任何一个,那该函数就是高阶函数。

  • 若A函数,接收的参数是一个函数,那么A就可以称之为高阶函数。
  • 若A函数,调用的返回值是一个函数,那么A就可以称之为高阶函数。
 // 相对于受控组件那段代码的高阶函数
 formChange = (type) => {
    return (e) => {
      //返回一个函数
      this.setState({ [type]: e.target.value });
    };
  };
  render() {
    return (
      
username:
password:
); }

函数柯里化

通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式。

函数柯里化详解_Boale_H的博客-CSDN博客

js面试高频题:函数柯里化的实现(彻底弄懂)_Coding101的博客-CSDN博客

ps:Array.prototype.slice.call(arguments)将伪数组转为数组 

生命周期

组件从 创建到销毁的过程 就是生命周期,过程中的不同阶段会触发不同的钩子函数

  • 初始化阶段
    • componentWillMount:组件将要初始化;render前最后一次修改状态
    • render:渲染组件 
    • componentDidMount:组件渲染完成真实dom;可以修改dom,进行异步请求
  • 运行中阶段
    • componentWillReceiveProps:父组件修改属性触发
    • shouldComponentUpdate:组件是否更新;若返回false可以阻止render调用
    • componentWillUpdate:组件将要更新;不能修改属性和状态
    • render:渲染组件;只能访问this.props和this.state,不允许修改状态和dom输出
    • componentDidUpdate:组件更新完成;可以修改dom
  • 销毁阶段
    • componentWillUnmount:组件将要卸载;可以进行清理工作,清除定时器和事件监听

你可能感兴趣的:(react.js,学习,javascript,前端)