问题
某小公司100-500人
-
自我介绍 -
react 组件传参 -
hooks 解决了什么问题,状态复用 -
react.lazy 和 suspence -
useEffect 的return 的执行时机 -
redux 的中间件用过哪些?聊一下saga -
用过哪些 hook,包括自定义 hook,和开源的 hook -
redux 的usememoselect?用过没? -
ts常用工具函数,infer 推断用过没 -
node写过没,在哪些地方用过? -
dockerfile 的最佳实践,sed 命令的报错总结
react组件传参
-
Props(属性)传递:
最常见的方式是通过 props 向组件传递参数。这是一种将数据从父组件传递给子组件的方式。在子组件中,你可以通过 this.props 或函数组件中的参数来访问这些属性。
例子(类组件):
class MyComponent extends React.Component {
render() {
return <div>{this.props.name}</div>;
}
}
// 在父组件中使用
<MyComponent name="John" />
例子(函数组件):
function MyComponent(props) {
return <div>{props.name}</div>;
}
// 在父组件中使用
<MyComponent name="John" />
-
Context(上下文)传递:
React 的 Context API 允许你在组件树中传递数据,而不需要将数据逐级传递给每个中间组件。这对于在深嵌套的组件中传递全局数据非常有用。
例子:
// 创建一个 Context
const MyContext = React.createContext();
// 在父组件中提供数据
<MyContext.Provider value="Hello, World!">
<MyComponent />
</MyContext.Provider>
// 在子组件中访问数据
function MyComponent() {
const data = useContext(MyContext);
return <div>{data}</div>;
}
-
Route 参数传递:
如果你在使用 React Router 或类似的路由库,你可以通过路由参数来传递数据给组件。
例子(React Router):
// 在路由配置中定义参数
<Route path="/user/:userId" component={UserProfile} />
// 在组件中访问参数
function UserProfile(props) {
const userId = props.match.params.userId;
// ...
}
-
状态管理库(如 Redux 或 Mobx):
在大型应用中,可能需要更高级的状态管理。状态管理库可以用来集中管理应用程序的状态,并允许组件之间共享数据。
例子(Redux):
// 定义一个 Redux action 来传递数据
const setName = (name) => ({
type: 'SET_NAME',
payload: name,
});
// 在组件中使用 Redux store
import { connect } from 'react-redux';
function MyComponent(props) {
return <div>{props.name}</div>;
}
const mapStateToProps = (state) => ({
name: state.name,
});
export default connect(mapStateToProps)(MyComponent);
-
事件回调传递:
你可以通过回调函数将参数传递给子组件,以便子组件可以触发事件并将数据传递回父组件。
例子:
class ParentComponent extends React.Component {
handleChildClick = (data) => {
// 处理来自子组件的数据
console.log(data);
}
render() {
return <ChildComponent onClick={this.handleChildClick} />;
}
}
class ChildComponent extends React.Component {
handleClick = () => {
const data = "Hello, World!";
this.props.onClick(data);
}
render() {
return <button onClick={this.handleClick}>Click Me</button>;
}
}
hooks 解决了什么问题,状态复用
hooks 解决了什么问题
-
复杂组件的逻辑分离:在以前的 React 类组件中,当组件包含多个生命周期方法、事件处理程序和状态管理代码时,组件会变得复杂且难以维护。Hooks 允许将组件的逻辑拆分为更小、更可管理的部分,使代码更加清晰和易于理解。
-
复用状态逻辑:以前,如果你需要在多个组件之间共享状态逻辑,你必须使用高阶组件 (HOC) 或 Render Props 模式。Hooks 提供了 useState 和 useEffect 等钩子,使你能够轻松地在不同组件之间重用状态逻辑,而无需使用复杂的模式。
-
副作用管理:在类组件中,副作用代码通常位于 componentDidMount、componentDidUpdate 和 componentWillUnmount 等生命周期方法中。Hooks 引入了 useEffect 钩子,它使副作用的管理更加明确和一致。此外,useEffect 还可以处理清理和取消订阅等操作。
-
更轻量的组件:使用类组件时,每个组件都需要创建一个类实例,这可能会导致性能开销。Hooks 使用函数组件,因此在内部更轻量,更高效。
-
可测试性:函数组件更容易进行单元测试,因为它们只是纯函数,不需要考虑类组件中的生命周期和实例方法。
-
减少样板代码:Hooks 可以减少类组件中的样板代码,例如构造函数、super(props) 调用和 this 关键字。这使得代码更加简洁和易于编写。
-
更好的类型推断:Hooks 在 TypeScript 和 Flow 等类型检查工具中具有更好的类型推断支持,因此可以帮助你在编译时捕获更多的错误。
状态复用
-
自定义 Hook:你可以创建自定义 Hook 来封装共享状态的逻辑。自定义 Hook 是一个函数,可以在不同组件中使用,以共享相同的状态逻辑。。
// 自定义 Hook
import { useState } from 'react';
function useSharedState(initialValue) {
const [state, setState] = useState(initialValue);
const updateState = (newValue) => {
setState(newValue);
};
return [state, updateState];
}
// 在多个组件中使用自定义 Hook
function ComponentA() {
const [sharedState, setSharedState] = useSharedState(initialValue);
// 使用 sharedState
}
function ComponentB() {
const [sharedState, setSharedState] = useSharedState(initialValue);
// 使用 sharedState
}
-
React Context:React 的 Context API 允许你在整个组件树中传递数据,而不需要将数据逐级传递给每个中间组件。这对于状态复用非常有用,特别是在深嵌套的组件中。
你可以创建一个包含共享状态的上下文对象,并在需要访问共享状态的组件中使用 useContext 钩子来获取共享状态。
// 创建一个共享状态的上下文
const SharedStateContext = React.createContext();
// 在父组件中提供共享状态
function ParentComponent() {
const sharedState = /* 初始化状态 */;
return (
<SharedStateContext.Provider value={sharedState}>
<ChildComponent />
</SharedStateContext.Provider>
);
}
// 在子组件中访问共享状态
function ChildComponent() {
const sharedState = useContext(SharedStateContext);
// 使用 sharedState
}
-
状态管理库(如 Redux 或 Mobx):在大型应用中,状态管理库可以用来集中管理应用程序的状态,并允许组件之间共享数据。这是一种更高级的状态共享方式,适用于复杂的应用。
Redux 是一个流行的状态管理库,它使用单一的全局状态存储,允许多个组件访问和修改该状态。你可以使用 react-redux 库来将 Redux 集成到 React 应用中。
以下是一个示例,展示了如何在 Redux 中实现状态复用:
// 使用 Redux 和 react-redux
import { createStore } from 'redux';
import { Provider, useSelector, useDispatch } from 'react-redux';
// 创建 Redux store
const initialState = /* 初始状态 */;
const rootReducer = (state = initialState, action) => {
// 处理不同的 action 类型
};
const store = createStore(rootReducer);
// 在组件中使用 Redux
function MyComponent() {
const sharedState = useSelector((state) => state.sharedState);
const dispatch = useDispatch();
// 使用 sharedState 和 dispatch
}
// 在应用程序的根组件中提供 Redux 的 Provider
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
react.lazy 和 suspence
React.lazy 和 Suspense 是 React 16.6 中引入的两个重要特性,用于实现懒加载(Lazy Loading)组件的方式,以提高应用程序的性能和用户体验。它们通常一起使用。
-
React.lazy:
React.lazy 是一个函数,它允许你动态加载(懒加载)一个组件,只有在该组件实际需要渲染时才会加载它。这有助于减少应用程序的初始加载时间,特别是对于大型应用来说,因为不会一次性加载所有组件。
使用方法如下:
const LazyComponent = React.lazy(() => import('./LazyComponent'));
function App() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
</div>
);
}
在上面的示例中,React.lazy 用于动态加载名为 LazyComponent 的组件。当该组件需要渲染时,React 会自动加载它。
-
Suspense:
Suspense 是一个新的 React 组件,它用于处理组件的懒加载过程中可能发生的加载延迟。你可以使用 Suspense 包装一个或多个懒加载组件,并提供一个 fallback 属性,以指定在加载懒加载组件时要显示的占位符。
在上面的示例中,<Suspense> 包装了 <LazyComponent>,并提供了一个 fallback 属性,以便在加载 LazyComponent 时显示 “Loading…”。
请注意,Suspense 不仅用于懒加载组件的情况,它还可以用于处理数据获取等异步操作的加载延迟。
-
使用方式:
使用 React.lazy 和 Suspense 的主要步骤如下:
使用 React.lazy 创建一个懒加载组件。 将懒加载组件用在需要的地方,通常用 <Suspense> 包装。 在 <Suspense> 中指定一个 fallback,以便在加载懒加载组件时显示加载状态。 当懒加载组件被渲染时,React 会自动触发加载。 通过这种方式,你可以更好地管理应用程序的加载性能,只加载用户实际需要的内容,从而提高用户体验。
需要注意的是,React.lazy 和 Suspense 目前主要用于处理组件的懒加载,对于数据获取等异步操作,你可能需要使用其他方案,如 React Query 或使用异步状态管理库(如 Redux、Mobx)来处理。
useEffect 的return 的执行时机
-
组件卸载时执行:如果 useEffect 的清理函数没有依赖项数组(即没有第二个参数),或者依赖项数组是一个空数组 [],那么清理函数会在组件卸载时执行。这是清理副作用的常见方式,例如在组件卸载时取消订阅或清除定时器。。
useEffect(() => {
// 副作用代码
return () => {
// 清理副作用代码
};
}, []); // 依赖项数组为空
-
下一个 useEffect 执行前执行:如果 useEffect 的清理函数有依赖项数组,并且依赖项发生变化(即依赖项数组中的元素发生了变化),则清理函数会在下一个 useEffect 钩子的执行之前执行。这是清理先前副作用并准备执行新副作用的方式。
const [count, setCount] = useState(0);
useEffect(() => {
// 副作用代码
return () => {
// 清理副作用代码
};
}, [count]); // 依赖项是 count
总之,useEffect 的清理函数在组件卸载时或在下一个 useEffect 钩子的执行之前执行,具体取决于依赖项数组和它的返回值。你可以根据你的需求和副作用的性质来选择适当的方式来清理副作用。
redux 的中间件用过哪些?聊一下saga
Redux 中间件是一种用于扩展 Redux 的功能的机制。通过中间件,你可以在 Redux 的 action 被派发和 reducer 处理 action 之间插入额外的逻辑。我将简要介绍一些常见的 Redux 中间件,然后深入聊一下 Redux Saga。
-
Redux Thunk:
Redux Thunk 是一个非常流行的中间件,它允许你在 action 创建函数中返回函数而不仅仅是一个普通的 action 对象。这个函数可以在异步操作完成后分发真正的 action 对象,用于处理异步数据流。
const fetchUserData = (userId) => {
return async (dispatch) => {
dispatch({ type: 'FETCH_USER_REQUEST' });
try {
const response = await api.fetchUser(userId);
dispatch({ type: 'FETCH_USER_SUCCESS', payload: response.data });
} catch (error) {
dispatch({ type: 'FETCH_USER_FAILURE', payload: error });
}
};
};
Redux Thunk 用法是处理异步操作的一种常见方式。但是,当你的应用中包含复杂的异步流程时,Redux Saga 可能是更好的选择。
-
Redux Saga:
Redux Saga 是一个用于处理副作用(如异步调用和多个 action 之间的协调)的库。它基于 generator 函数,使得副作用的控制流变得非常清晰和易于测试。
Redux Saga 提供了一种将副作用逻辑从组件中分离出来的方式,使得你可以将这些逻辑单独测试,并将应用程序的业务逻辑与副作用逻辑解耦。
以下是一个使用 Redux Saga 的简单示例:
import { call, put, takeEvery } from 'redux-saga/effects';
import { fetchUserSuccess, fetchUserFailure } from './actions';
import * as api from './api';
function* fetchUser(action) {
try {
const response = yield call(api.fetchUser, action.payload.userId);
yield put(fetchUserSuccess(response.data));
} catch (error) {
yield put(fetchUserFailure(error));
}
}
function* userSaga() {
yield takeEvery('FETCH_USER_REQUEST', fetchUser);
}
export default userSaga;
在这个示例中,fetchUser generator 函数处理了异步数据获取并分发了成功或失败的 action。userSaga generator 函数监听 FETCH_USER_REQUEST action,并调用 fetchUser 函数来处理它。
总的来说,Redux Saga 是一个非常强大和灵活的中间件,用于处理复杂的副作用和异步逻辑。它提供了一种清晰、可测试和可维护的方式来管理副作用,特别适用于大型应用程序或需要复杂异步逻辑的应用程序。但需要注意,学习和使用 Redux Saga 可能需要一些时间和努力。
用过哪些 hook,包括自定义 hook,和开源的 hook
「内置的 React Hook」:
-
useState:用于在函数组件中管理状态。 -
useEffect:用于在函数组件中执行副作用操作,例如数据获取、订阅和 DOM 操作。 -
useContext:用于在函数组件中访问 React 上下文(Context)。 -
useReducer:用于在函数组件中管理复杂状态逻辑,类似于 Redux 的 reducer。 -
useRef:用于获取对 DOM 元素的引用,并在函数组件渲染之间保留变量。 -
useMemo:用于记忆计算昂贵的值,以避免不必要的重新计算。 -
useCallback:用于记忆回调函数,以避免不必要的重新渲染。 -
useLayoutEffect:与 useEffect 类似,但会在 DOM 更新之前同步触发。
「自定义 Hook」:
-
useLocalStorage:用于在本地存储中保存和检索数据的自定义 Hook。 -
useDarkMode:用于切换应用程序主题模式(暗模式和亮模式)的自定义 Hook。 -
useForm:用于处理表单输入的自定义 Hook,包括输入验证和提交处理。 -
usePagination:用于管理分页器状态的自定义 Hook,用于分页数据的展示。 -
useDebounce:用于处理输入框或搜索框的输入防抖操作的自定义 Hook。 -
useScroll:用于监听页面滚动事件的自定义 Hook,用于实现无限滚动加载等功能。
「开源的 React Hook」:
-
react-query:用于数据获取和缓存的库,提供了一系列强大的 Hook,用于处理数据的异步获取、缓存和自动失效。 -
react-router:React Router 提供了多个用于路由和导航的 Hook,如 useParams、useHistory 和 useLocation。 -
react-query/devtools:与 react-query 配合使用的开发者工具 Hook,用于在开发环境中监控数据查询和状态。 -
react-use:一个包含各种有用 Hook 的开源库,包括 useLocalStorage、useAsync、useEventListener 等。
redux 的useSelector 和 useDispatch?用过没?
useSelector 和 useDispatch 是 React Redux 库中提供的两个常用的 Hook,用于在函数组件中连接 Redux 的状态和分发 action。它们是 Redux Toolkit 和 React Redux Hooks 的一部分,使得在函数组件中更方便地与 Redux 进行交互。
-
useSelector:
useSelector 是用于从 Redux store 中选择和获取状态的 Hook。你可以使用它来选择感兴趣的部分状态,并在组件中访问该状态的值。
import { useSelector } from 'react-redux';
function MyComponent() {
const count = useSelector((state) => state.counter); // 选择 counter 状态
// 使用 count
}
在上面的示例中,useSelector 接受一个回调函数,该函数返回你希望选择的状态部分。每当 Redux store 中的状态发生变化时,useSelector 将自动重新运行回调函数,并返回新的状态值。
-
useDispatch:
useDispatch 是用于获取 Redux store 的 dispatch 函数的 Hook。你可以使用它来分发 action。
import { useDispatch } from 'react-redux';
function MyComponent() {
const dispatch = useDispatch();
const increment = () => {
dispatch({ type: 'INCREMENT' }); // 分发 INCREMENT action
};
// 使用 increment 函数
}
useDispatch 用于获取分发 action 的函数,你可以在组件中使用它来触发 Redux 中的状态变更。
这两个 Hook 的使用使得在函数组件中与 Redux 进行交互更加简洁和直观。它们不再需要你将 mapStateToProps 和 mapDispatchToProps 连接到组件,而是让你在组件内部直接访问状态和分发 action。这使得代码更加模块化和易于维护。
总之,useSelector 和 useDispatch 是 React Redux 库中提供的两个非常有用的 Hook,用于在函数组件中连接 Redux 并处理状态和 action 的分发。如果你使用 React Redux 来管理状态,建议考虑使用这些 Hook 来简化你的组件代码。
ts常用工具函数,infer 推断用过没
在 TypeScript 中,有一些常用的工具函数和关键字,如 infer,用于实现更强大的类型推断和生成更具表现力的类型定义。下面我将介绍一些常用的 TypeScript 工具函数和 infer 关键字,以及它们的用法。
-
typeof 关键字:typeof 关键字用于获取变量的类型,常用于从已有变量推断类型。
const name = "John";
type NameType = typeof name; // 推断 NameType 为字符串类型
-
keyof 关键字:keyof 关键字用于获取对象类型的键集合。
type Person = {
name: string;
age: number;
};
type PersonKey = keyof Person; // 推断 PersonKey 为 "name" | "age"
-
Partial<T>:Partial 泛型类型可以用来创建一个包含了类型 T 所有属性的可选版本。
type Person = {
name: string;
age: number;
};
type PartialPerson = Partial<Person>; // 推断 PartialPerson 为 { name?: string; age?: number; }
-
Required<T>:Required 泛型类型可以用来创建一个包含了类型 T 所有属性的必选版本。
type PartialPerson = {
name?: string;
age?: number;
};
type RequiredPerson = Required<PartialPerson>; // 推断 RequiredPerson 为 { name: string; age: number; }
-
Pick<T, K>:Pick 泛型类型用于从类型 T 中选择指定的属性键集合 K。
type Person = {
name: string;
age: number;
email: string;
};
type PersonInfo = Pick<Person, "name" | "email">; // 推断 PersonInfo 为 { name: string; email: string; }
-
Exclude<T, U> 和 Extract<T, U>:这两个工具函数用于处理联合类型。Exclude 用于从 T 中排除 U 中包含的类型,而 Extract 用于从 T 中提取出 U 中包含的类型。
type Colors = "red" | "blue" | "green";
type PrimaryColors = "red" | "blue";
type NonPrimaryColors = Exclude<Colors, PrimaryColors>; // 推断 NonPrimaryColors 为 "green"
type CommonColors = Extract<Colors, PrimaryColors>; // 推断 CommonColors 为 "red" | "blue"
-
infer 关键字:infer 关键字常用于条件类型(Conditional Types)中,它允许你推断类型中的某个部分,并将其用于创建其他类型。
type ExtractReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
function greet(): string {
return "Hello!";
}
type Greeting = ExtractReturnType<typeof greet>; // 推断 Greeting 为 string
node写过没,在哪些地方用过?
-
Web 服务器:Node.js 可以用来创建 Web 服务器,处理 HTTP 请求和响应。Express.js 是一个流行的 Node.js 框架,用于快速构建 Web 应用程序和 API。
-
API 服务器:Node.js 可以用于构建 RESTful 或 GraphQL API 服务器,用于前端应用程序的数据交互。
-
实时应用程序:Node.js 适用于构建实时应用程序,如聊天应用程序、在线游戏、协作工具等,通过 WebSocket 或其他实时通信协议实现。
-
命令行工具:Node.js 可以用来编写自定义命令行工具,用于自动化任务、脚本和工作流程。
-
数据处理:Node.js 可以用于处理大量数据,如文件操作、数据导入/导出、数据转换和清洗等。
-
后端微服务:Node.js 可以作为微服务架构的一部分,处理特定的业务逻辑或数据服务。
-
构建工具:Node.js 可以用于构建前端工具,如打包工具(Webpack、Parcel)、任务运行器(Gulp、Grunt)等。
-
服务器端渲染(SSR):Node.js 可以用于服务器端渲染 React、Vue 或其他前端框架的应用程序,以提高首次加载性能。
-
文件上传和存储:Node.js 可以用于处理文件上传、存储和管理,如图片上传、文件云存储等。
-
数据库操作:Node.js 可以与各种数据库系统集成,执行数据库查询、更新和数据操作。
dockerfile 的最佳实践,sed 命令的报错总结
「Dockerfile 的最佳实践」:
-
最小化镜像:使用基础镜像时,尽量选择最小化的基础镜像,以减小镜像的大小。例如,使用 Alpine Linux 镜像可以获得较小的镜像。
-
合理排序指令:将经常更改的指令放在 Dockerfile 末尾,以利用 Docker 缓存。较少更改的指令应该在前面,以确保缓存的最大重用。
-
多阶段构建:对于大型项目,可以使用多阶段构建来减小最终镜像的大小。在第一阶段构建依赖,然后将依赖结果复制到最终阶段。
-
避免不必要的包:只包括运行应用程序所需的依赖项,避免不必要的包,以减小镜像大小。
-
清理不需要的文件:在构建阶段删除不需要的临时文件和缓存,以减小镜像大小。
-
使用 .dockerignore 文件:在构建镜像之前,使用 .dockerignore 文件排除不必要的文件和目录,以提高构建速度和减小镜像大小。
「关于 sed 命令的常见报错和解决方法」:
-
sed 命令未找到:如果在 Dockerfile 中使用 sed 命令,首先确保基础镜像中安装了 sed。你可以使用 RUN 指令来安装 sed,如 RUN apt-get update && apt-get install -y sed。
-
文件不存在:如果 sed 报错说文件不存在,确保在运行 sed 命令之前,目标文件已经存在。你可以使用 COPY 指令将文件复制到容器中,或者使用其他方式创建文件。
-
正则表达式错误:sed 命令中的正则表达式可能会引发错误。请确保你的正则表达式语法正确,并且不包含特殊字符或错误。
-
权限问题:如果 sed 命令试图修改文件但没有权限,你可能需要在 RUN 指令之前添加 chmod 命令来更改文件的权限。
-
换行符问题:在 Windows 上编辑的文件可能包含不同的换行符,导致 sed 命令无法正常运行。在 Windows 上编辑文件时,确保使用 LF(Unix 风格)换行符。
-
sed 命令语法错误:检查 sed 命令的语法,确保它符合 sed 的语法要求。
原文始发于微信公众号(前端大大大):2023前端面试实战篇
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/174169.html