【React】 React 基礎詳解

111 阅读4分钟

1. 函數式和類式

1.1 Code

  • 函数式写法更加简洁和思维导向,适用于无状态、UI纯粹的组件,且可以使用Hooks处理副作用。
  • 类式写法适用于有内部状态生命周期方法复杂交互逻辑的组件,提供了更多的灵活性和控制力。

函數式寫法

  • 方法名就是組件名
import React, { useState } from 'react';
 
const CounterFunctional = () => {
  const [count, setCount] = useState(0);
 
  const increment = () => {
    setCount(count + 1);
  };
 
  return (
    <div>
      <h2>Counter (Functional)</h2>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
};
 
export default CounterFunctional;

類式寫法

  • 類名就是組件名
  • 必須繼承React.Component
  • 必須有render方法,而且有返回值
import React from 'react';
 
class CounterClass extends React.Component {
  //直接把變數放入state
  state = {
      count: 0,
  }
 
  //這種寫法相當於賦值,給這個類添加了一個屬性increment
  increment = () => {
    this.setState({ count: this.state.count + 1 });
  };
 
  render() {
    return (
      <div>
        <h2>Counter (Class)</h2>
        <p>Count: {this.state.count}</p>
        <button onClick={this.increment}>Increment</button>
      </div>
    );
  }
}
 
export default CounterClass;

笨重寫法,需要bind修改this的指向

import React from 'react';
 
class CounterClass extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
    };
    this.increment = this.increment.bind(this)
  }

  increment() {
    this.setState({
      count: this.state.count + 1,
    })
  }
 
  render() {
    return (
      <div>
        <h2>Counter (Class)</h2>
        <p>Count: {this.state.count}</p>
        <button onClick={this.increment}>Increment</button>
      </div>
    );
  }
}
 
export default CounterClass;

1.2 Diff

狀態管理:

  • 函数式组件可以使用React Hooks,如useStateuseReducer等来管理状态和订阅等行为。
  • 类组件可以通过state属性来存储和更新内部数据,this.state初始化、this.setState更新。

生命週期:

  • 函數式組件使用useEffect鉤子來處理組件掛載
  • 类组件具有一系列生命周期方法(如componentDidMountcomponentDidUpdate等),可以在特定的时刻执行一些操作,例如数据获取、订阅和清理等。

1.3 useState

useState 以及任何其他以“use”开头的函数都被称为 Hook

const [count, setCount] = useState(initialCount)

  • 它返回一个状态和一个狀態更新函數;
  • initialCount 是我们传入的一个初始状态,它是惰性的,我们可以通过传一个函数来返回一个值当作初始状态,并且这个函数只会在初始渲染时执行一次;

回購頭來看,前面函數式編程代碼

    //定義了一個變量count = 0
    //定義了一個方法setCount
    const [count, setCount] = useState(0)
    const handleClick = () => {
        setCount(count + 1)
        // 使用新值调用状态更新器函数setState(newState)更新状态。
        //也可以使用一个回调setState(prev => next)来更新狀態,該回調將返回基於先前狀態的新狀態
        // setCount(count => count + 1)
    }
    handleClick();

userState注意事項:

  • 仅顶层调用 Hook :不能在循环,条件,嵌套函数等中调用useState()。
  • 在多个useState()调用中,渲染之间的调用顺序必须相同。
  • 必须仅在函数组件或自定义钩子内部调用useState()。

2. 組件實例的三大核心屬性

下面的三件套都是對類組件說的,函數式組件沒有this

2.1 state

1.重點:State對每一個組件來說,是隔离且私有的

state是組件最重要的屬性,裡面的內容是多個key-value組合

2.注意:組件自定義的方法中this為undefined,如何解決?

  • 通過bind(this)強制修改this指向
  • 使用箭頭函數,this指向父級

3.修改state值

使用this.setState({key:value})來修改。

export default class xxxxPopup extends React.Component {
 
  constructor(props) {
    super(props)
    this.state = {
      Entity: {
        name: '',
        desc: '',
      }
    }
  }
 
  OnSubmit =() => {
    console.log(this.state.subdomainEntity)
  }
 
  render() {
    return (
      <CRow>
        <CCol xs="12" md="12">
          <CCardHeader>
            <CNavbarBrand className="glossay-madal-header">
              <p>
                <div>
                  <strong>New Domain</strong>
                </div>
                <div>
                  <p>Create a new SubDomain</p>
                </div>
              </p>
            </CNavbarBrand>
          </CCardHeader>
        </CCol>
      </CRow>
    )
  }
}

2.2 props

父子組件傳值

Father.js是父组件,Header.js是子组件

import React from 'react';
import Header from './Header';
class Father extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            title: 'hello qing',
            num: 123//num如果是字符串的话,控制台会报错,因为子组件设置了Header.propTypes
        };
    }
    run = () => {
        alert('我是父组件run方法');
    }
    getDate = () => {
        alert(this.state.title);
    }
    //获取子组件传过来的数据
    getSonData = (result) => {
        alert(result);
    }
    //父组件调用子组件的数据和方法
    getSonRun = () => {
        // alert(this.refs.footer.state.sonmsg);
        this.refs.footer.run();
    }
    render() {
        return (
            // 父组件可以传值,也可以传方法给子组件,还可以把整个父组件传给子组件
            <div><Header title="haha" run={this.run} father={this} ref='footer' num={this.state.num} getSonData={this.getSonData}>header中间的文字对应props.children</Header>
                <hr />我是父组件内容
                <br />
                <button onClick={this.getSonRun}>获取整个子组件</button>
            </div>
        );
    }
}
 
export default Father;
import React from 'react';
import Proptypes from 'prop-types';
class Header extends React.Component {
    constructor(props) {
        super(props);
        this.state = { 
            sonmsg:'header----sonmsg'
         };
    }
    getFathMsg=()=>{
        alert(this.props.father.state.title);
    }
    run=()=>{
        alert('我是子组件的run方法');
    }
    render() {
        return (
            <div>
                <h1>{this.props.children}</h1>
                <h2>{this.props.title}---我是子组件内容</h2>
                <button onClick={this.props.run}>调用父组件中的run方法</button>
                <button onClick={this.props.father.getDate}>调用父组件中的getDate方法</button>
                <button onClick={this.getFathMsg}>获取父组件中state中的title属性</button>
                <button onClick={this.props.father.getSonData.bind(this,'我是子组件传过来的')}>子组件给父组件传值</button>
                <button onClick={this.props.getSonData.bind(this,'我是子组件传过来的222')}>子组件给父组件传值2</button>
            </div>
        );
    }
}
 
//defaultProps:如果父组件调用子组件时,不给子组件传title属性,那么就在子组件中使用defaultProps定义的默认值
Header.defaultProps={
    title:'标题'
}
// propTypes:验证父组件传值类型的合法性,Proptypes.number中的Proptypes名称可以自己定义,与上面引入的名称一致即可
Header.propTypes={
    num:Proptypes.number
}
export default Header;

2.3 refs