Skip to content
本页目录

一文让你快速上手React18,最直白知识点总结

Excerpt

一文让你快速上手React18,最直白知识点总结 0、环境配置 1、使用 create-react-app 快速创建开发环境 npx create-react-app my-app --templat


一文让你快速上手React18,最直白知识点总结

本文是个人自己学习React后的基础知识总结,是为了加深印象,以及后续项目中某些知识点记忆不清晰,能够快速查找到实用案例;希望对学习React的朋友们带来些许帮助,谢谢~

1、JSX插值表达式

jsx
 1-1{/* 🔔// string number 正常显示 */}
 <h1>{'hello React'}</h1>
 <h1>{73}</h1>

 1-2{/* null undefined  boolean  🔔不显示*/}

 1-3{/* 💥对象不能直接放在插值表达式中,会报错 */}
 ex: const obj = {name:'zs'}
   {obj} => 报错
   {obj.name} => 🆗
  
 1-4{/* 🔔 数组中的每项元素,都会当做一个dom节点渲染出来 */}
  //  数组
  const list = [<div>1</div>, <div>2</div>, <div>3</div>]
  <h1>{list}</h1> => 1
       2
       3

 1-5{/* 1. 💥 函数本身也属于对象,函数本身不能放在插值表达式中 */}
   {/* 通常放函数的调用,函数的返回值也不能对象 */}
   {hello()}

 1-6{/*  三元 */}
   <h2>{isShow ? 'show' : '不显示'}</h2>

 1-7{/* 逻辑 */}
   <h3>{isShow && '显示'}</h3>

 1-8{/* 💥 JSX本身也可以当做表达式放在插值符号中,往往配合其它的使用方式 */}
   <h4>{<span>123</span>}</h4>

2、条件、列表渲染

  • if else 语句

    javascript
    function loadData() {
     if (isLoading) {
     return <h1>加载中...</h1>;
      } else {
     return <div>加载完毕</div>;
      }
    }
    
    {loadData()}
    
  • 三元表达式

    text
    {isLoading ? <h1>加载中...</h1> : <h3>加载完毕</h3>}
    
    
  • 逻辑运算符

    text
    {isLoading && <h1>加载中...</h1>}
    {!isLoading && <div>加载完毕</div>}
    
    
  • 列表渲染,类似v-for

    javascript
    // 方法一
    const list = ['萝卜', '白菜', '橘子'];
    
    {list.map((item, index) => { // render 内部
      return (
      <h1
       // 💥key的作用:和v-for的key作用一模一样,都是提高更新效率
       // 🔔key的口诀:有id 用id ,没id用索引
       key={index}
      >
        {item}
      </h1>
       );
    })}
    
    // 方法二 
    const list = ['萝卜', '白菜', '橘子'];
    const listNode = list.map((item, index) => {
     return <h1 key={index}>{item}</h1>;
    });
    
    {listNode} // render 内部
    
    

3、行内样式

stylus
语法:style= {{css属性名:属性值}}

{/* 💥 React中不支持css属性连字符, 👍要求使用驼峰 */}
{/* 💥 px单位可以省略,值直接写数字 */}
<h1 style={{ color: 'red', fontSize: 12 }}>我想红</h1>

4、组件类型(函数式组件/类组件)

  • 函数式组件

    javascript
    // 基本要求
    // 1.1 组件名称首字母必须大写
    // 1.2 函数必须返回一段JSX,如果不需要渲染任何内容,返回一个null
    
    // ✅ 组件
    function Hello() {
     return null;
    }
    
    {/* 使用上:💥React对大小写敏感 */}
    <Hello></Hello>
    
    
  • 类组件

    javascript
    // 基本要求
    // 1. 组件名字必须大写字母开头
    // 2. render函数中必须返回一段JSX,如果不需要渲染任何内容,返回null
    // 3. 必须有render函数,否则报错,render函数类似函数式组件的语法
    
    // ✅ 组件
    class Hello extends React.Component {
     render() {
     return null;
      }
    }
    
    {/* 使用上:💥React对大小写敏感 */}
    <Hello></Hello>
    
    
    • extend继承
    javascript
    // class的作用: 创建对象
    // 💥 属性 = 值
    
    class Programer {
     gender = '';
    
     writeCode() {
     console.log('我代码写的贼6  ----->  ');
      }
    }
    
    // extends的作用:基础父类(爸爸)所有的属性和方法
    // 目的:复用相同的属性和方法,减少创建对象时消耗的内存
    class FrontEnd extends Programer {
     //  自动获得爸爸所有的属性和方法
     name = 'fe';
    }
    
    

