react实例与总结(一)

目录

一、简单认识

1.1、特点

1.2、JSX语法规则

1.3、函数组件和类式组件

1.4、类组件三大属性state、props、refs

1.4.1、state

1.4.2、props

1.4.3、refs

1.5、事件处理

1.6、收集表单数据---非受控组件和受控组件

1.7、高阶函数---函数柯里化

1.8、生命周期---新旧对比

1.8.1、旧16+

1.8.2、新17+

1.8.3、对比

1.9、DOM的Diffing算法

二、脚手架搭建

2.1、创建项目

因为真实DOM频繁操作节点会导致页面重绘和重排,影响性能,所以会用虚拟DOM【应用于前端框架】进行跨平台开发

一、简单认识

英文:Getting Started -- React

中文:快速入门 -- React 中文文档

1.1、特点

(1)采用组件化模式、声明式编码,提高开发效率及组件复用率

(2)在React Native中使用它进行移动端开发

(3)使用虚拟DOM+Diffing算法,减少与真实DOM的交互

1.2、JSX语法规则

(1)、定义虚拟DOM时,不要写引号

(2)、标签中混入js表达式时要用{}

(3)、样式的类名指定不要用class,要用className

(4)、内联样式:要用**style={{key:value}}**形式

(5)、只有一个根标签,所有标签必须闭合

(6)、标签首字母

若小写字母开头,则将该标签转为html中同名元素;若html中没有该标签对应的同名元素,则报错

若大写字母开头,则react去找对应的组件,若找不到,则报错

在Microsoft Edge安装React Developer Tools扩展进行开发辅助,以下语法基于**16+**版本。

1.3、函数组件和类式组件

前者适用于简单组件(只能使用props属性,除非使用Hooks里的useRef 和 useState ),后者适用于复杂组件

html 复制代码
    <div id="root"></div>
    <script type="text/babel">
      // 1.创建函数式组件
      function MyComponent() {
        return <h1>我是函数式组件</h1>;
      }
      // 2.渲染组件到页面
      ReactDOM.render(<MyComponent />, document.getElementById("root"));
    </script>
javascript 复制代码
      // 1.创建类式组件
      class MyComponent extends React.Component {
        render() {
          //  render()中的this 指向当前组件实例
          return <h1>我是类式组件</h1>;
        }
      }
      // 2.渲染组件到页面
      ReactDOM.render(<MyComponent />, document.getElementById("root"));

1.4、类组件三大属性state、props、refs

注意:类组件里的render()会调用1+N次(只要state更新就变)

1.4.1、state

javascript 复制代码
      class MyMood extends React.Component {
        state = {
          isGood: false,
          number: 0,
        };
        render() {
          const { isGood, number } = this.state;
          return (
            <div>
              <h1 onClick={this.changeMyMood}>
                今天心情很{isGood ? "好" : "糟糕"}
              </h1>
              <h1 onClick={() => this.setState({ number: 10 })}>
                打个{number}分
              </h1>
            </div>
          );
        }
        changeMyMood = () => {
          this.setState({
            isGood: !this.state.isGood,
          });
        };
      }
      ReactDOM.render(<MyMood />, document.getElementById("root"));

总结:

(1)、状态必须通过setState进行更新,且更新是一种合并,不是替换;

(2)、组件中render()方法中的this为组件实例对象,当this为undefined,如何解决?

a. 通过函数对象的**bind()**强制绑定this;b.箭头函数

1.4.2、props

html 复制代码
<div id="root1"></div>
<div id="root2"></div>
<div id="root3"></div>
    <script type="text/babel">
      class Person extends React.Component {
      // 使用 PropTypes 进行类型检查
      static propTypes = {
        name: PropTypes.string.isRequired,//必传项
        sex: PropTypes.string,
        age: PropTypes.number,
        onSuccess: PropTypes.func
      };
      // 设置默认属性
      static defaultProps = {
        age: 18,
        sex: "男"
      };
      render() {
          const { name, age, sex } = this.props;
          return (
            <ul>
              <li>姓名:{name}</li>
              <li>性别:{sex}</li>
              <li>年龄:{age + 1}</li>
            </ul>
          );
        }
      }
ReactDOM.render(<Person name="tom" age={18} sex="男" onSuccess={onSuccess}/>, document.getElementById("root1"));
      // 批量传递 props 【{...x}】
      const backData = { name: '后端返回数据', age: 19, sex: "女" }; 
ReactDOM.render(<Person {...backData} />, document.getElementById("root2"));
ReactDOM.render(<Person name="jack" age={20}/>, document.getElementById("root3"));
      function onSuccess() {
        console.log('执行事件');
      }
    </script>

