base深圳 冰智科技 前端实习面经
投递渠道:BOSS
时间线
- 2024-02-16 打招呼投简历
- 2024-02-18 一面
- 2024-02-24 二面
一面
- 自我介绍与实习经历介绍
1. Vue3 生命周期
在Vue 3中,生命周期钩子函数和Vue 2有一些变化,主要是针对Composition API的引入以及对Options API的改进。以下是Vue 3中的主要生命周期钩子函数:
-
beforeCreate:
- 在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。
-
created:
- 实例已经创建完成之后被调用。在这一步,实例已完成以下的配置:数据观测 (data observer),属性和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el属性目前不可见。
-
beforeMount:
- 在挂载开始之前被调用:相关的render函数首次被调用。
-
mounted:
- el 被新创建的 vm.el 也在文档内。
-
beforeUpdate:
- 数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。这里适合在更新之前访问现有 DOM,比如手动移除已添加的事件监听器。
-
updated:
- 由于数据更改导致的虚拟 DOM 重新渲染和打补丁后调用。调用时,组件 DOM 已更新,可以执行依赖于DOM的操作。
-
beforeUnmount:
- 在卸载之前调用。在这个阶段,实例仍然完全可用。
-
unmounted:
- 在卸载之后调用。这个时候,实例的所有指令已经解绑,所有的事件监听器已经移除。
-
errorCaptured:
- 当捕获一个来自子孙组件的错误时被调用。
需要注意的是,Vue 3中移除了Vue 2中的beforeDestroy和destroyed钩子函数,取而代之的是beforeUnmount和unmounted,以更贴合Composition API的语义。
3. v-if 与 v-show 的区别
v-if和v-show都是Vue.js中用于条件渲染的指令,但它们之间有一些重要的区别:
- v-if:
v-if是“条件性地渲染”一个元素。即根据表达式的真假来决定是否渲染该元素及其内部内容。- 当表达式为真时,元素会被渲染到DOM中;当表达式为假时,元素不会被渲染到DOM中。
- 在切换时,
v-if条件块内的事件监听器和子组件适当地被销毁和重建,有助于节省内存消耗。
<div v-if="isDisplayed">
Content to be displayed
</div>
- v-show:
v-show是“条件性地显示或隐藏”一个元素。即根据表达式的真假来控制元素的显示或隐藏。- 当表达式为真时,元素会显示在页面上;当表达式为假时,元素会被设置为
display: none,仍然存在于DOM中。 - 在切换时,
v-show元素不会被销毁和重建,因此它的事件监听器和子组件保持在DOM中,但是可能会影响页面的性能。
<div v-show="isDisplayed">
Content to be displayed
</div>
主要区别总结如下:
v-if:在切换时条件块内的事件监听器和子组件会被销毁和重建,有助于节省内存消耗,适用于不经常切换的场景。v-show:在切换时元素只是简单地切换了display属性,不会被销毁和重建,但可能会影响页面性能,适用于经常切换的场景。
因此,通常情况下,如果需要频繁切换元素的显示和隐藏,则可以使用v-show;如果只是需要根据条件动态渲染元素,可以使用v-if。
- 什么是虚拟 DOM
4. useState 和 useEffect 如何使用
在React中,useState和useEffect是两个常用的Hooks,用于管理组件的状态和副作用。下面分别介绍它们的使用方法:
使用 useState:
useState用于在函数式组件中添加状态。它接收一个初始状态作为参数,并返回一个状态变量和一个更新状态的函数,通常约定为数组解构赋值的形式。
import React, { useState } from 'react';
function MyComponent() {
// 使用useState声明状态变量和更新函数
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
{/* 点击按钮时调用setCount更新状态 */}
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
使用 useEffect:
useEffect用于在函数式组件中执行副作用操作,比如订阅数据、操作DOM等。它接收一个回调函数作为参数,函数体内可以执行副作用操作,并返回一个清除副作用的函数(可选)。
import React, { useState, useEffect } from 'react';
function MyComponent() {
const [count, setCount] = useState(0);
// 使用useEffect执行副作用操作
useEffect(() => {
// 更新文档标题
document.title = `You clicked ${count} times`;
// 返回清除副作用的函数(可选)
return () => {
document.title = 'React App';
};
}, [count]); // 第二个参数是依赖数组,表示什么状态变量发生变化时执行副作用
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
在上面的例子中,useEffect中的回调函数会在组件渲染后执行,并且每次count状态变化时都会执行。在这个例子中,我们使用useEffect来更新文档标题,并在组件卸载时清除副作用。
6. React 中 state 与 props 有什么区别(通常 state 的改变由网络请求或者用户操作引起,props 由父组件传递)
在React中,state和props都是用于管理组件数据的机制,但它们有一些重要的区别:
State(状态):
-
定义位置:
- state是由组件自身管理的数据,可以在组件内部通过useState或者this.state来定义和更新。
-
可变性:
- state是可变的,组件可以通过调用setState方法来更新state,并且更新state会触发组件的重新渲染。
-
作用范围:
- state的作用范围是局部的,即只能在定义它的组件内部访问和修改。
-
数据源:
- state通常用于存储组件内部的状态数据,例如用户输入、组件的展开状态等。
Props(属性):
-
定义位置:
- props是由父组件传递给子组件的数据,子组件无法直接修改props,只能通过父组件重新传递props来更新。
-
不可变性:
- props是不可变的,子组件无法直接修改props的值,只能通过父组件重新传递新的props来更新。
-
作用范围:
- props的作用范围是组件之间的通信,通过props可以将数据从父组件传递给子组件。
-
数据源:
- props通常用于传递数据给子组件,例如配置信息、初始化数据等。
总的来说,state和props都是用于管理组件数据的机制,但它们的定义位置、可变性、作用范围和数据源等方面有所不同。在React中,通常将组件的内部状态存储在state中,而将来自父组件的数据传递给子组件通过props实现。
8. key 的作用
在React中,key是用于帮助React识别列表中各个元素的唯一标识符。它主要的作用包括:
-
提高列表渲染性能: 当列表中的元素发生变化时,React会根据元素的key来识别哪些元素发生了变化、被添加或被移除,从而最小化DOM操作,提高渲染性能。
-
帮助React进行组件重用: 当列表中的元素发生变化时,React会尽可能地复用已经存在的组件实例,而不是重新创建一个新的实例。通过key的唯一性,React可以准确地判断哪些组件需要被更新,哪些组件需要被重新渲染。
-
维护组件的状态: 在列表中的元素发生变化时,如果没有为每个元素指定唯一的key,React会导致组件的状态混乱,可能会出现错误的更新或重新渲染。
-
优化动画效果: 在列表中元素发生变化时,通过key的唯一性,可以帮助React更好地处理动画效果,使得动画的过渡更加流畅自然。
总的来说,key是React中用于列表渲染优化和组件重用的重要机制,是帮助React识别和管理列表中各个元素的关键。因此,在使用React进行列表渲染时,应该为每个列表元素指定唯一的key,以确保React能够正确地识别和管理列表中的元素。
- 实习:如何进行项目规范搭建
- 实习:如何进行性能优化
11. 项目:介绍一下项目中如何使用 rollup 的
在项目中使用Rollup主要是为了打包JavaScript代码,它是一个功能强大的打包工具,特别适合用于构建JavaScript库和模块。
下面是使用Rollup的基本流程和一些常见的配置方式:
安装 Rollup:
npm install rollup --save-dev
创建配置文件:
创建一个名为rollup.config.js的配置文件,用于配置Rollup的打包规则和插件。
// rollup.config.js
import babel from '@rollup/plugin-babel';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'umd'
},
plugins: [
resolve(),
commonjs(),
babel({
exclude: 'node_modules/**' // 只编译我们的源代码
})
]
};
编写源代码:
编写你的JavaScript源代码,通常放在src目录下。
运行 Rollup 打包:
运行以下命令来执行Rollup打包:
rollup -c
或者将其添加到package.json的scripts中:
{
"scripts": {
"build": "rollup -c"
}
}
然后可以通过以下命令执行打包:
npm run build
使用插件:
Rollup本身只能处理ES模块,但是大部分的项目可能会包含CommonJS或AMD模块,所以需要使用一些插件来处理这些模块的引入。在配置文件中,我们使用了@rollup/plugin-node-resolve插件来帮助解析node_modules中的模块,以及@rollup/plugin-commonjs插件来将CommonJS模块转换为ES模块。
另外,我们还使用了@rollup/plugin-babel插件来使用Babel进行代码转换,使得我们可以在代码中使用ES6+语法,并且可以通过配置选项指定需要排除的文件或目录。
总的来说,Rollup是一个强大而灵活的打包工具,可以帮助我们将JavaScript代码打包成各种不同格式的文件,同时也支持各种插件来处理不同类型的模块和语法。
12. 手写代码:现场其一个 react 项目并实现一个 TodoList
以下是一个简单的React项目,实现了一个TodoList:
import React, { useState } from 'react';
function TodoList() {
const [todos, setTodos] = useState([]);
const [inputValue, setInputValue] = useState('');
const handleInputChange = (e) => {
setInputValue(e.target.value);
};
const handleAddTodo = () => {
if (inputValue.trim() !== '') {
setTodos([...todos, inputValue]);
setInputValue('');
}
};
const handleDeleteTodo = (index) => {
const newTodos = [...todos];
newTodos.splice(index, 1);
setTodos(newTodos);
};
return (
<div>
<h2>Todo List</h2>
<input
type="text"
value={inputValue}
onChange={handleInputChange}
placeholder="Enter a new todo"
/>
<button onClick={handleAddTodo}>Add Todo</button>
<ul>
{todos.map((todo, index) => (
<li key={index}>
{todo}
<button onClick={() => handleDeleteTodo(index)}>Delete</button>
</li>
))}
</ul>
</div>
);
}
export default TodoList;
在这个例子中,我们使用了useState来管理TodoList中的状态,包括todo列表和输入框的值。当用户输入新的todo时,通过handleAddTodo函数将其添加到todo列表中;当用户点击某个todo的删除按钮时,通过handleDeleteTodo函数删除对应的todo。