5、状态 state

javascript
// 基本语法:state = {数据变量名: 值}, 可以声明多个数据
 state = {
 count: 100,
 msg: 'hello React',
  };

// 使用:获取state: 通过this.state.xxxx访问数据
// 💥 this 指向组件实例对象,与Vue类似
render(
  return (
  <h1>
    我是App - {this.state.count} - {this.state.msg}
  </h1>
  );
)

6、事件绑定

javascript
// 基础语法:on+大写驼峰事件名 = {函数名}

// 常见的两种写法:
// 👍1. 少量代码: 使用一个箭头函数
onClick={() => alert('123')}

onClick={this.handleClick}

// 注意:
// 1. 不能加():❌ onClick={this.handleClick()}
//  事件必须接受一个函数,而且要放在花括号中
// 2. 不能放在字符串中:❌onClick="alert('123')"

7、获取事件对象

javascript
// 获取事件对象 event
  <a
   // 💥 绑定事件的默认形参就是事件对象event, 类似Vue,
   // 1. onClick={(e) => e.preventDefault()}
   href="http://www.baidu.com"
   onClick={this.handleClick}
  >
   点我跳百度
  </a>
// 多行代码写法
 handleClick(e) {
 e.preventDefault();
 console.log('come here  ----->  ');
  }

8、事件传值

javascript
// 基础语法
onClick={(e) => this.handleClick(e, 2)}

// 自定义事件函数
 handleClick(e, num) {
 // 能够接收到外部传来的值
 console.log('num, e  ----->  ', num, e);
  }

9、修改状态 setState

javascript
// 基础语法:setState({更新的数据: 新的值})
this.setState({ msg: this.state.msg + '123', count: this.state.count + 100 });

// 💥注意:
// React中不可变数据-不允许直接修改state
this.state.count += 100;

this.setState({ count: (this.state.count += 100) });

10、不可变数据(即数组不可用方法修改state)

javascript
// 不可变数据: 不能使用会修改原数据的方法
// 如:push 、concat
// 如:this.state.count++

// ✅setState 新值覆盖旧值
this.setState({ list: [...this.state.list, 5] });

// 注意:
this.state.list.push(5);

11、受控组件

  • 受控组件 => 表单操做方式

    javascript
     <input
       type="text"
       value={this.state.msg}
       // 💥React对表单的事件特殊处理,以后,所有表单的改变事件都用onChange
       onChange={(e) => {
       console.log('e.target.value  ----->  ', e.target.value);
       this.setState({ msg: e.target.value });
        }}
       // 💥 React中的失焦事件为onBlur
       onBlur={(e) => {
       console.log('e.target.value  ----->  ', e.target.value);
        }}
    />
    //
    
  • 常见受控组件

    javascript
    state = {
     name: 'zs',
     intro: '',
     city: '4',
     isSingle: true,
    };
    
    // input 
    <input type="text" value={name} onChange={this.handleChangeName} />
    
    // textarea 文本域
    <textarea value={intro} onChange={this.handleChangeIntro}></textarea>
    
    // select 下拉选择
    <select value={city} onChange={this.handleChangeCity}>
       <option value="1">北京</option>
       <option value="2">上海</option>
       <option value="3">广州</option>
       <option value="4">深圳</option>
    </select>
    
    // checkbox 单选框
    <input type="checkbox" checked={isSingle} onChange={this.handleChangeSingle} />
    

12、ref(获取dom元素、组件实例对象)

javascript
// 1. 创建 ref
 iptRef = React.createRef();
 childRef = React.createRef();

// 2. 绑定给dom元素或者组件
<input
 type="text"
 // 2. 绑定给dom元素或者组件
 ref={this.iptRef}