函数组件Props

javascript 复制代码
      function Person(props) {
        const { name, age, sex } = props;
        return (
          <ul>
            <li>姓名:{name}</li>
            <li>性别:{sex}</li>
            <li>年龄:{age + 1}</li>
          </ul>
        );
      }
      Person.propTypes = {
        name: PropTypes.string.isRequired, 
        sex: PropTypes.string,
        age: PropTypes.number,
      };
ReactDOM.render(<Person name='tom' age={18} sex="男" />, document.getElementById("root"));

总结:

(1)、组件标签的所有属性都保存在props中,但是组件内部不要修改props数据;

(2)、批量传递:{...item}、类型检查:PropTypes、默认属性:defaultProps

1.4.3、refs

javascript 复制代码
class MyComponent extends React.Component {
        showData = () => {
          const { input1 } = this.refs;
          alert(input1.value);
        };
        showData2 = () => {
          const { input2 } = this;
          alert(input2.value);
        };
        myRef=React.createRef();
        showData3 = () => {
          alert(this.myRef.current.value);
        };
render() {
          return (
            <div>
              {/* 1、字符串形式 */}
              <input ref="input1" type="text" placeholder="点击按钮提示数据" />
              &nbsp;
              <button onClick={this.showData}>点击提示左侧数据</button>&nbsp;
              {/* 2、回调函数形式 */}
              <input
                ref={(c) => (this.input2 = c)}
                onBlur={this.showData2}
                type="text"
                placeholder="失去焦点提示数据"
              />&nbsp;
              {/* 3、createRef API:存储被ref标识的节点,"专人专用" */}
              <input
                ref={this.myRef}
                onBlur={this.showData3}
                type="text"
                placeholder="createRef的使用"
              />
            </div>
          );
        }
}
ReactDOM.render(<MyComponent />, document.getElementById("root"));

总结:

(1)、直接访问和操作DOM元素或React组件实例;

(2)、使用React.createRef() 或者回调函数形式(类组件);使用**useRef**(函数组件)

1.5、事件处理

总结:

(1)、通过onXxx属性指定事件处理函数,事件通过事件委托【委托给组件最外层的元素】处理的;

(2)、通过event.target得到发生事件的DOM元素对象【高效】;

(3)、原生Js事件使用onclick,而React事件使用onClick【为了更好的兼容性】。

1.6、收集表单数据---非受控组件和受控组件

特性 受控组件 (Controlled) 非受控组件 (Uncontrolled)
值存储位置 存储在React组件的state 存储在DOM中(使用ref访问)
表单元素控制 React通过state控制表单的值 浏览器控制,React不干涉
更新方式 用户输入时通过onChange更新state 使用**ref获取值**,无需触发事件
适用场景 需要表单验证、交互或复杂逻辑时 简单表单,且无需与React状态紧密交互
代码复杂度 稍微复杂,需要维护状态和事件处理 简单,直接使用ref访问DOM

1.7、高阶函数---函数柯里化

总结:

高阶函数 :如果函数的参数或者返回值是函数,那么这个函数就是高阶函数。

常见有:Promise、setTimeout、arr.map()、call、apply、bind、...

函数柯里化 :通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的一种函数编码形式。·

或者:直接在视图上使用箭头函数,同时传入属性值和对应的event。

1.8、生命周期---新旧对比

1.8.1、旧16+

javascript 复制代码
  <script type="text/babel">
    class MyComponent extends React.Component {
      constructor(props) {
        console.log("构造器---constructor");
        super(props);
        this.state = { count: 0 };
      }
      componentWillMount() {
        console.log("组件将要挂载---componentWillMount");
      }
      componentDidMount() {
        console.log("组件挂载完毕---componentDidMount");
      }
      shouldComponentUpdate(nextProps, nextState) {
        console.log("组件是否需要更新---shouldComponentUpdate");
        return true;
      }
      componentWillUpdate() {
        console.log("组件将要更新---componentWillUpdate");
      }
      componentDidUpdate() {
        console.log("组件更新完毕---componentDidUpdate");
      }
      componentWillUnmount() {
        console.log("组件即将卸载---componentWillUnmount");
      }
      moveIt = () => {
        ReactDOM.unmountComponentAtNode(document.getElementById("root")); //卸载
      };
      addIt = () => {
        const { count } = this.state;
        this.setState({ count: count + 1 });
      };
      forceIt = () => {
        this.forceUpdate();
      };
      render() {
        console.log("挂载页面---render");
        const { count } = this.state;
        return (
          <div>
            <h2>当前求和为:{count}</h2>
            <button onClick={this.addIt}>点击+1</button>
            <button onClick={this.moveIt}>销毁</button>
            <button onClick={this.forceIt}>强制更新</button>
          </div>
        );
      }
    }
    // A和B是父子关系
    class A extends React.Component {
      state = { carName: '奔驰' };
      changeCar = () => {
        this.setState({ carName: '宝马' });
      };
      render() {
        return (
          <div>
            <div>A页面</div>
            <button onClick={this.changeCar}>换车</button>
            <B carName={this.state.carName} />
          </div>
        );
      }
    }
    class B extends React.Component {
      componentWillReceiveProps(nextProps) {
        console.log('B组件接收到新的属性(第一次不调)', nextProps);
      }
      render() {
        return <div>B组件接收的车是:{this.props.carName}</div>;
      }
    }
    // ReactDOM.render(<MyComponent />, document.getElementById("root"));
    ReactDOM.render(<A />, document.getElementById("root"));
  </script>

