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 写法。

相关推荐
泯泷7 小时前
那段文字是谁删的?Yjs 14 正式版之前,一套删除归属方案的实现与边界
前端·javascript·算法
hold?fish:palm7 小时前
34 合并K个升序链表
javascript·算法·链表
野槐9 小时前
前端项目优化(有了我,会发生...)
前端
幸运小圣10 小时前
PointerEvent 常用属性与事件整理【JavaScript】
开发语言·javascript·ecmascript
aa小小10 小时前
【无标题】
前端
计算机魔术师11 小时前
还在单线程跟 AI 聊天?Claude Code 并行多会话让你一个人干三个人的活
前端
志尊宝11 小时前
Vue3 零基础每日笔记(038):亲手封装 useDebounceFn 与 useThrottleFn——高频事件的流量阀
前端·javascript·vue·html·vue3
JavaGuide11 小时前
对标 MinIO!全新一代分布式文件系统正式发布
前端·后端
风骏时光牛马11 小时前
AI驱动自动化业务工作流搭建实践
前端
码云之上11 小时前
Skill 里的脚本终于能跑了,星悟接 CubeSandbox 的纪实
前端·人工智能·前端框架