/>
<Child ref={this.childRef}></Child>
<button onClick={this.handleClick}>点我访问input元素,主动让input获得焦点</button>

// 3. 通过ref对象.current属性来访问
this.iptRef.current.focus();

13、props 组件通讯

  • 基本使用

    javascript
    {/* 1. 传递数据: 给标签加上标签属性和值 */}
    <Child name="zs123" age={18123} gender={'xxxx'}></Child>
    
    // 函数式组件:通过形参接收props
    function Child({ name, age } = props) {
     return (
     <h1>
       我是子组件 - {name} -{age}
     </h1>
      );
    }
    
    // 类组件:通过this.props接收
    class Child2 extends React.Component {
     render() {
     const { name, age } = this.props;
     return (
      <div>
      <h1>{name}</h1>
      <h1>{age}</h1>
      </div>
       );
      }
    }
    
    
  • props的三个特点

    javascript
    1. props不必先定义后使用
    2. props可以传递任意数据类型
      number string null undefined boolean object
      🔔 function JSX
    3. props是只读的 - 类似vue中的单项数据流(修改需要调用父组件内的方法修改)
    
    
  • 父传子

    javascript
    // 父组件
     state = {
     money: 1000,
      };
    
    // 父传子
    <Child money={this.state.money}></Child>
    
    // 子组件接收展示
    class Child extends React.Component {
     render() {
     const { money } = this.props;
     return (
      <div>
      <h1>爸爸给我钱了: {money} </h1>
      </div>
       );
      }
    }
    
    
  • 子传父

    javascript
    // 父组件内部定义修改state的方法
    // 1. 父组件内定义一个函数
    handleCost = (num) => {
     console.log('num  ----->  ', num);
     this.setState({ money: this.state.money - num });
    };
    
    // 父传子
    <Child
     money={this.state.money}
     // 2. 通过props传函数给子组件
     handleCost={this.handleCost}
    ></Child>
    
    // 子组件:调用父组件传来的函数
    <button onClick={() => handleCost(8000)}>点我花爸爸的钱</button>
    
    
  • 兄弟通信

    // 整体思路
    兄弟组件通信,需要设计一个双方共同的父组件,然后数据及函数都由父组件集体管理,将父组件的state及fun传给兄弟组件,最终兄弟组件都是调用集体父组件的方法及state来达到通信的目的;
    
    
  • Context 跨组件通信

    javascript
    // 1. React.createContext创建上下文, 解构出两个组件 Provider(提供者)Consumer(消费者)
    const { Provider, Consumer } = React.createContext();
    
    // 2. 使用Provider组件,传数据: 设置value属性传数据 -- 包住后代
    <Provider
     value="hello 我跨组件而来"
    >
     <Son></Son> // 子组件
    </Provider>
    
    // 3. 使用Consumer组件,接收数据
    {/* 💥 接受一个函数,返回需要返回一端JSX,形参就是Provider传来的数据 */}
    <Consumer> // 在孙组件之内
      {(data) => {
     return <h1>我是Consumer - {data}</h1>;
      }}
    </Consumer>
    
    // 优缺点:
     缺点:🔔增加组件的嵌套解构,难以阅读和理解
     优点:
     1. 🔔是React自带的跨组件通信方案,不需要额外下包
     2. 第三方的包喜欢用这个,减少体积
     场景🔔:
     1. 多语言切换
     2. 一键换色
    
    

