React官网学习笔记

148 阅读5分钟

配置

1. CDN引入Reactjs

版本号可以根据实际修改,把18换成别的版本即可

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

2. JSX配置

# 初始化package.json文件
npm init -y
# 安装babel和babel-react预设
npm install babel-cli@6 babel-preset-react-app@3
# 执行babel命令,自动监听src目录下的文件转化jsx语法输出到当前目录下,配置预设react-app/prod
npx babel --watch src --out-dir . --presets react-app/prod

核心概念

1. Hello World

ReactDOM
  .createRoot(document.getElementById('root'))
  .render(<h1>Hello, world!</h1>);

2. JSX简介

JSX是什么:一个 JavaScript 的语法扩展,可以在js中直接写html标签,比如:

const element = <h1>Hello, world!</h1>;

基本语法:

  • 在 JSX 中嵌入表达式,用大括号包裹起来,和es6的字符串模版类似
const name = 'Josh Perez';
const element = <h1>Hello, {name}</h1>;
  • JSX 也是一个表达式,jsx相当于是一个变量可以当函数参数
  • JSX 中指定元素属性,注意class要改成classNamefor要改成htmlFor
    • 使用引号,来将属性值指定为字符串字面量
    • 使用大括号,来在属性值中插入一个 JavaScript 表达式
  • 使用 JSX 指定子元素,多行标签要用小括号包裹,比如
const element = (
  <div>
    <h1>Hello!</h1>
    <h2>Good to see you here.</h2>
  </div>
);
  • JSX会自动转义来避免XSS攻击
  • Babel 会把 JSX 转译成一个名为 React.createElement() 函数调用
// jsx
const element = (
  <h1 className="greeting">
    Hello, world!
  </h1>
);
// 转译后
const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);

3. 元素渲染

4. 组件&Props

函数组件

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

class组件

class Welcome extends React.Component {
  constructor(props) {
    super(props)
  }
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

注意: 组件名称必须以大写字母开头。React 会将以小写字母开头的组件视为原生 DOM 标签。例如,<div /> 代表 HTML 的 div 标签,而 <Welcome /> 则代表一个组件

props:传给组件的只读属性(单向数据流)

5. State&生命周期

state是组件内部的状态,需要注意如下事项:

  1. 不能直接修改(除了在构造函数中才能通过赋值的方式来初始化),只能通过setState函数来修改,
class Clock extends React.Component {
  constructor(props) {
    super(props);
    // 构造函数中初始化状态,唯一可以直接赋值的地方
    this.state = {date: new Date()};
  }

  render() {
    return <div>内容</div>
  }
}
  1. state修改可能是异步的,React 可能会把多个 setState() 调用合并成一个调用,如果需要依赖上一个状态,需要这样处理:
this.setState(function(state, props) {
  return {
    counter: state.counter + props.increment
  };
});
  1. React 会把你提供的对象合并到当前的 state。也就是setState可以只修改一个或者某几个状态

生命周期和vue的生命周期一样的作用,只是函数名不同比如:
componentDidMount(挂载后触发)
componentWillUnmount(销毁前触发)

6. 事件处理

  1. React 事件的命名采用小驼峰式(camelCase),而不是纯小写。
  2. 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。
<button onClick={activateLasers}>
  Activate Lasers
</button>
  1. 在 React 中另一个不同点是你不能通过返回 false 的方式阻止默认行为。你必须显式的使用 preventDefault 回调中的event是一个合成事件。React 根据 W3C 规范来定义这些合成事件来处理各浏览器兼容性,更多请点击这里
  2. 绑定的函数必须手动绑定this,这是js的this的原因(函数单独调用this指向默认值),否则回调中this是window(严格模式下是undefined),一般有以下几种方式:
    1. 通过Function.prototype.bind绑定this
    this.handleClick = this.handleClick.bind(this);
    
    1. class的public class fields 语法()
    handleClick = () => {
      console.log('this is:', this);
    }
    
    1. 在jsx中直接使用箭头函数。强烈不推荐使用这种方式。每次渲染时都会创建不同的回调函数,如果传给子组件的props则子组件可能会(因为该props改变)进行额外的重新渲染
    <button onClick={() => this.handleClick()}>
      Click me
    </button>
    

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // 为了在回调中使用 `this`,这个绑定是必不可少的
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}
  1. 回调中传递参数,有如下两种方式(不推荐箭头函数这种方式):
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

在这两种情况下,React 的事件对象 e 会被作为第二个参数传递

7. 条件渲染

  1. 元素变量
let button;
if (isLoggedIn) {
  button = <LogoutButton onClick={this.handleLogoutClick} />;
} else {
  button = <LoginButton onClick={this.handleLoginClick} />;
}
  1. 与运算符 &&
<div>  
  {unreadMessages.length > 0 && <h2>xxx</h2>}
</div>
  1. 三目运算符
<div>
  {isLoggedIn
    ? <LogoutButton onClick={this.handleLogoutClick} />
    : <LoginButton onClick={this.handleLoginClick} />
  }
</div>
  1. 阻止组件渲染。render方法直接返回null,而不进行任何渲染。**注意:**在组件的 render 方法中返回 null 并不会影响组件的生命周期的执行

8. 列表&Key

10. 状态提升

子组件共用的状态提升到父组件,不是尝试在不同组件间同步state。 父组件给需要的子组件通过props传递值(比如value),以及传递一个可以修改父组件状态的函数props(比如onXXXChangeonXXXChange定义在父组件中)

class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: '' // 共用的状态
    }
  }

  handleValueChange = (value) => {
    // 传递给子组件,子组件变化时通知父组件来修改值
    this.setState({value})
  }
  
  render() {
    return (
      <div>
        <Child1 value={value} onValueChange={this.handleValueChange}></Child1>
        <Child2 value={value} onValueChange={this.handleValueChange}></Child2>
      </div>
    );
  }
}

11. 组合vs继承

  1. jsx中组件标签包含的所有内容会作为一个children prop 传递给组件,组件通过在渲染函数中加{props.children}来渲染出来
function FancyBorder(props) {
  return (
    <div className={'fancy-border fancy-border-' + props.color}>
      {props.children}
    </div>
  )
}

function WelcomeDialog(props) {
  return(
    <FancyBorder color='blue'>
      <h1 className="Dialog-title">
        Welcome
      </h1>
      <p className="Dialog-message">
        Thank you for visiting our spacecraft!
      </p >
    </FancyBorder>
  )
}
  1. 预定位置(和vue的插槽类似)
    jsx中元素可以作为变量,而变量也可以插入到jsx中。所以可以循环嵌套😀:sunglasses:
    所以直接通过props传递指定的元素,然后在渲染函数中通过嵌套变量的方式来实现
function SplitPane(props) {
  return (
    <div className="SplitPane">
      <div className="SplitPane-left">
        {props.left}
      </div>
      <div className="SplitPane-right">
        {props.right}
      </div>
    </div>
  );
}

function App() {
  return (
    <SplitPane
      left={
        <Contacts />
      }
      right={
        <Chat />
      } />
  );
}

继承,没有使用的场景,因为props和组合已经可以完全满足,官方是这么说的:

Props 和组合为你提供了清晰而安全地定制组件外观和行为的灵活方式。注意:组件可以接受任意 props,包括基本数据类型,React 元素以及函数。

12. React哲学