劫持react组件

news/2024/7/2 23:44:26

劫持props

假设我们有一个原组件,它接收一个 name prop,并显示一个问候语:

// 原组件
function Greeting(props) {
  return <h1> Hello, {props.name}! </h1>;
}

我们可以定义一个高阶组件,它可以通过 props 传递一个 color prop 给原组件,让原组件的文字颜色变化。同时,它也可以修改原组件的 name prop,让它变成大写。这样,我们就劫持了原组件的 props。

// 高阶组件
function withColor(WrappedComponent) {
  return function (props) {
    // 劫持 props
    const newProps = { ...props, name: props.name.toUpperCase() };
    // 劫持 render
    const style = { color: props.color };
    return (
      <div style={style}>
        <WrappedComponent {...newProps} />
      </div>
    );
  };
}

然后,我们可以使用高阶组件来创建一个新的组件,它接收一个 color prop,并传递给原组件:

// 劫持后的组件
const ColoredGreeting = withColor(Greeting);

ReactDOM.render(
  <ColoredGreeting name="Alice" color="red" />,
  document.getElementById("root")
);

这样,我们就得到了一个显示红色文字,并且名字是大写的问候语组件。

劫持state

假设我们有一个原组件,它接收一个 count prop,并显示一个计数器:

// 原组件
function Counter(props) {
  return (
    <div>
      <h1> Count: {props.count} </h1>
      <button onClick={props.increment}> + </button>
      <button onClick={props.decrement}> - </button>
    </div>
  );
}

我们可以定义一个高阶组件,它可以管理原组件的 count 状态,并提供 increment 和 decrement 方法给原组件,让原组件可以更新状态。这样,我们就劫持了原组件的 state。

// 高阶组件
function withState(WrappedComponent) {
  return class extends React.Component {
    constructor(props) {
      super(props);
      this.state = { count: 0 };
      this.increment = this.increment.bind(this);
      this.decrement = this.decrement.bind(this);
    }
    increment() {
      this.setState((state) => ({ count: state.count + 1 }));
    }
    decrement() {
      this.setState((state) => ({ count: state.count - 1 }));
    }
    render() {
      // 劫持 state
      const newProps = {
        ...this.props,
        count: this.state.count,
        increment: this.increment,
        decrement: this.decrement,
      };
      return <WrappedComponent {...newProps} />;
    }
  };
}

然后,我们可以使用高阶组件来创建一个新的组件,它不需要接收任何 prop,因为它的状态已经由高阶组件管理了:

// 劫持后的组件
const StatefulCounter = withState(Counter);

ReactDOM.render(<StatefulCounter />, document.getElementById("root"));

这样,我们就得到了一个可以自增和自减的计数器组件。

劫持render

假设我们有一个原组件,它接收一个 title prop,并显示一个标题:

// 原组件
function Title(props) {
  return <h1> {props.title} </h1>;
}

我们可以定义一个高阶组件,它可以在原组件的外面添加一个边框,修改原组件的样式,或者根据条件决定是否渲染原组件。这样,我们就劫持了原组件的 render。

// 高阶组件
function withBorder(WrappedComponent) {
  return function (props) {
    // 劫持 render
    const style = { border: "1px solid black", padding: "10px" };
    return (
      <div style={style}>
        <WrappedComponent {...props} />
      </div>
    );
  };
}

function withStyle(WrappedComponent) {
  return function (props) {
    // 劫持 render
    const style = { color: "red", fontSize: "24px" };
    return <WrappedComponent {...props} style={style} />;
  };
}

function withCondition(WrappedComponent) {
  return function (props) {
    // 劫持 render
    if (props.title.length > 10) {
      return <WrappedComponent {...props} />;
    } else {
      return null;
    }
  };
}

然后,我们可以使用高阶组件来创建一个新的组件,它会根据不同的高阶组件有不同的渲染效果:

// 劫持后的组件
const BorderedTitle = withBorder(Title);
const StyledTitle = withStyle(Title);
const ConditionalTitle = withCondition(Title);

ReactDOM.render(
  <div>
    <BorderedTitle title="Hello, world!" />
    <StyledTitle title="Hello, world!" />
    <ConditionalTitle title="Hello, world!" />
    <ConditionalTitle title="Hello, everyone!" />
  </div>,
  document.getElementById("root")
);

这样,我们就得到了一个有边框的标题,一个红色字体的标题,和一个只在标题长度大于10时才显示的标题。

劫持生命周期

假设我们有一个原组件,它接收一个 data prop,并显示一个列表:

// 原组件
function List(props) {
  return (
    <div>
      <ul>
        {props.data.map((item, index) => {
          return <li key={index}>{item}</li>;
        })}
      </ul>
    </div>
  );
}

我们可以定义一个高阶组件,它可以在原组件的 componentDidMount 和 componentWillUnmount 方法中执行一些操作,比如发送请求,设置定时器,添加事件监听等。这样,我们就劫持了原组件的生命周期。