14、props深入使用(插槽、校验)

  • childre(类似vue的插槽)

  • 插槽的定义:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式

    javascript
    // 第一步设置插槽组件
    function Child({ children }: any) {
     return <h1>{children}</h1>
    }
    
    // 第二步
    {/* 数组、原始数据类型  */}
    <Child>{[1, 2, 3, 4]}</Child>
    {/* 💥函数  */}
    <Child2>
      {() => {
     return <i>我是children传来的函数</i>
      }}
    </Child2>
    {/* 💥JSX */}
    <Child>
     <ul>
     <li>123</li>
     <li>456</li>
     </ul>
    </Child>
    
    
  • childre模拟 匿名插槽&具名插槽&作用域插槽

    javascript
    // 匿名插槽
    // 父组件内:
    <Child>{this.state.msg}</Child>
    
    // 子租件:
    class Child extends Component {
     render() {
     console.log('this  ----->  ', this);
     return <h1>Child子组件 - {this.props.children}</h1>;
      }
    }
    
    // 具名插槽
    // 父组件内:
    <ChildHasName>
      {{
     header: '蜀道难',
     footer: '难于上青天',
      }}
    </ChildHasName>
    
    // 子组件内:
    class ChildHasName extends Component {
     render() {
     return (
      <div>
      <header>显示header: {this.props.children.header}</header>
      <footer>显示footer: {this.props.children.footer}</footer>
      </div>
       );
      }
    }
    
    // 作用域插槽
    // 父组件内:
    <ChildScope>
      {(data) => {
     return (
      <ul>
        {data.map((item) => {
       return <li key={item}>{item}</li>;
        })}
      </ul>
       );
      }}
    </ChildScope>
    
    // 子组件:
    class ChildScope extends Component {
     state = {
     list: ['苹果', '橘子', '香蕉'],
      };
    
     render() {
     return <h1>Child子组件 - {this.props.children(this.state.list)}</h1>;
      }
    }
    
    
  • 利用props校验

    javascript
    // 1. 导入包props-type,提供类型 安装:npm install prop-types --save
    import PropTypes from 'prop-types';
    
    // 2. 给组件设置规则对象
    // 💥 组件名.propTypes = { 规则}
    Child.propTypes = {
     msg: PropTypes.string.isRequired,
     list: PropTypes.array,
     person: PropTypes.object,
     isShow: PropTypes.bool,
     handleClick: PropTypes.func,
     // 💥 JSX
     title: PropTypes.element,
     zs: PropTypes.shape({
     name: PropTypes.string,
     age: PropTypes.number,
      }),
    };
    
    // 3. 组件无需额外操作,父组件传值时需要按照规则传值
    class Child extends React.Component {
     render() {
     return <div></div>;
      }
    }
    
    
  • defaultProps 默认值

    javascript
    // 第一步 设置defaultProps 默认值
    Child(Son).defaultProps = {
     msg: 'hello Child',
    };
    
    // 第二步 组件内用 props 获取
    class Child extends React.Component {
     render() {
     return <div>{this.props.msg}</div>;
      }
    } // 类组件
    
    function Son({ msg = 'hello Son' }) {
     return <h1>{msg}</h1>;
    } // 函数组件
    
    
  • static关键字

    javascript
    // 类内部使用 static 关键字之后不会被子类继承,也不会初始化到实例对象中
    
    // 使用
    class Child extends React.Component {
     static propTypes = {
     msg: PropTypes.string.isRequired,
     list: PropTypes.array,
     person: PropTypes.object,
     isShow: PropTypes.bool,
     handleClick: PropTypes.func,
     // 💥 JSX
     title: PropTypes.element,
     zs: PropTypes.shape({
      name: PropTypes.string,
      age: PropTypes.number,
       }),
      };
    
     static defaultProps = {
     hello: '123',
      };
    
     render() {
     return <div>{this.props.hello}</div>;
      }
    }
    
    

15、React 的生命周期

详细讲述React生命周期文章地址:juejin.cn/post/696618…

javascript
1. 挂载阶段 - 
 1.1 constructor: 创建时,对标vue中的 created
  💥 早期声明state和ref,现在都简写
 1.2 render:渲染dom
 1.3 componentDidMount: 挂载后,对标vue中的mounted
  💥 发请求、最先能够获取DOM、定时器、绑定事件
      
2. 更新阶段
 2.1 render: 重新渲染dom
 2.2 compoentDidUpdate:更新后,对标vue中的updated
  💥 可以获取到更新后的值,常用来做缓存
     
3. 卸载阶段 -
 3.1 componentWillUnMount
 💥 做清除的动作,如:清除定时器、取消监听的事件
执行次数:
 constructor和componentDidMount只会执行一次
 componentWillUnMount只会执行一次

16、Hooks (重要)

16-1、useState基本使用