1.8.2、新17+

javascript 复制代码
    static getDerivedStateFromProps(props,state) {
        console.log("获取新的属性---getDerivedStateFromProps",props,state);
        return null;//返回null或者props
      }
    ReactDOM.render(<MyComponent count={199} />, document.getElementById("root"));
javascript 复制代码
<style>
    .list {
      width: 200px;
      height: 150px;
      background-color: skyblue;
      overflow: auto;
    }
    .news {
      height: 30px;
</style>
class MyComponent extends React.Component {
      state = { newArr: [] }
      componentDidMount() {
        setInterval(() => {
          const { newArr } = this.state
          const news = '新闻' + (newArr.length + 1)
          this.setState({ newArr: [news, ...newArr] })
        }, 1000);
      }
      getSnapshotBeforeUpdate(prevProps, prevState) {
        return this.refs.list.scrollHeight;// 获取更新前的DOM节点
      }
      componentDidUpdate(prevProps, prevState, snapshot) {
        this.refs.list.scrollTop += this.refs.list.scrollHeight - snapshot;
      }
      render() {
        return <div className="list" ref="list">
          {
            this.state.newArr.map((item, index) => {
              return <div className="news" key={index}>{item}</div>
            })
          }</div>;
      }
}

1.8.3、对比

17+在16+的基础上新增了getDerivedStateFromProps、getSnapshotBeforeUpdate;

即将废弃 componentWillMount、componentWillReceiveProps、componentWillUpdate三个钩子。

1.9、DOM的Diffing算法

经典面试题:为啥key不能使用index,而是取id(唯一标识)

总结:

1、使用 index 作为 key

在列表项的顺序发生变化、增加或删除时,可能会导致错误渲染或状态丢失

适用于列表项不变,且不涉及删除、增加或排序操作的简单情况。

2、使用id 作为 key

更稳定,能够确保元素在更新时保持一致,特别是在列表顺序发生变化时。

尤其是在动态数据列表(增、删、改、排序等操作)中使用。

二、脚手架搭建

2.1、创建项目

1、全局安装:npm i -g create-react-app【查看是否下载create-react-app --version

2、切换到想创建项目的目录下:create-react-app react_app【Node版本在**14+**及以上】

3、进入项目文件夹:cd react_app

4、启动项目:npm start【修改package.json,重新下载node_modules、 package-lock.json来修改版本

或者直接用:React--Umi和Dva_react dva-CSDN博客

相关推荐
kyriewen6 小时前
写组件文档写到吐?我用AI自动生成Storybook,同事以后直接抄
前端·javascript·面试
五点六六六7 小时前
你敢信这是非Native页面写出来的渐变效果吗🌝(底层原理解析
前端·javascript·面试
吃西瓜的年年8 小时前
TypeScript
javascript·ubuntu·typescript
熊猫_豆豆11 小时前
一个模拟四轴飞行器在随机气流扰动下悬停飞行的交互式3D仿真网页,包含飞行器建模与PID控制算法
javascript·3d·html·四轴无人机模拟飞行
来恩100312 小时前
jQuery选择器
前端·javascript·jquery
前端繁华如梦12 小时前
树上挂苹果还是挂玻璃球?Three.js 程序化果实的完整实现指南
前端·javascript
CDwenhuohuo12 小时前
优惠券组件直接用 uview plus
前端·javascript·vue.js
川冰ICE13 小时前
TypeScript装饰器与元编程实战
前端·javascript·typescript
AI砖家13 小时前
Vue3组件传参大全,各种传参方式的对比
前端·javascript·vue.js
希望永不加班13 小时前
var局部变量类型推断的利弊
java·服务器·前端·javascript·html