// 高阶组件
function withLifecycle(WrappedComponent) {
  return class extends React.Component {
    constructor(props) {
      super(props);
      this.state = { data: [] };
      this.fetchData = this.fetchData.bind(this);
      this.handleResize = this.handleResize.bind(this);
    }
    componentDidMount() {
      // 劫持生命周期
      this.fetchData();
      this.timer = setInterval(this.fetchData, 5000);
      window.addEventListener("resize", this.handleResize);
    }
    componentWillUnmount() {
      // 劫持生命周期
      clearInterval(this.timer);
      window.removeEventListener("resize", this.handleResize);
    }
    fetchData() {
      fetch("/api/data")
        .then((data) => {
          this.setState({ data: data });
        })
        .catch((error) => {
          console.error(error);
        });
    }
    handleResize() {
      console.log("Window resized");
    }
    render() {
      return <WrappedComponent {...this.props} data={this.state.data} />;
    }
  };
}

然后,我们可以使用高阶组件来创建一个新的组件,它不需要接收任何 prop,因为它的数据和行为已经由高阶组件管理了:

// 劫持后的组件
const LifecycleList = withLifecycle(List);

ReactDOM.render(<LifecycleList />, document.getElementById("root"));

这样,我们就得到了一个可以自动更新数据,并且响应窗口大小变化的列表组件。


http://lihuaxi.xjx100.cn/news/1293885.html

相关文章

Linux教程——Linux用户和用户组(包含两者之间的关系)

Linux 是多用户多任务操作系统&#xff0c;换句话说&#xff0c;Linux 系统支持多个用户在同一时间内登陆&#xff0c;不同用户可以执行不同的任务&#xff0c;并且互不影响。 例如&#xff0c;某台 Linux 服务器上有 4 个用户&#xff0c;分别是 root、www、ftp 和 mysql&…

PDF如何转换成Word?PDF转Word方法分享!​

PDF大家都不陌生了吧&#xff1f;作为打工人&#xff0c;学生党的大家都知道&#xff0c;PDF是现在不可或缺的文件传输工具之一&#xff0c;不仅可将文档转为Word&#xff0c;还可以转成excel,ppt等各种形式&#xff0c;其重要性不言而喻&#xff0c;那么今天小编就跟大家具体说…

【Java】直接return 会触发try-catch 里面的finally的方法么

&#x1f431;‍&#x1f680;/背景 try-catch 主要的作用是捕获异常&#xff0c;那么程序没有异常&#xff0c;finally里面代码能否执行&#xff1f; 特别是如果我们前面进行了加锁等操作&#xff0c;没有释放锁&#xff0c;那不是会造成业务逻辑问题, 先说结论&#xff1a;…

【Vue】axios发请求下载excel--20230630

1.关键点&#xff1a; blob乱码传参 2.参考资料&#xff1a;处理blob文件流和乱码问题 https://blog.csdn.net/qq_41512902/article/details/125680531 https://blog.csdn.net/qq_38804584/article/details/109238794 3.我的代码&#xff1a;axios发请求下载excel js代…

JAVA开发运维(linux环境防火墙与端口开启使用总结记录)

一、问题背景&#xff1a; 将web项目开发完成&#xff0c;需要上到生产环境。那么我们应用调用的一些ip&#xff0c;端口都是要设置的&#xff0c;比如说应用提供给谁访问&#xff0c;那些人不能访问&#xff0c;应用的端口是多少&#xff0c;也是需要开启才能访问的。在实际研…

git杀手级功能 —— 分支管理

目录 分支介绍 创建分支 切换分支 和并分支 删除分支 合并冲突 分支管理策略 分支策略 bug分支 其他问题 强行删除临时分支 结语 分支介绍 在版本回退里发现&#xff1a;每次提交&#xff0c;git都会把它们穿成一条时间线&#xff0c;而这条时间线就可以理解为一个分支…

玩机搞机---另类操作 修改原生卡刷包转换为线刷包方式刷机

偶然给安卓机型刷写原生安卓的系统。可能其第三方twrp原因或者底包原因导致卡刷一直报错。虽然最终写入开机&#xff0c;但浪费时间&#xff0c;究其原因还在于分区切换和挂载分区导致的。写这篇博文的意义不是在于让玩家按步骤转换线刷&#xff0c;只是明白其分区写入的原理 索…

关于Jetpack DataStore(Proto)的六点疑问

前言 上篇分析了DataStore(Preferences)的使用与原理&#xff0c;本篇接着阐述DataStore的另一种实现形式&#xff1a;DataStore(Proto)。 通过本篇文章&#xff0c;你将了解到&#xff1a; 1. 为什么需要Proto&#xff1f; DataStore(Preferences)对标SharedPreferences&a…