面试题答案
一键面试具体场景
假设我们正在开发一个电商产品详情页应用。该应用由一个主组件 ProductDetails
作为根组件,它包含了多个子组件,如 ProductInfo
展示产品基本信息,ProductReviews
展示产品评价,AddToCartButton
用于添加商品到购物车。
Props
ProductDetails
组件从其父组件接收产品数据,例如产品名称、价格、描述等,通过 props 传递给 ProductInfo
组件,以便展示这些信息。示例代码如下:
<script>
let product = {
name: "示例产品",
price: 199.99,
description: "这是一款示例产品"
};
</script>
<ProductInfo {product} />
在 ProductInfo
组件中接收 props:
<script>
export let product;
</script>
<h1>{product.name}</h1>
<p>价格: {product.price}</p>
<p>{product.description}</p>
Context
如果应用中有一些全局配置信息,如当前语言设置、主题等,我们可以使用 context 来共享这些数据。例如,我们创建一个 AppContext
用于共享语言设置。
在父组件 ProductDetails
中设置 context:
<script>
import { setContext } from'svelte';
let lang = 'zh-CN';
setContext('langContext', lang);
</script>
在子组件 ProductReviews
中获取 context:
<script>
import { getContext } from'svelte';
let lang = getContext('langContext');
</script>
这样,无论 ProductReviews
组件在组件树中处于多深的位置,都能获取到语言设置。
事件派发
当用户点击 AddToCartButton
组件时,需要通知父组件 ProductDetails
执行添加到购物车的逻辑。AddToCartButton
组件派发一个事件,ProductDetails
组件监听该事件。
在 AddToCartButton
组件中派发事件:
<script>
import { createEventDispatcher } from'svelte';
const dispatch = createEventDispatcher();
function addToCart() {
dispatch('add-to-cart');
}
</script>
<button on:click={addToCart}>添加到购物车</button>
在 ProductDetails
组件中监听事件:
<script>
function handleAddToCart() {
// 执行添加到购物车的逻辑,如调用 API
console.log('添加到购物车成功');
}
</script>
<AddToCartButton on:add-to-cart={handleAddToCart} />
最佳实践
- Props 传递:保持 props 数据简洁明了,尽量避免传递过多无关数据。同时,明确 props 的类型,使用 TypeScript 或 JSDoc 进行类型注释,提高代码的可维护性。
- Context 使用:只将真正全局且需要广泛共享的数据放入 context,避免滥用 context 导致数据流向不清晰。对 context 数据的变化进行适当管理,例如使用响应式数据机制来通知依赖组件更新。
- 事件派发:为事件命名时遵循清晰的命名规范,能准确表达事件的含义。在事件处理函数中进行必要的错误处理,确保应用的稳定性。
需要避免的陷阱
- Props 陷阱:避免 props 层级过深传递,这会使组件间的耦合度增加,不利于组件的复用和维护。如果出现这种情况,可以考虑使用 context 或其他状态管理方案。
- Context 陷阱:避免在 context 中存储易变的数据,因为 context 的变化不会自动触发依赖组件的重新渲染,可能导致数据不一致。同时,注意不同模块对 context 的命名冲突问题,建议使用唯一的命名空间。
- 事件派发陷阱:在事件派发时确保事件的作用域正确,避免事件处理函数中的
this
指向错误。另外,要注意事件的冒泡和捕获机制,防止事件处理的逻辑冲突。