react17版本以前类组件常用操作

React 17 及以前版本(主要是 16.x 到 17.x)是类组件(Class Component)为主流的时代,函数组件(Function Component)当时还没有 Hooks(Hooks 是 React 16.8 引入的,但类组件仍是主流写法)。下面按常用功能逐一介绍。


一、组件传参(Props)

父组件向子组件传递数据,通过属性(props)实现。

bash 复制代码
// 父组件
class Parent extends React.Component {
  render() {
    return <Child name="张三" age={20} />;
  }
}

// 子组件
class Child extends React.Component {
  render() {
    return <div>{this.props.name},今年 {this.props.age} 岁</div>;
  }
}

特点:

  • props 是只读的,子组件不能修改
  • 可以传递任意类型:字符串、数字、对象、函数、JSX 节点
  • 通过 defaultProps 设置默认值:Child.defaultProps = { age: 18 }

二、数据绑定(State)

类组件通过 this.state 管理内部数据,通过 this.setState() 更新。

bash 复制代码
class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  increment = () => {
    // setState 是异步的,更新会合并
    this.setState({ count: this.state.count + 1 });
    
    // 如果需要基于前一个状态更新,用函数形式
    this.setState(prevState => ({ count: prevState.count + 1 }));
  };

  render() {
    return (
      <div>
        <p>计数:{this.state.count}</p>
        <button onClick={this.increment}>+1</button>
      </div>
    );
  }
}

单向数据流: React 是单向绑定,数据从 state 流向视图,视图变化通过事件回调修改 state


三、事件处理

bash 复制代码
class Form extends React.Component {
  handleClick = (e) => {
    e.preventDefault(); // 阻止默认行为
    console.log('点击了');
  };

  render() {
    return <button onClick={this.handleClick}>点击</button>;
  }
}

注意点:

  • 事件名用驼峰:onClickonChangeonSubmit
  • 需要绑定 this(上面用了箭头函数,或者在 constructorthis.handleClick = this.handleClick.bind(this)

四、表单与双向绑定(受控组件)

React 中没有真正的 v-model,需要手动实现"双向绑定":

bash 复制代码
class InputForm extends React.Component {
  state = { value: '' };

  handleChange = (e) => {
    this.setState({ value: e.target.value });
  };

  handleSubmit = (e) => {
    e.preventDefault();
    alert('提交:' + this.state.value);
  };

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <input 
          type="text" 
          value={this.state.value} 
          onChange={this.handleChange} 
        />
        <button type="submit">提交</button>
      </form>
    );
  }
}

非受控组件(用 ref 直接操作 DOM):

bash 复制代码
class Uncontrolled extends React.Component {
  inputRef = React.createRef();

  handleSubmit = () => {
    console.log(this.inputRef.current.value);
  };

  render() {
    return <input ref={this.inputRef} />;
  }
}

五、条件渲染 & 列表渲染

bash 复制代码
class ListDemo extends React.Component {
  state = {
    isLogin: true,
    list: ['苹果', '香蕉', '橙子']
  };

  render() {
    const { isLogin, list } = this.state;

    return (
      <div>
        {/* 条件渲染 */}
        {isLogin ? <p>欢迎回来</p> : <p>请登录</p>}
        
        {/* 也可以用 && */}
        {isLogin && <p>已登录</p>}

        {/* 列表渲染,必须加 key */}
        <ul>
          {list.map((item, index) => (
            <li key={index}>{item}</li>
          ))}
        </ul>
      </div>
    );
  }
}

key 的重要性: 帮助 React 识别哪些元素改变了,提升 diff 效率,列表中必须提供唯一 key


六、生命周期(Class 组件核心)

React 16.3 之后生命周期分为三个阶段:

阶段 方法 说明
挂载 constructor 初始化 state 和绑定方法
static getDerivedStateFromProps 根据 props 更新 state(很少用)
render 返回 JSX
componentDidMount 组件挂载完成,适合发请求、操作 DOM
更新 static getDerivedStateFromProps 同上
shouldComponentUpdate 返回 false 可阻止渲染(性能优化)
render 重新渲染
getSnapshotBeforeUpdate 获取更新前 DOM 状态(很少用)
componentDidUpdate 更新完成
卸载 componentWillUnmount 清理工作:取消定时器、取消订阅

旧版(16.3 之前)还有:

  • componentWillMountcomponentWillReceivePropscomponentWillUpdate(现已标记为不安全,不建议使用)

七、路由(React Router v4/v5)

React 17 时代主流是 React Router v5

bash 复制代码
import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom';

// App.js
class App extends React.Component {
  render() {
    return (
      <Router>
        <nav>
          <Link to="/">首页</Link>
          <Link to="/about">关于</Link>
        </nav>
        
        <Switch>
          <Route exact path="/" component={Home} />
          <Route path="/about" component={About} />
          <Route path="/user/:id" component={User} />
          <Route component={NotFound} /> {/* 404 */}
        </Switch>
      </Router>
    );
  }
}