javascript
// 1. 导入 useState钩子函数: 声明状态
import React, { useState } from 'react';

// 2. 调用钩子函数
const [count, setCount] = useState(100);
// count 等价于 this.state.couont
// setCount等价于this.setState({couont: xxx})

// 3、使用
return (
 <div>
 <h1>{count}</h1>
 <button
  onClick={() => {
  setCount(count + 1);
   }}
 >
   点我加+1
 </button>
 </div>
);

16-2、useState注意事项

javascript
// 1. useState可以多次调用,声明多个状态
 const [count, setCount] = useState(100);
 const [msg, setMsg] = useState('hello React');
// 2. useState可声明任意数据类型
 const [list, setList] = useState([1, 2, 3]);
 const [person, setPerson] = useState({ name: 'zs', age: 18 });
// 3. 更新状态,还是新值覆盖旧值
 setPerson({ ...person, name: 'ww' });
 // ❌person.name = '王五';

16-3、Hooks的三个使用限制

javascript
// 1. hooks不能放在if语句中
 if (false) {
 // 💥React 是根据useState调用顺序,保证每个状态的值分配。React要求调用顺序永远不变
 const [hello, setHello] = useState('123');
  }

// 2. 不能放在for语句中
 for (let index = 0; index < list.length; index++) {
 const [hello, setHello] = useState('123');
  }

// 3. 普通函数中不能使用hooks
function hello(params) {
 const [state, setState] = useState('xxxx');
 return null;
}

16-4、受控组件

javascript
// 1. 声明state
const [value, setValue] = useState('');

// 2. 控制value
<input
 type="text"
 value={value}
 // 💥 绑定方法没有this了
 onChange={handleChange}
/>

// 3. 声明方法用const
const handleChange = (e) => {
 setValue(e.target.value);
};

16-5、useEffect基本使用

javascript
// 第一步 引入 useEffect
import React, { useState, useEffect } from 'react';

// 第二步 导入useEffect钩子函数: 会自动执行
// 语法: useEffect(回调函数);  回调函数中可以获取到更新后的值
useEffect(() => {
  document.title = count;
});

16-6、useEffect模拟生命周期

javascript
// 1. 第二个参数为数组:空数组时代表的是挂载时。等价于componentDidMount
useEffect(() => {
 console.log('我是挂载时的钩子函数,只会执行一次  ----->  ');
 document.title = count;
}, []);

// 2. 第二个参数为数组:数组内有依赖项(状态)时,
// 💥代表的是挂载时和更新时二合一, 类似Vue中的watch属性,开启了immediately
// 💥等价于componentDidMount 和 componentDidUpdate 二合一
useEffect(() => {
  console.log('我是更新时的钩子函数  ----->  ');
  document.title = count;
}, [count]);

// 3、通过返回一个函数,模拟卸载时的生命周期
// 语法: useEffect回调函数内,返回一个函数,这个函数就是卸载时会自动执行的钩子函数
useEffect(() => {
 return () => {
 console.log('我要被卸载掉了  ----->  ');
  };
}, []);

16-7、useEffect监听多个状态

javascript
// 第一种 合并写法,需要根据多个状态的值,进行计算
useEffect(() => {
 document.title = count + msg;
}, [count, msg]);

// 第二种 分开监听,不需要使用多个状态计算
useEffect(() => {
 console.log('count  ----->  ', count);
}, [count]);

useEffect(() => {
 console.log('msg  ----->  ', msg);
}, [msg]);

16-8、useEffect挂载与卸载综合写法

javascript
useEffect(() => {
 const fn = () => {
 console.log('浏览器窗口被调整了');
  };
 // 2. 同一个逻辑的挂载和卸载,合在一个useEffect里起来写
 window.addEventListener('resize', fn);
 return () => {
 window.removeEventListener('resize', fn);
  };
}, []);

16-9、useEffect 与 axios 请求

javascript
// 第一步 封装一个异步函数
useEffect(() => {
 loadData();
}, []);

// 第二步 声明函数,请求回值并赋值
const loadData = async () => {
 const res = await getChannelsAPI();
 setList(res.data.channels);
};