// 路由传参方式
class User extends React.Component {
  render() {
    // URL 参数:/user/123
    const { id } = this.props.match.params;
    
    // Query 参数:/user?id=123
    const query = new URLSearchParams(this.props.location.search);
    const id2 = query.get('id');
    
    return <div>用户ID:{id}</div>;
  }
}

常用 API:

  • <Link>:声明式导航
  • this.props.history.push('/path'):编程式导航
  • withRouter:让非路由组件也能获取 historylocationmatch

八、父子组件通信

1. 父 → 子:Props

bash 复制代码
<Child data={this.state.data} />

2. 子 → 父:回调函数

bash 复制代码
// 父
class Parent extends React.Component {
  getData = (data) => {
    console.log('子组件传来的:', data);
  };

  render() {
    return <Child onSend={this.getData} />;
  }
}

// 子
class Child extends React.Component {
  send = () => {
    this.props.onSend('子组件数据');
  };

  render() {
    return <button onClick={this.send}>传数据给父组件</button>;
  }
}

3. 兄弟组件通信:通过共同的父组件提升状态(State Lifting)

bash 复制代码
class Parent extends React.Component {
  state = { message: '' };

  setMessage = (msg) => {
    this.setState({ message: msg });
  };

  render() {
    return (
      <div>
        <SiblingA onSend={this.setMessage} />
        <SiblingB message={this.state.message} />
      </div>
    );
  }
}

九、跨层级通信(Context)

避免层层传递 props("prop drilling")。

bash 复制代码
// 1. 创建 Context
const ThemeContext = React.createContext('light');

// 2. 提供数据(Provider)
class App extends React.Component {
  render() {
    return (
      <ThemeContext.Provider value="dark">
        <Toolbar />
      </ThemeContext.Provider>
    );
  }
}

// 3. 消费数据(Consumer)
class ThemedButton extends React.Component {
  render() {
    return (
      <ThemeContext.Consumer>
        {theme => <button className={theme}>主题按钮</button>}
      </ThemeContext.Consumer>
    );
  }
}

Class 组件也可以用 static contextType

bash 复制代码
class MyComponent extends React.Component {
  static contextType = ThemeContext;
  
  render() {
    return <div>{this.context}</div>;
  }
}

十、Refs(操作 DOM / 获取子组件实例)

bash 复制代码
class AutoFocus extends React.Component {
  inputRef = React.createRef();

  componentDidMount() {
    this.inputRef.current.focus();
  }

  render() {
    return <input ref={this.inputRef} />;
  }
}

回调 ref(旧写法):

bash 复制代码
<input ref={el => this.inputEl = el} />

十一、性能优化

方法 说明
shouldComponentUpdate 手动控制是否重新渲染
React.PureComponent 自动浅比较 props 和 state
React.memo(函数组件) 类似 PureComponent
拆分组件 避免不必要的渲染范围
bash 复制代码
class ListItem extends React.PureComponent {
  // 自动实现 shouldComponentUpdate 的浅比较
  render() {
    return <li>{this.props.name}</li>;
  }
}

总结对比(React 17 vs 18+)

特性 React 17 及以前 React 18+
主流写法 Class 组件 Function 组件 + Hooks
状态管理 this.state / this.setState useState / useReducer
副作用 componentDidMount 等生命周期 useEffect
上下文 static contextType / <Context.Consumer> useContext
路由 React Router v5 React Router v6(API 变化大)
并发特性 有(Concurrent Features)

如果你是在维护一个 React 17 的老项目,以上知识基本够用;如果是新项目,建议直接使用 React 18/19 + Hooks 写法。

相关推荐
ly76891 小时前
Web 性能优化实战:从 Core Web Vitals 到工程化性能治理
前端·性能优化
冬奇Lab1 小时前
一天一个开源项目(第200篇):next-forge - 生产级 Next.js SaaS 启动模板
前端·前端框架·开源
Profile排查笔记2 小时前
指纹浏览器怎么设置 IP?代理配置、检测与排错流程
前端·人工智能·后端·自动化
lzhdim2 小时前
13、JavaScript事件循环机制 - JavaScript学习系列文章
开发语言·前端·javascript·学习·ecmascript
liangshanbo12152 小时前
Vue 3 <script setup> 的本质原理是什么?它与普通 setup()有何区别?
前端·javascript·vue.js
IT_陈寒3 小时前
SpringBoot自动配置失效?你可能漏了这个小开关
前端·人工智能·后端
kyriewen3 小时前
我写了1个复盘Skill,和AI协作踩过的坑第二天自动变成护栏
前端·程序员·ai编程
风骏时光牛马3 小时前
AI提示词异常故障复盘分析
前端
SoaringHeart3 小时前
Flutter 进阶:NCanvasImageLoader 让 Canvas 也能画网络图
前端·flutter