300+ 个 React 面试问题

2025-05-26

300+ 个 React 面试问题

今天我从这个很棒的repo中准备了一份很长的 React 面试问题清单。

欲了解更多信息,我开发了一个项目,其中包含 500 多个面向前端开发人员的问题

这里是:https://iq.js.org/

如果您喜欢这篇文章,请添加到书签以供将来使用并关注我:

目录

不。 问题
核心反应
1 什么是 React?
2 React 的主要特性是什么?
3 什么是 JSX?
4 元素和组件有什么区别?
5 如何在 React 中创建组件?
6 何时使用类组件而不是函数组件?
7 什么是纯组件?
8 React 中的状态是什么?
9 React 中的 props 是什么?
10 状态和道具有什么区别?
11 为什么我们不应该直接更新状态?
12 回调函数作为 setState() 的参数的目的是什么?
十三 HTML 和 React 事件处理有什么区别?
14 如何在 JSX 回调中绑定方法或事件处理程序?
15 如何将参数传递给事件处理程序或回调?
16 React 中的合成事件是什么?
17 什么是内联条件表达式?
18 什么是“key”属性以及在元素数组中使用它有什么好处?
19 refs 有什么用?
20 如何创建 refs?
21 什么是前向引用?
22 回调 refs 和 findDOMNode() 中哪个是首选选项?
23 为什么 String Refs 是遗留的?
24 什么是虚拟 DOM?
二十五 虚拟 DOM 如何工作?
二十六 Shadow DOM 和 Virtual DOM 有什么区别?
二十七 什么是 React Fiber?
二十八 React Fiber 的主要目标是什么?
二十九 什么是受控组件?
三十 什么是不受控制的组件?
31 createElement 和 cloneElement 有什么区别?
三十二 React 中的 Lifting State Up 是什么?
33 组件生命周期有哪些不同阶段?
三十四 React 的生命周期方法有哪些?
三十五 什么是高阶组件?
三十六 如何为 HOC 组件创建 props 代理?
三十七 什么是上下文?
三十八 children 道具是什么?
三十九 如何在 React 中写评论?
40 使用带有 props 参数的超级构造函数的目的是什么?
41 什么是和解?
四十二 如何使用动态键名设置状态?
43 每次组件渲染时调用函数的常见错误是什么?
四十四 惰性函数是否支持命名导出?
45 为什么 React 使用 className 而不是 class 属性?
46 什么是碎片?
四十七 为什么 Fragment 比容器 div 更好?
四十八 React 中的门户是什么?
49 什么是无状态组件?
50 什么是有状态组件?
51 如何在 React 中对 props 应用验证?
52 React 有哪些优点?
53 React 有哪些局限性?
54 React v16 中的错误边界是什么
55 React v15 中如何处理错误边界?
56 静态类型检查的推荐方法有哪些?
57 react-dom 包有什么用?
58 react-dom 的 render 方法的目的是什么?
59 什么是 ReactDOMServer?
60 如何在 React 中使用 InnerHtml?
61 如何在 React 中使用样式?
62 React 中的事件有何不同?
63 如果在构造函数中使用 setState 会发生什么?
64 索引作为键有何影响?
65 在 componentWillMount() 方法中使用 setState() 好吗?
66 如果在初始状态下使用 props 会发生什么?
67 如何有条件地渲染组件?
68 为什么我们在 DOM 元素上传播 props 时需要小心?
69 如何在 React 中使用装饰器?
70 如何记忆组件?
71 如何实现服务器端渲染(SSR)?
72 如何在 React 中启用生产模式?
73 什么是 CRA 及其好处?
74 安装过程中的生命周期方法顺序是什么?
75 React v16 中将弃用哪些生命周期方法?
76 getDerivedStateFromProps() 生命周期方法的用途是什么?
77 getSnapshotBeforeUpdate() 生命周期方法的用途是什么?
78 Hooks 是否会取代渲染道具和高阶组件?
79 推荐的组件命名方式是什么?
80 组件类中方法的推荐顺序是什么?
81 什么是开关组件?
82 为什么我们需要向 setState() 传递一个函数?
83 React 中的严格模式是什么?
84 React Mixins 是什么?
85 为什么 isMounted() 是一种反模式以及正确的解决方案是什么?
86 React 支持哪些指针事件?
87 为什么组件名称要以大写字母开头?
88 React v16 是否支持自定义 DOM 属性?
89 构造函数和 getInitialState 有什么区别?
90 您可以在不调用 setState 的情况下强制组件重新渲染吗?
91 使用 ES6 类的 React 中的 super() 和 super(props) 有什么区别?
92 如何在 JSX 内部循环?
93 如何访问属性引号中的 props?
94 React PropType 数组的形状是什么?
95 如何有条件地应用类属性?
96 React 和 ReactDOM 有什么区别?
97 为什么要将 ReactDOM 与 React 分离?
98 如何使用 React 标签元素?
99 如何组合多个内联样式对象?
100 当浏览器调整大小时如何重新渲染视图?
101 setState 和 replaceState 方法有什么区别?
102 如何监听状态变化?
103 在反应状态下删除数组元素的推荐方法是什么?
104 是否可以在不渲染 HTML 的情况下使用 React?
105 如何使用 React 漂亮地打印 JSON?
106 为什么你不能在 React 中更新 props?
107 如何在页面加载时聚焦输入元素?
108 有哪些可能的方法可以更新状态中的对象?
110 我们如何在浏览器中找到运行时 React 的版本?
111 有哪些方法可以在 create-react-app 中包含 polyfill?
112 如何在 create-react-app 中使用 https 而不是 http?
113 如何避免在 create-react-app 中使用相对路径导入?
114 如何为 react-router 添加 Google Analytics?
115 如何每秒更新一个组件?
116 如何将供应商前缀应用于 React 中的内联样式?
117 如何使用 React 和 ES6 导入和导出组件?
118 React 组件命名有哪些例外?
119 为什么组件构造函数只被调用一次?
120 如何在 React 中定义常量?
121 如何在 React 中以编程方式触发点击事件?
122 可以在普通 React 中使用 async/await 吗?
123 React 的常见文件夹结构有哪些?
124 有哪些流行的动画软件包?
125 样式模块有什么好处?
126 有哪些流行的 React 专用 linters?
127 如何进行 AJAX 调用以及应该在哪些组件生命周期方法中进行 AJAX 调用?
128 什么是渲染道具?
React 路由器
129 什么是 React Router?
130 React Router 与历史库有何不同?
131 React Router v4 的 <Router> 组件是什么?
132 推送和替换历史方法的目的是什么?
133 如何使用 React router v4 以编程方式导航?
134 如何在 React Router v4 中获取查询参数
135 为什么会收到“路由器可能只有一个子元素”警告?
136 如何将参数传递给 React Router v4 中的 history.push 方法?
137 如何实现默认或NotFound页面?
138 如何获取 React Router v4 的历史记录?
139 如何实现登录后自动重定向?
React 国际化
140 什么是 React-Intl?
141 React Intl 的主要功能是什么?
142 React Intl 中有哪两种格式化方式?
143 如何使用 React Intl 将 FormattedMessage 用作占位符?
144 如何使用 React Intl 访问当前语言环境
145 如何使用 React Intl 格式化日期?
反应测试
146 React 测试中的浅渲染器是什么?
147 React 中的 TestRenderer 包是什么?
148 ReactTestUtils 包的用途是什么?
149 什么是 Jest?
150 Jest 相对于 Jasmine 有哪些优势?
151 举一个简单的Jest测试用例的例子
React Redux
152 Flux 是什么?
153 什么是 Redux?
154 Redux 的核心原则是什么?
155 与 Flux 相比,Redux 有哪些缺点?
156 mapStateToProps() 和 mapDispatchToProps() 有什么区别?
157 我可以在 Reducer 中发送一个动作吗?
158 如何在组件外部访问 Redux 存储?
159 MVW 模式的缺点是什么
160 Redux 和 RxJS 之间有什么相似之处吗?
161 如何在加载时分派动作?
162 如何使用 React Redux 中的 connect?
163 如何在 Redux 中重置状态?
164 redux connect 装饰器中的 at 符号的用途是什么?
165 React context 和 React Redux 有什么区别?
166 为什么 Redux 状态函数被称为 Reducer?
167 如何在 Redux 中发出 AJAX 请求?
168 我是否应该将所有组件的状态保存在 Redux 存储中?
169 访问 Redux 存储的正确方法是什么?
170 React Redux 中的组件和容器有什么区别?
171 Redux 中常量的用途是什么?
172 编写 mapDispatchToProps() 有哪些不同的方法?
173 mapStateToProps() 和 mapDispatchToProps() 中的 ownProps 参数有什么用?
174 如何构建 Redux 顶级目录?
175 什么是 redux-saga?
176 redux-saga 的心理模型是什么?
177 redux-saga 中的 call 和 put 有什么区别
178 什么是 Redux Thunk?
179 redux-saga 和 redux-thunk 之间有什么区别
180 什么是 Redux DevTools?
181 Redux DevTools 有哪些功能?
182 什么是 Redux 选择器以及为什么要使用它们?
183 什么是 Redux Form?
184 Redux Form 的主要特性是什么?
185 如何向 Redux 添加多个中间件?
186 如何在 Redux 中设置初始状态?
187 Relay 与 Redux 有何不同?
188 Redux 中的动作是什么?
反应原生
188 React Native 和 React 有什么区别?
189 如何测试 React Native 应用程序?
190 如何在 React Native 中进行日志记录?
191 如何调试你的 React Native?
React 支持的库和集成
192 什么是重新选择以及它如何工作?
193 什么是 Flow?
194 Flow 和 PropTypes 有什么区别?
195 如何在 React 中使用 Font-awesome 图标?
196 什么是 React Dev Tools?
197 为什么 DevTools 无法在 Chrome 中加载本地文件?
198 如何在 React 中使用 Polymer?
199 React 相对于 Vue.js 有哪些优势?
200 React 和 Angular 有什么区别?
201 为什么 React 选项卡没有显示在 DevTools 中?
202 什么是样式组件?
203 给出一个 Styled Components 的例子?
204 什么是 Relay?
205 如何在 create-react-app 应用程序中使用 TypeScript?
各种各样的
206 reselect 库的主要特点是什么?
207 给出一个reselect用法的例子?
209 静态对象可以与 React 中的 ES6 类一起使用吗?
210 Redux 只能与 React 一起使用吗?
211 您是否需要特定的构建工具才能使用 Redux?
212 Redux Form initialValues 如何从状态更新?
213 React PropTypes 如何允许一个 prop 具有不同的类型?
214 我可以导入 SVG 文件作为反应组件吗?
215 为什么不推荐使用内联 ref 回调或函数?
216 React 中的渲染劫持是什么?
217 HOC 工厂实现有哪些?
218 如何将数字传递给 React 组件?
219 我需要把所有状态都保存到 Redux 中吗?我应该使用 React 内部状态吗?
220 React 中 registerServiceWorker 的用途是什么?
221 React 备忘录功能是什么?
222 什么是 React 惰性函数?
223 如何防止使用 setState 进行不必要的更新?
224 如何在 React 16 版本中渲染数组、字符串和数字?
225 如何在 React 类中使用类字段声明语法?
226 什么是钩子?
227 钩子需要遵循什么规则?
228 如何确保钩子遵循项目中的规则?
229 Flux 和 Redux 之间有什么区别?
230 React Router V4 有哪些好处?
231 您能描述一下 componentDidCatch 生命周期方法签名吗?
232 在哪些情况下错误边界不会捕获错误?
233 为什么事件处理程序不需要错误边界?
234 try catch 块和错误边界之间有什么区别?
235 React 16 中未捕获错误的行为是怎样的?
236 错误边界的正确位置是什么?
237 从错误边界进行组件堆栈跟踪有什么好处?
238 类组件需要定义什么方法?
239 render 方法可能的返回类型有哪些?
240 构造函数的主要用途是什么?
241 是否必须为 React 组件定义构造函数?
242 什么是默认道具?
243 为什么不应该在 componentWillUnmount 中调用 setState?
244 getDerivedStateFromError 的目的是什么?
245 组件重新渲染时的方法顺序是什么?
246 错误处理期间调用哪些方法?
247 displayName 类属性的用途是什么?
248 哪些浏览器支持 React 应用程序?
249 unmountComponentAtNode 方法的目的是什么?
250 什么是代码分割?
251 严格模式有什么好处?
252 什么是 Keyed Fragments?
253 React 是否支持所有 HTML 属性?
254 HOC 有哪些局限性?
255 如何在 DevTools 中调试 forwardRefs?
256 组件 props 何时默认为 true?
257 什么是 NextJS 以及它的主要功能?
258 如何将事件处理程序传递给组件?
259 在渲染方法中使用箭头函数好吗?
260 如何防止一个函数被多次调用?
261 JSX 如何防止注入攻击?
262 如何更新渲染元素?
263 怎么说道具是只读的?
264 您如何说状态更新已合并?
265 如何将参数传递给事件处理程序?
266 如何防止组件渲染?
267 安全地使用索引作为键的条件是什么?
268 密钥应该是全局唯一的吗?
269 表单处理的流行选择是什么?
270 formik 相对于 redux 表单库有哪些优势?
271 为什么不需要使用继承?
272 我可以在 React 应用程序中使用 Web 组件吗?
273 什么是动态导入?
274 什么是可加载组件?
275 什么是悬念组件?
276 什么是基于路由的代码拆分?
277 举一个如何使用上下文的例子?
278 上下文中默认值的目的是什么?
279 如何使用 contextType?
280 什么是消费者?
281 在使用上下文时如何解决性能极端情况?
282 HOC 中的 forward ref 的用途是什么?
283 ref 参数是否适用于所有函数或类组件?
284 为什么在使用前向引用时需要额外注意组件库?
285 如何在没有 ES6 的情况下创建 React 类组件?
286 不使用 JSX 可以使用 React 吗?
287 什么是 diffing 算法?
288 差异算法涵盖哪些规则?
289 什么时候需要使用 ref?
290 对于渲染 props,prop 是否必须命名为 render?
291 使用纯组件的渲染道具有什么问题?
292 如何使用渲染道具创建 HOC?
293 什么是开窗技术?
294 如何在 JSX 中打印虚假值?
295 门户的典型用例是什么?
296 如何为不受控制的组件设置默认值?
297 你最喜欢的 React 堆栈是什么?
298 真实 DOM 和虚拟 DOM 有什么区别?
299 如何将 Bootstrap 添加到 React 应用程序?
300 你能列出使用 React 作为前端框架的顶级网站或应用程序吗?
301 建议在 React 中使用 CSS In JS 技术吗?
302 我是否需要用钩子重写所有类组件?
303 如何使用 React Hooks 获取数据?
304 Hooks 是否涵盖了类的所有用例?
305 钩子支持的稳定版本是什么?
306 为什么我们在 useState 中使用数组解构(方括号符号)?
307 引入钩子的来源有哪些?
308 如何访问 Web 组件的命令式 API?
309 什么是 formik?
310 在 Redux 中处理异步调用的典型中间件选择有哪些?
311 浏览器能理解 JSX 代码吗?
312 描述一下 React 中的数据流?
313 什么是反应脚本?
314 create react app 有哪些功能?
315 renderToNodeStream 方法的目的是什么?
316 什么是 MobX?
317 Redux 和 MobX 之间有什么区别?
318 在学习 ReactJS 之前我应该​​学习 ES6 吗?
319 什么是并发渲染?
320 异步模式和并发模式有什么区别?
321 我可以在 react16.9 中使用 javascript url 吗?
322 eslint 插件的 hooks 用途是什么?
323 React 中的命令式和声明式有什么区别?
324 使用 typescript 和 reactjs 有什么好处?
325 使用 Context API 状态管理时,如何确保用户在页面刷新时仍保持身份验证?
326 新的 JSX 转换有哪些好处?
327 新的 JSX 转换与旧的转换有何不同?

核心反应

什么是 React?

React 是一个开源前端 JavaScript 库,用于构建用户界面,尤其是单页应用程序。它用于处理 Web 和移动应用程序的视图层。React 由Facebook 软件工程师Jordan Walke创建。React 于 2011 年首次部署在 Facebook 的 News Feed 上,并于 2012 年部署在 Instagram 上。

⬆ 返回顶部

React 的主要特性是什么?

React 的主要特性包括:

  • 考虑到 RealDOM 操作成本高昂,它使用VirtualDOM而不是 RealDOM。
  • 支持服务器端渲染
  • 遵循单向数据流或数据绑定。
  • 使用可重复使用/可组合的UI 组件来开发视图。

⬆ 返回顶部

什么是 JSX?

JSX是 ECMAScript( JavaScript XML的缩写)的一种类似 XML 的语法扩展。本质上,它只是为函数提供了语法糖React.createElement(),让我们既能拥有 JavaScript 的表达能力,又能拥有类似 HTML 的模板语法。

在下面的示例中,<h1>标签内的文本作为 JavaScript 函数返回给渲染函数。

class App extends React.Component {
  render() {
    return (
      <div>
        <h1>{'Welcome to React world!'}</h1>
      </div>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

元素和组件有什么区别?

元素是一个普通的对象它描述了你希望在屏幕上显示的内容(以 DOM 节点或其他组件的形式)。元素可以在其 props 中包含其他元素。创建 React 元素的成本很低。元素一旦创建,就永远不会改变。

React Element 的对象表示如下:

const element = React.createElement('div', { id: 'login-btn' }, 'Login');
Enter fullscreen mode Exit fullscreen mode

上述React.createElement()函数返回一个对象:

{
  type: 'div',
  props: {
    children: 'Login',
    id: 'login-btn'
  }
}
Enter fullscreen mode Exit fullscreen mode

最后使用以下命令渲染到 DOM ReactDOM.render()

<div id="login-btn">Login</div>
Enter fullscreen mode Exit fullscreen mode

组件可以用多种不同的方式声明。它可以是一个带有方法的类。或者,在简单的情况下,它可以定义为一个函数render()无论哪种情况,它都接受 props 作为输入,并返回一个 JSX 树作为输出:

const Button = ({ onLogin }) => (
  <div id={'login-btn'} onClick={onLogin}>
    Login
  </div>
);
Enter fullscreen mode Exit fullscreen mode

然后 JSX 被转换为React.createElement()函数树:

const Button = ({ onLogin }) =>
  React.createElement('div', { id: 'login-btn', onClick: onLogin }, 'Login');
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如何在 React 中创建组件?

有两种可能的方法可以创建组件。

  1. 函数组件:这是创建组件最简单的方法。这些是纯 JavaScript 函数,接受 props 对象作为第一个参数,并返回 React 元素:
function Greeting({ message }) {
  return <h1>{`Hello, ${message}`}</h1>;
}
Enter fullscreen mode Exit fullscreen mode
  1. 类组件:你也可以使用 ES6 类来定义组件。上面的函数组件可以写成:
class Greeting extends React.Component {
  render() {
    return <h1>{`Hello, ${this.props.message}`}</h1>;
  }
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

何时使用类组件而不是函数组件?

如果组件需要状态或生命周期方法,则使用类组件,否则使用函数组件。但是,从 React 16.8 开始,随着 Hooks 的加入,你可以在函数组件中使用状态、生命周期方法和其他仅在类组件中可用的功能。

⬆ 返回顶部

什么是纯组件?

React.PureComponent与 完全相同,React.Component只是它替shouldComponentUpdate()你处理了该方法。当 props 或 state 发生变化时,PureComponent会对 props 和 state 进行浅比较。而ComponentshouldComponentUpdate则不会将当前的 props 和 state 与下一个 props 和 state 进行比较。因此,每次调用时,组件都会默认重新渲染。

⬆ 返回顶部

React 中的状态是什么?

组件的状态是一个对象,它保存着一些可能在组件生命周期内发生变化的信息。我们应该始终尝试使状态尽可能简单,并尽量减少有状态组件的数量。

让我们创建一个具有消息状态的用户组件,

class User extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      message: 'Welcome to React world',
    };
  }

  render() {
    return (
      <div>
        <h1>{this.state.message}</h1>
      </div>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

状态

状态类似于道具,但它是私有的并且完全由组件控制。即,除了拥有和设置它的组件之外,任何组件都无法访问它。

⬆ 返回顶部

React 中的 props 是什么?

Props是组件的输入。它们是单个值或包含一组值的对象,这些值在创建时使用类似于 HTML 标签属性的命名约定传递给组件。它们是从父组件向下传递到子组件的数据。

React 中 props 的主要目的是提供以下组件功能:

  1. 将自定义数据传递给您的组件。
  2. 触发状态改变。
  3. this.props.reactProp通过组件内部的render()方法使用。

例如,让我们创建一个具有reactProp以下属性的元素:

<Element reactProp={'1'} />
Enter fullscreen mode Exit fullscreen mode

这个reactProp(或者任何你想出来的)名称将成为附加到 React 原生 props 对象的属性,该属性最初已经存在于使用 React 库创建的所有组件上。

props.reactProp
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

状态和道具有什么区别?

propsstate都是普通的 JavaScript 对象。虽然它们都包含影响渲染输出的信息,但它们在组件中的功能有所不同。props 传递给组件的方式类似于函数参数,而 state 则在组件内部进行管理,类似于函数内声明的变量。

⬆ 返回顶部

为什么我们不应该直接更新状态?

如果您尝试直接更新状态,那么它将不会重新渲染组件。

//Wrong
this.state.message = 'Hello world';
Enter fullscreen mode Exit fullscreen mode

请使用setState()方法。它会安排组件状态对象的更新。当状态发生变化时,组件会通过重新渲染来响应。

//Correct
this.setState({ message: 'Hello World' });
Enter fullscreen mode Exit fullscreen mode

注意:您可以在构造函数中或使用最新的 javascript 的类字段声明语法直接分配给状态对象。

⬆ 返回顶部

回调函数作为的参数的目的是什么setState()

回调函数在 setState 完成且组件渲染完成后调用。由于setState()异步操作,因此回调函数可用于任何后续操作。

注意:建议使用生命周期方法而不是此回调函数。

setState({ name: 'John' }, () => console.log('The name has updated and component re-rendered'));
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

HTML 和 React 事件处理有什么区别?

以下是 HTML 和 React 事件处理之间的一些主要区别,

  1. 在 HTML 中,事件名称应小写
<button onclick="activateLasers()"></button>
Enter fullscreen mode Exit fullscreen mode

而在 React 中它遵循camelCase约定:

<button onClick={activateLasers}>
Enter fullscreen mode Exit fullscreen mode
  1. 在 HTML 中,您可以返回来false阻止默认行为:
<a href="#" onclick='console.log("The link was clicked."); return false;' />
Enter fullscreen mode Exit fullscreen mode

而在 React 中你必须preventDefault()明确调用:

function handleClick(event) {
  event.preventDefault();
  console.log('The link was clicked.');
}
Enter fullscreen mode Exit fullscreen mode
  1. 在 HTML 中,您需要通过附加来调用该函数,()而在 React 中,您不应该附加()函数名称。(例如,参考第一点中的“activateLasers”函数)

⬆ 返回顶部

如何在 JSX 回调中绑定方法或事件处理程序?

有 3 种可能的方法可以实现此目的:

  1. 构造函数中的绑定:在 JavaScript 类中,方法默认不绑定。同样适用于定义为类方法的 React 事件处理程序。通常我们在构造函数中绑定它们。
class Component extends React.Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    // ...
  }
}
Enter fullscreen mode Exit fullscreen mode
  1. 公共类字段语法:如果您不喜欢使用绑定方法,那么可以使用公共类字段语法来正确绑定回调。
handleClick = () => {
  console.log('this is:', this);
};
Enter fullscreen mode Exit fullscreen mode
<button onClick={this.handleClick}>{'Click me'}</button>
Enter fullscreen mode Exit fullscreen mode
  1. 回调中的箭头函数:您可以在回调中直接使用箭头函数。
<button onClick={(event) => this.handleClick(event)}>{'Click me'}</button>
Enter fullscreen mode Exit fullscreen mode

注意:如果将回调作为 prop 传递给子组件,这些组件可能会进行额外的重新渲染。在这种情况下,考虑到性能.bind(),建议使用public class fields 语法。

⬆ 返回顶部

如何将参数传递给事件处理程序或回调?

您可以使用箭头函数来包装事件处理程序并传递参数:

<button onClick={() => this.handleClick(id)} />
Enter fullscreen mode Exit fullscreen mode

这相当于调用.bind

<button onClick={this.handleClick.bind(this, id)} />
Enter fullscreen mode Exit fullscreen mode

除了这两种方法之外,你还可以将参数传递给定义为箭头函数的函数

<button onClick={this.handleClick(id)} />;
handleClick = (id) => () => {
  console.log('Hello, your ticket number is', id);
};
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

React 中的合成事件是什么?

SyntheticEvent是浏览器原生事件的跨浏览器包装器。它的 API 与浏览器原生事件相同,包括 和stopPropagation()preventDefault()但事件在所有浏览器中的工作方式相同。

⬆ 返回顶部

什么是内联条件表达式?

您可以使用JS 提供的if 语句三元表达式来有条件地渲染表达式。除了这些方法之外,您还可以将任何表达式嵌入到 JSX 中,方法是将它们括在花括号中,然后跟上 JS 逻辑运算符&&

<h1>Hello!</h1>;
{
  messages.length > 0 && !isLogin ? (
    <h2>You have {messages.length} unread messages.</h2>
  ) : (
    <h2>You don't have unread messages.</h2>
  );
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

什么是“key”属性以及在元素数组中使用它有什么好处?

Akey是一个特殊的字符串属性,在创建元素数组时应该包含它。Key属性帮助 React 识别哪些元素发生了更改、被添加或被删除。

我们通常使用数据中的 ID 作为密钥

const todoItems = todos.map((todo) => <li key={todo.id}>{todo.text}</li>);
Enter fullscreen mode Exit fullscreen mode

当你没有渲染项目的稳定 ID 时,你可以使用项目索引作为作为最后的手段:

const todoItems = todos.map((todo, index) => <li key={index}>{todo.text}</li>);
Enter fullscreen mode Exit fullscreen mode

笔记:

  1. 如果项的顺序可能会发生变化,则不建议对键使用索引。这可能会对性能产生负面影响,并可能导致组件状态出现问题
  2. 如果您将列表项提取为单独的组件,则在列表组件上应用而不是li标签。
  3. key如果列表项中不存在该道具,控制台中将出现一条警告消息。

⬆ 返回顶部

refs 有什么用?

ref用于返回元素的引用。大多数情况下应该避免使用它们,但是,当你需要直接访问 DOM 元素或组件实例时,它们会很有用

⬆ 返回顶部

如何创建 refs?

有两种方法

  1. 这是最近添加的方法。ref使用方法创建,并通过属性附加到 React 元素上。为了在整个组件中使用 ref,只需在构造函数中将 ref 赋值实例属性即可。React.createRef()ref
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }
  render() {
    return <div ref={this.myRef} />;
  }
}
Enter fullscreen mode Exit fullscreen mode
  1. 无论 React 版本如何,你都可以使用 ref 回调方法。例如,搜索栏组件的 input 元素访问如下:
class SearchBar extends Component {
  constructor(props) {
    super(props);
    this.txtSearch = null;
    this.state = { term: '' };
    this.setInputSearchRef = (e) => {
      this.txtSearch = e;
    };
  }
  onInputChange(event) {
    this.setState({ term: this.txtSearch.value });
  }
  render() {
    return (
      <input
        value={this.state.term}
        onChange={this.onInputChange.bind(this)}
        ref={this.setInputSearchRef}
      />
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

你也可以通过闭包在函数组件中使用ref注意:你也可以使用内联 ref 回调,尽管这不是推荐的方法。

⬆ 返回顶部

什么是前向引用?

Ref 转发是一项功能,它允许某些组件获取它们收到的ref,并将其进一步传递给子组件。

const ButtonElement = React.forwardRef((props, ref) => (
  <button ref={ref} className="CustomButton">
    {props.children}
  </button>
));

// Create ref to the DOM button:
const ref = React.createRef();
<ButtonElement ref={ref}>{'Forward Ref'}</ButtonElement>;
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

回调 refs 和 findDOMNode() 中哪个是首选选项?

建议使用回调 refs而不是findDOMNode()API。因为它findDOMNode()会阻碍 React 未来某些功能的改进。

传统使用方法findDOMNode

class MyComponent extends Component {
  componentDidMount() {
    findDOMNode(this).scrollIntoView();
  }

  render() {
    return <div />;
  }
}
Enter fullscreen mode Exit fullscreen mode

推荐的方法是:

class MyComponent extends Component {
  constructor(props) {
    super(props);
    this.node = createRef();
  }
  componentDidMount() {
    this.node.current.scrollIntoView();
  }

  render() {
    return <div ref={this.node} />;
  }
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

为什么 String Refs 是遗留的?

如果您之前使用过 React,您可能熟悉一个较旧的 API,其中ref属性是字符串,例如ref={'textInput'},并且 DOM 节点以 的形式访问this.refs.textInput。我们不建议这样做,因为字符串引用存在以下问题,并且被视为遗留问题。字符串引用已在 React v16 中被移除

  1. 它们强制 React 跟踪当前正在执行的组件。这很成问题,因为它使 React 模块具有状态,因此当 React 模块在 bundle 中重复时会导致奇怪的错误。
  2. 它们不可组合——如果库在传递的子元素上放置了一个引用,用户就无法在其上放置另一个引用。回调引用完全可组合。
  3. 它们不像 Flow 那样支持静态分析。Flow 无法猜测框架是如何让字符串引用出现在 上的this.refs,也无法猜测它的类型(类型可能不同)。回调引用对静态分析更友好。
  4. 它不能像大多数人期望的那样使用“渲染回调”模式(例如)
class MyComponent extends Component {
  renderRow = (index) => {
    // This won't work. Ref will get attached to DataTable rather than MyComponent:
    return <input ref={'input-' + index} />;

    // This would work though! Callback refs are awesome.
    return <input ref={(input) => (this['input-' + index] = input)} />;
  };

  render() {
    return <DataTable data={this.props.data} renderRow={this.renderRow} />;
  }
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

什么是虚拟 DOM?

虚拟DOM (VDOM) 是真实 DOM的内存表示。UI 的表示保存在内存中,并与“真实” DOM 同步。这是在调用渲染函数和元素显示在屏幕上之间发生的一个步骤。整个过程称为协调 (reconciliation)

⬆ 返回顶部

虚拟 DOM 如何工作?

虚拟DOM 的工作原理分为三个简单的步骤。

  1. 每当任何底层数据发生变化时,整个 UI 都会以虚拟 DOM 表示重新渲染。

替代文本

  1. 然后计算先前的 DOM 表示和新的 DOM 表示之间的差异。

替代文本

  1. 一旦计算完成,真实的 DOM 将仅更新实际发生变化的内容。

替代文本

⬆ 返回顶部

Shadow DOM 和 Virtual DOM 有什么区别?

Shadow DOM是一种浏览器技术,主要用于在Web 组件中限定变量和 CSS 的作用域。Virtual DOM是由 JavaScript 库在浏览器 API 之上实现的概念。

⬆ 返回顶部

什么是 React Fiber?

Fiber 是 React v16 中新的协调引擎,或者说是核心算法的重新实现。React Fiber 的目标是提升其在动画、布局、手势、暂停、中止或重用工作以及为不同类型的更新分配优先级等领域的适用性,以及新的并发原语。

⬆ 返回顶部

React Fiber 的主要目标是什么?

React Fiber的目标是提升其在动画、布局和手势等领域的适用性。其核心功能是增量渲染:能够将渲染工作拆分成多个块,并将其分散到多个帧上。

⬆ 返回顶部

什么是受控组件?

在后续用户输入时控制表单内输入元素的组件称为受控组件,即每个状态突变都会有一个相关的处理程序函数。

例如,要将所有名称都写成大写字母,我们使用下面的 handleChange,

handleChange(event) {
this.setState({value: event.target.value.toUpperCase()})
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

什么是不受控制的组件?

非受控组件指在内部存储自身状态的组件,需要时可以使用 ref 查询 DOM 来获取其当前值。这更像传统的 HTML。

在下面的 UserProfile 组件中,name使用 ref 访问输入。

class UserProfile extends React.Component {
  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.input = React.createRef();
  }

  handleSubmit(event) {
    alert('A name was submitted: ' + this.input.current.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          {'Name:'}
          <input type="text" ref={this.input} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

大多数情况下,建议使用受控组件来实现表单。

⬆ 返回顶部

createElement 和 cloneElement 有什么区别?

JSX 元素将被转换为React.createElement()函数,以创建用于 UI 对象表示的 React 元素。而 则cloneElement用于克隆元素并向其传递新的 props。

⬆ 返回顶部

React 中的 Lifting State Up 是什么?

当多个组件需要共享相同的变化数据时,建议将共享状态提升到它们最近的共同祖先组件。这意味着,如果两个子组件共享来自其父组件的相同数据,则将状态移动到父组件,而不是在两个子组件中都维护本地状态。

⬆ 返回顶部

组件生命周期有哪些不同阶段?

组件生命周期有三个不同的生命周期阶段:

  1. 挂载:组件已准备好挂载到浏览器 DOM 中。此阶段涵盖constructor()getDerivedStateFromProps()render()componentDidMount()生命周期方法的初始化。

  2. 更新:在此阶段,组件通过两种方式更新:发送新的 props 以及从setState()或更新状态forceUpdate()。此阶段涵盖getDerivedStateFromProps()shouldComponentUpdate()render()生命周期方法getSnapshotBeforeUpdate()componentDidUpdate()

  3. 卸载:在最后一个阶段,组件不再需要,并从浏览器 DOM 中卸载。此阶段包含componentWillUnmount()生命周期方法。

值得一提的是,React 内部在 DOM 操作中有一个阶段的概念。它们被划分如下:

  1. 渲染:组件将渲染,且不会产生任何副作用。这适用于纯组件,并且在此阶段,React 可以暂停、中止或重新启动渲染。

  2. 预提交在组件实际将更改应用于 DOM 之前,有一个时刻允许 React 通过 从 DOM 读取getSnapshotBeforeUpdate()

  3. Commit React 与 DOM 协同工作,并分别执行componentDidMount()挂载、componentDidUpdate()更新和componentWillUnmount()卸载的最终生命周期。

React 16.3+ 阶段(或交互式版本

替代文本

React 16.3 之前

替代文本

⬆ 返回顶部

React 的生命周期方法有哪些?

React 16.3 之前

  • componentWillMount:渲染之前执行,用于根组件中的应用程序级别配置。
  • componentDidMount:首次渲染后执行,所有 AJAX 请求、DOM 或状态更新以及设置的事件监听器都应该在这里发生。
  • componentWillReceiveProps:当特定 prop 更新以触发状态转换时执行。
  • shouldComponentUpdate:确定组件是否更新。默认情况下返回true。如果您确定组件在状态或属性更新后无需渲染,则可以返回 false 值。这是一个很好的提升性能​​的地方,因为它允许您在组件收到新的属性时避免重新渲染。
  • componentWillUpdate:当 props 和 state 发生变化时,在重新渲染组件之前执行,并shouldComponentUpdate()返回 true。
  • componentDidUpdate:主要用于响应 prop 或 state 的变化来更新 DOM。
  • componentWillUnmount:它将用于取消任何传出的网络请求,或删除与组件关联的所有事件监听器。

React 16.3+

  • getDerivedStateFromProps:在调用之前调用,并且每次render()渲染时都会调用。这适用于需要派生状态的罕见情况。如果你需要派生状态,值得一读。
  • componentDidMount:首次渲染后执行,所有 AJAX 请求、DOM 或状态更新以及设置的事件监听器都应该在这里发生。
  • shouldComponentUpdate:确定组件是否更新。默认情况下返回true。如果您确定组件在状态或属性更新后无需渲染,则可以返回 false 值。这是一个很好的提升性能​​的地方,因为它允许您在组件收到新的属性时避免重新渲染。
  • getSnapshotBeforeUpdate:在渲染输出提交到 DOM 之前执行。此方法返回的任何值都将传入componentDidUpdate()。这对于从 DOM 中捕获信息(例如滚动位置)非常有用。
  • componentDidUpdate:主要用于响应 prop 或 state 的变化来更新 DOM。如果shouldComponentUpdate()返回 ,则不会触发false
  • componentWillUnmount它将用于取消任何传出的网络请求,或删除与组件关联的所有事件监听器。

⬆ 返回顶部

什么是高阶组件?

高阶组件HOC 是一个函数,它接受一个组件作为参数并返回一个新组件。本质上,它是一种源自 React 组合特性的模式。

我们称它们为纯组件,因为它们可以接受任何动态提供的子组件,但它们不会修改或复制其输入组件的任何行为。

const EnhancedComponent = higherOrderComponent(WrappedComponent);
Enter fullscreen mode Exit fullscreen mode

HOC 可用于多种用例:

  1. 代码重用、逻辑和引导抽象。
  2. 渲染劫持。
  3. 状态抽象和操作。
  4. 道具操控。

⬆ 返回顶部

如何为 HOC 组件创建 props 代理?

您可以使用props 代理模式添加/编辑传递给组件的 props,如下所示:

function HOC(WrappedComponent) {
  return class Test extends Component {
    render() {
      const newProps = {
        title: 'New Header',
        footer: false,
        showFeatureX: false,
        showFeatureY: true,
      };

      return <WrappedComponent {...this.props} {...newProps} />;
    }
  };
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

什么是上下文?

Context提供了一种通过组件树传递数据的方法,而无需在每个级别手动传递 props。

例如,应用程序中的许多组件都需要访问经过身份验证的用户、语言环境偏好、UI 主题。

const { Provider, Consumer } = React.createContext(defaultValue);
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

children 道具是什么?

Children是一个 prop ( this.props.children),它允许你将组件作为数据传递给其他组件,就像你使用的任何其他 prop 一样。放置在组件开始和结束标签之间的组件树将作为childrenprop 传递给该组件。

React API 中有许多方法可以处理此 prop。其中包括React.Children.mapReact.Children.forEachReact.Children.countReact.Children.onlyReact.Children.toArray

children prop 的简单用法如下,

const MyDiv = React.createClass({
  render: function () {
    return <div>{this.props.children}</div>;
  },
});

ReactDOM.render(
  <MyDiv>
    <span>{'Hello'}</span>
    <span>{'World'}</span>
  </MyDiv>,
  node,
);
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如何在 React 中写评论?

React/JSX 中的注释类似于 JavaScript 多行注释,但用花括号括起来。

单行注释:

<div>
  {/* Single-line comments(In vanilla JavaScript, the single-line comments are represented by double slash(//)) */}
  {`Welcome ${user}, let's play React`}
</div>
Enter fullscreen mode Exit fullscreen mode

多行注释:

<div>
  {/* Multi-line comments for more than
  one line */}
  {`Welcome ${user}, let's play React`}
</div>
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

使用带有 props 参数的超级构造函数的目的是什么?

子类构造函数在方法调用之前不能使用this引用super()。ES6 子类也是如此。将 props 参数传递给 call 的主要原因是为了在子类构造函数中super()访问。this.props

传递道具:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);

    console.log(this.props); // prints { name: 'John', age: 42 }
  }
}
Enter fullscreen mode Exit fullscreen mode

不传递道具:

class MyComponent extends React.Component {
  constructor(props) {
    super();

    console.log(this.props); // prints undefined

    // but props parameter is still available
    console.log(props); // prints { name: 'John', age: 42 }
  }

  render() {
    // no difference outside constructor
    console.log(this.props); // prints { name: 'John', age: 42 }
  }
}
Enter fullscreen mode Exit fullscreen mode

上面的代码片段表明,this.props仅在构造函数内部有所不同。在构造函数外部,情况应该相同。

⬆ 返回顶部

什么是和解?

当组件的 props 或 state 发生变化时,React 会通过比较新返回的元素与之前渲染的元素来决定是否需要实际更新 DOM。如果它们不相等,React 将更新 DOM。这个过程称为协调 (reconciliation )。

⬆ 返回顶部

如何使用动态键名设置状态?

如果您使用 ES6 或 Babel 转换器来转换您的 JSX 代码,那么您可以使用计算属性名称来实现这一点。

handleInputChange(event) {
this.setState({ [event.target.id]: event.target.value })
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

每次组件渲染时调用函数的常见错误是什么?

您需要确保在将函数作为参数传递时不会调用该函数。

render() {
// Wrong: handleClick is called instead of passed as a reference!
return <button onClick={this.handleClick()}>{'Click Me'}</button>
}
Enter fullscreen mode Exit fullscreen mode

相反,传递函数本身而不使用括号:

render() {
// Correct: handleClick is passed as a reference!
return <button onClick={this.handleClick}>{'Click Me'}</button>
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

惰性函数是否支持命名导出?

不,目前React.lazy函数仅支持默认导出。如果您想导入名为导出的模块,可以创建一个中间模块,将其重新导出为默认模块。这还能确保摇树优化持续有效,并且不会拉取未使用的组件。我们以一个导出多个名为组件的组件文件为例,

// MoreComponents.js
export const SomeComponent = /* ... */;
export const UnusedComponent = /* ... */;
Enter fullscreen mode Exit fullscreen mode

MoreComponents.js在中间文件中重新导出组件IntermediateComponent.js

// IntermediateComponent.js
export { SomeComponent as default } from './MoreComponents.js';
Enter fullscreen mode Exit fullscreen mode

现在您可以使用惰性函数导入模块,如下所示,

import React, { lazy } from 'react';
const SomeComponent = lazy(() => import('./IntermediateComponent.js'));
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

为什么 React 使用classNameoverclass属性?

classclassName是 JavaScript 中的关键字,而 JSX 是 JavaScript 的扩展。这就是 React 使用而不是 的主要原因class。传递一个字符串作为classNameprop。

render() {
return <span className={'menu navigation-menu'}>{'Menu'}</span>
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

什么是碎片?

这是 React 中常见的模式,用于一个组件返回多个元素。Fragment允许你对子元素列表进行分组,而无需在 DOM 中添加额外的节点

render() {
return (
  <React.Fragment>
    <ChildA />
    <ChildB />
    <ChildC />
  </React.Fragment>
)
}
Enter fullscreen mode Exit fullscreen mode

还有一种更短的语法,但许多工具不支持它:

render() {
return (
  <>
    <ChildA />
    <ChildB />
    <ChildC />
  </>
)
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

为什么 Fragment 比容器 div 更好?

以下是原因列表,

  1. 由于不创建额外的 DOM 节点,Fragment 的速度更快,内存占用更少。这只有在非常大且深度极深的树上才会真正发挥作用。
  2. 一些 CSS 机制(例如FlexboxCSS Grid)具有特殊的父子关系,在中间添加 div 会使保持所需的布局变得困难。
  3. DOM 检查器不再那么混乱。

⬆ 返回顶部

React 中的门户是什么?

Portal是一种推荐的方法,用于将子项渲染到父组件 DOM 层次结构之外的 DOM 节点中。

ReactDOM.createPortal(child, container);
Enter fullscreen mode Exit fullscreen mode

第一个参数是任何可渲染的 React 子元素,例如元素、字符串或片段。第二个参数是 DOM 元素。

⬆ 返回顶部

什么是无状态组件?

如果行为独立于其状态,那么它可以是无状态组件。您可以使用函数或类来创建无状态组件。但除非您需要在组件中使用生命周期钩子,否则您应该选择函数组件。如果您决定在这里使用函数组件,会有很多好处:它们易于编写、理解和测试,速度更快,而且您可以this完全避免使用关键字。

⬆ 返回顶部

什么是有状态组件?

如果组件的行为依赖于组件的状态,则可以将其称为有状态组件。这些有状态组件始终是类组件,并且具有在 中初始化的状态constructor

class App extends Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  render() {
    // ...
  }
}
Enter fullscreen mode Exit fullscreen mode

React 16.8 更新:

Hooks 让您无需编写类即可使用状态和其他 React 功能。

等效函数组件

import React, {useState} from 'react';

const App = (props) => {
  const [count, setCount] = useState(0);

  return (
    // JSX
  )
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如何在 React 中对 props 应用验证?

当应用程序在开发模式下运行时,React 会自动检查我们在组件上设置的所有 props,以确保它们具有正确的类型。如果类型不正确,React 会在控制台中生成警告消息。由于性能影响,此功能在生产模式下被禁用。必需的 props 用 定义isRequired

预定义的 prop 类型集:

  1. PropTypes.number
  2. PropTypes.string
  3. PropTypes.array
  4. PropTypes.object
  5. PropTypes.func
  6. PropTypes.node
  7. PropTypes.element
  8. PropTypes.bool
  9. PropTypes.symbol
  10. PropTypes.any

我们可以propTypesUser组件进行如下定义:

import React from 'react';
import PropTypes from 'prop-types';

class User extends React.Component {
  static propTypes = {
    name: PropTypes.string.isRequired,
    age: PropTypes.number.isRequired,
  };

  render() {
    return (
      <>
        <h1>{`Welcome, ${this.props.name}`}</h1>
        <h2>{`Age, ${this.props.age}`}</h2>
      </>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

注意:在 React v15.5 中,PropTypesReact.PropTypes已从库中移出prop-types

⬆ 返回顶部

React 有哪些优点?

以下是 React 的主要优点:

  1. 使用虚拟 DOM提高应用程序的性能
  2. JSX 使代码易于阅读和编写。
  3. 它在客户端和服务器端(SSR)上呈现。
  4. 由于它只是一个视图库,因此易于与框架(Angular、Backbone)集成。
  5. 使用 Jest 等工具轻松编写单元和集成测试。

⬆ 返回顶部

React 有哪些局限性?

除了优点之外,React 也有一些限制,

  1. React 只是一个视图库,而不是一个完整的框架。
  2. 对于刚接触 Web 开发的初学者来说,有一个学习曲线。
  3. 将 React 集成到传统的 MVC 框架中需要一些额外的配置。
  4. 代码复杂性随着内联模板和 JSX 而增加。
  5. 太多较小的组件导致过度工程或样板化。

⬆ 返回顶部

React v16 中的错误边界是什么?

错误边界是捕获其子组件树中任何位置的 JavaScript 错误、记录这些错误并显示后备 UI 而不是崩溃的组件树的组件。

componentDidCatch(error, info)如果类组件定义了一个名为或 的新生命周期方法,它就会成为错误边界static getDerivedStateFromError()

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  componentDidCatch(error, info) {
    // You can also log the error to an error reporting service
    logErrorToMyService(error, info);
  }

  static getDerivedStateFromError(error) {
    // Update state so the next render will show the fallback UI.
    return { hasError: true };
  }

  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return <h1>{'Something went wrong.'}</h1>;
    }
    return this.props.children;
  }
}
Enter fullscreen mode Exit fullscreen mode

之后将其用作常规组件:

<ErrorBoundary>
  <MyWidget />
</ErrorBoundary>
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

React v15 中如何处理错误边界?

React v15使用方法为错误边界提供了非常基本的支持。在 React v16 中,unstable_handleError它已被重命名为。componentDidCatch

⬆ 返回顶部

静态类型检查的推荐方法有哪些?

通常,我们使用PropTypes 库自 React v15.5 起React.PropTypes已移至包中)在 React 应用程序中进行类型检查。对于大型代码库,建议使用静态类型检查器(例如 Flow 或 TypeScript),它们在编译时执行类型检查并提供自动完成功能。prop-types

⬆ 返回顶部

包有什么用react-dom

react-dom软件包提供了特定于 DOM 的方法,可在应用的顶层使用。大多数组件并非必须使用此模块。此软件包的一些方法如下:

  1. render()
  2. hydrate()
  3. unmountComponentAtNode()
  4. findDOMNode()
  5. createPortal()

⬆ 返回顶部

render 方法的目的是什么react-dom

此方法用于将 React 元素渲染到指定容器的 DOM 中,并返回该组件的引用。如果该 React 元素之前已渲染到容器中,则该方法将对其进行更新,并仅在必要时修改 DOM 以反映最新的更改。

ReactDOM.render(element, container[, callback])
Enter fullscreen mode Exit fullscreen mode

如果提供了可选的回调,它将在组件渲染或更新后执行。

⬆ 返回顶部

什么是 ReactDOMServer?

ReactDOMServer对象使你能够将组件渲染为静态标记(通常用于 Node 服务器上)。此对象主要用于服务器端渲染(SSR)。以下方法可在服务器和浏览器环境中使用:

  1. renderToString()
  2. renderToStaticMarkup()

例如,您通常运行基于 Node 的 Web 服务器(如 Express、Hapi 或 Koa),然后调用它renderToString来将根组件渲染为字符串,然后将其作为响应发送。

// using Express
import { renderToString } from 'react-dom/server';
import MyPage from './MyPage';

app.get('/', (req, res) => {
  res.write('<!DOCTYPE html><html><head><title>My Page</title></head><body>');
  res.write('<div id="content">');
  res.write(renderToString(<MyPage />));
  res.write('</div></body></html>');
  res.end();
});
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如何在 React 中使用 innerHTML?

dangerouslySetInnerHTML属性是 React 中用于innerHTML浏览器 DOM 的替代方案。与 一样innerHTML,考虑到跨站点脚本 (XSS) 攻击,使用此属性存在风险。您只需将__html对象作为键,将 HTML 文本作为值传递即可。

在此示例中,MyComponent 使用dangerouslySetInnerHTML属性来设置 HTML 标记:

function createMarkup() {
  return { __html: 'First &middot; Second' };
}

function MyComponent() {
  return <div dangerouslySetInnerHTML={createMarkup()} />;
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如何在 React 中使用样式?

style属性接受带有驼峰式命名属性的 JavaScript 对象,而不是 CSS 字符串。这与 DOM 样式的 JavaScript 属性一致,效率更高,并能防止 XSS 安全漏洞。

const divStyle = {
  color: 'blue',
  backgroundImage: 'url(' + imgUrl + ')',
};

function HelloWorldComponent() {
  return <div style={divStyle}>Hello World!</div>;
}
Enter fullscreen mode Exit fullscreen mode

样式键采用驼峰命名法,以便与访问 JavaScript 中的 DOM 节点上的属性保持一致(例如node.style.backgroundImage)。

⬆ 返回顶部

React 中的事件有何不同?

在 React 元素中处理事件有一些语法差异:

  1. React 事件处理程序使用驼峰式命名,而不是小写。
  2. 使用 JSX,您可以传递一个函数作为事件处理程序,而不是字符串。

⬆ 返回顶部

如果在构造函数中使用会发生什么setState()

当你使用 时setState(),除了将状态赋值给对象之外,React 还会重新渲染组件及其所有子组件。你会收到类似这样的错误:只能更新已安装或正在安装的组件。因此,我们需要this.state在构造函数中使用 来初始化变量。

⬆ 返回顶部

索引作为键有何影响?

键应该是稳定、可预测和唯一的,以便 React 可以跟踪元素。

在下面的代码片段中,每个元素的键将基于排序,而不是与所表示的数据绑定。这限制了 React 的优化能力。

{
  todos.map((todo, index) => <Todo {...todo} key={index} />);
}
Enter fullscreen mode Exit fullscreen mode

如果您使用元素数据作为唯一键,假设 todo.id 对于此列表是唯一的并且稳定,则 React 将能够重新排序元素而无需重新评估它们。

{
  todos.map((todo) => <Todo {...todo} key={todo.id} />);
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

在方法setState()使用好吗?componentWillMount()

setState()是的,在方法内部使用是安全的componentWillMount()。但同时建议避免在componentWillMount()生命周期方法中进行异步初始化。componentWillMount()在挂载之前立即调用。它在 之前调用render(),因此在此方法中设置状态不会触发重新渲染。避免在此方法中引入任何副作用或订阅。我们需要确保组件初始化的异步调用发生在 中,componentDidMount()而不是 中componentWillMount()

componentDidMount() {
axios.get(`api/todos`)
  .then((result) => {
    this.setState({
      messages: [...result.data]
    })
  })
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如果在初始状态下使用 props 会发生什么?

如果组件的 props 在组件未刷新的情况下发生变化,新的 props 值将永远不会显示,因为构造函数永远不会更新组件的当前状态。props 中的 state 初始化仅在组件首次创建时运行。

以下组件不会显示更新后的输入值:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      records: [],
      inputValue: this.props.inputValue,
    };
  }

  render() {
    return <div>{this.state.inputValue}</div>;
  }
}
Enter fullscreen mode Exit fullscreen mode

在 render 方法中使用 props 将更新值:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      record: [],
    };
  }

  render() {
    return <div>{this.props.inputValue}</div>;
  }
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如何有条件地渲染组件?

在某些情况下,您希望根据某些状态渲染不同的组件。JSX 不会渲染falseundefined,因此您可以使用条件短路,仅在特定条件为真时渲染组件的特定部分。

const MyComponent = ({ name, address }) => (
  <div>
    <h2>{name}</h2>
    {address && <p>{address}</p>}
  </div>
);
Enter fullscreen mode Exit fullscreen mode

如果需要if-else条件,则使用三元运算符

const MyComponent = ({ name, address }) => (
  <div>
    <h2>{name}</h2>
    {address ? <p>{address}</p> : <p>{'Address is not available'}</p>}
  </div>
);
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

为什么在 DOM 元素上传播 props 时需要小心?

当我们扩展 props时,我们面临着添加未知 HTML 属性的风险,这是一种不好的做法。相反,我们可以使用带有...rest操作符的 prop 解构,这样它只会添加必需的 props。

例如,

const ComponentA = () => <ComponentB isDisplay={true} className={'componentStyle'} />;

const ComponentB = ({ isDisplay, ...domProps }) => <div {...domProps}>{'ComponentB'}</div>;
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如何在 React 中使用装饰器?

你可以装饰你的组件,就像将组件传递给函数一样。装饰器是一种灵活且易读的修改组件功能的方式。

@setTitle('Profile')
class Profile extends React.Component {
  //....
}

/*
title is a string that will be set as a document title
WrappedComponent is what our decorator will receive when
put directly above a component class as seen in the example above
*/
const setTitle = (title) => (WrappedComponent) => {
  return class extends React.Component {
    componentDidMount() {
      document.title = title;
    }

    render() {
      return <WrappedComponent {...this.props} />;
    }
  };
};
Enter fullscreen mode Exit fullscreen mode

注意:装饰器是未纳入 ES7 的功能,但目前属于第 2 阶段提案

⬆ 返回顶部

如何记忆组件?

有可用于函数组件的记忆库。

例如,moize库可以在另一个组件中记忆该组件。

import moize from 'moize';
import Component from './components/Component'; // this module exports a non-memoized component

const MemoizedFoo = moize.react(Component);

const Consumer = () => {
  <div>
    {'I will memoize the following entry:'}
    <MemoizedFoo />
  </div>;
};
Enter fullscreen mode Exit fullscreen mode

更新:从 React v16.6.0 开始,我们新增了一个React.memo。它提供了一个高阶组件,除非 props 发生变化,否则会记忆组件。要使用它,只需在使用前用 React.memo 包裹组件即可。

const MemoComponent = React.memo(function MemoComponent(props) {
  /* render using props */
});
OR;
export default React.memo(MyFunctionComponent);
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如何实现服务器端渲染(SSR)?

React 已经具备处理 Node 服务器上渲染的能力。它有一个特殊版本的 DOM 渲染器可用,其遵循与客户端相同的模式。

import ReactDOMServer from 'react-dom/server';
import App from './App';

ReactDOMServer.renderToString(<App />);
Enter fullscreen mode Exit fullscreen mode

此方法将常规 HTML 输出为字符串,然后可以将其作为服务器响应的一部分放置在页面主体中。在客户端,React 会检测预渲染的内容,并从中断处无缝衔接。

⬆ 返回顶部

如何在 React 中启用生产模式?

你应该使用 Webpack 的DefinePlugin方法将其设置NODE_ENVproduction,这样它就可以去除诸如 propType 验证和额外警告之类的内容。除此之外,如果你压缩代码,例如使用 Uglify 的死代码消除功能来去除仅用于开发的代码和注释,这将大大减少你的打包文件的大小。

⬆ 返回顶部

什么是 CRA 及其好处?

CLI工具create-react-app允许您快速创建和运行 React 应用程序,无需任何配置步骤。

让我们使用CRA创建 Todo App :

# Installation
$ npm install -g create-react-app

# Create new project
$ create-react-app todo-app
$ cd todo-app

# Build, test and run
$ npm run build
$ npm run test
$ npm start
Enter fullscreen mode Exit fullscreen mode

它包含构建 React 应用程序所需的一切:

  1. React、JSX、ES6 和 Flow 语法支持。
  2. 超越 ES6 的语言附加功能,例如对象扩展运算符。
  3. 自动添加前缀 CSS,因此您不需要 -webkit- 或其他前缀。
  4. 一个快速交互式单元测试运行器,内置对覆盖率报告的支持。
  5. 实时开发服务器,对常见错误发出警告。
  6. 一个构建脚本,用于捆绑 JS、CSS 和图像以用于生产,并带有哈希和源映射。

⬆ 返回顶部

安装过程中的生命周期方法顺序是什么?

当创建组件实例并将其插入 DOM 时,生命周期方法按以下顺序调用。

  1. constructor()
  2. static getDerivedStateFromProps()
  3. render()
  4. componentDidMount()

⬆ 返回顶部

React v16 中将弃用哪些生命周期方法?

以下生命周期方法将是不安全的编码实践,并且在异步渲染时会出现更多问题。

  1. componentWillMount()
  2. componentWillReceiveProps()
  3. componentWillUpdate()

从 React v16.3 开始,这些方法以UNSAFE_前缀作为别名,而无前缀的版本将在 React v17 中删除。

⬆ 返回顶部

生命周期方法的目的是什么getDerivedStateFromProps()

新的静态getDerivedStateFromProps()生命周期方法在组件实例化之后以及重新渲染之前调用。它可以返回一个对象来更新状态,或者null指示新的 props 不需要任何状态更新。

class MyComponent extends React.Component {
  static getDerivedStateFromProps(props, state) {
    // ...
  }
}
Enter fullscreen mode Exit fullscreen mode

此生命周期方法涵盖了componentDidUpdate()的所有用例componentWillReceiveProps()

⬆ 返回顶部

生命周期方法的目的是什么getSnapshotBeforeUpdate()

新的getSnapshotBeforeUpdate()生命周期方法在 DOM 更新之前被调用。该方法的返回值将作为第三个参数传递给componentDidUpdate()

class MyComponent extends React.Component {
  getSnapshotBeforeUpdate(prevProps, prevState) {
    // ...
  }
}
Enter fullscreen mode Exit fullscreen mode

此生命周期方法涵盖了componentDidUpdate()的所有用例componentWillUpdate()

⬆ 返回顶部

Hooks 是否会取代渲染道具和高阶组件?

渲染道具和高阶组件都仅渲染一个子项,但在大多数情况下,Hooks 是一种通过减少树中的嵌套来实现此目的的更简单方法。

⬆ 返回顶部

推荐的组件命名方式是什么?

建议通过引用来命名组件,而不是使用displayName

用于displayName命名组件:

export default React.createClass({
  displayName: 'TodoApp',
  // ...
});
Enter fullscreen mode Exit fullscreen mode

推荐的方法

export default class TodoApp extends React.Component {
  // ...
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

组件类中方法的推荐顺序是什么?

从安装渲染阶段的方法推荐顺序

  1. static方法
  2. constructor()
  3. getChildContext()
  4. componentWillMount()
  5. componentDidMount()
  6. componentWillReceiveProps()
  7. shouldComponentUpdate()
  8. componentWillUpdate()
  9. componentDidUpdate()
  10. componentWillUnmount()
  11. 点击处理程序或事件处理程序,例如onClickSubmit()onChangeDescription()
  12. 用于渲染的 getter 方法,例如getSelectReason()getFooterContent()
  13. 可选的渲染方法,例如renderNavigation()renderProfilePicture()
  14. render()

⬆ 返回顶部

什么是开关组件?

切换组件渲染多个组件之一的组件。我们需要使用对象将 prop 值映射到组件。

例如,一个根据pageprop 显示不同页面的切换组件:

import HomePage from './HomePage';
import AboutPage from './AboutPage';
import ServicesPage from './ServicesPage';
import ContactPage from './ContactPage';

const PAGES = {
  home: HomePage,
  about: AboutPage,
  services: ServicesPage,
  contact: ContactPage,
};

const Page = (props) => {
  const Handler = PAGES[props.page] || ContactPage;

  return <Handler {...props} />;
};

// The keys of the PAGES object can be used in the prop types to catch dev-time errors.
Page.propTypes = {
  page: PropTypes.oneOf(Object.keys(PAGES)).isRequired,
};
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

为什么我们需要向 setState() 传递一个函数?

背后的原因是setState()是一个异步操作。出于性能原因,React 会批量更改状态,因此setState()调用 后状态可能不会立即更改。这意味着您在调用时不应依赖当前状态,setState() 因为您无法确定该状态将是什么。解决方案是将一个函数传递给setState(),并将先前的状态作为参数。这样做可以避免由于 的异步特性而导致用户在访问时获取旧状态值的问题setState()

假设初始计数值为零,连续三次递增操作后,计数值只会增加一。

// assuming this.state.count === 0
this.setState({ count: this.state.count + 1 });
this.setState({ count: this.state.count + 1 });
this.setState({ count: this.state.count + 1 });
// this.state.count === 1, not 3
Enter fullscreen mode Exit fullscreen mode

如果我们将一个函数传递给setState(),计数就会正确增加。

this.setState((prevState, props) => ({
  count: prevState.count + props.increment,
}));
// this.state.count === 3 as expected
Enter fullscreen mode Exit fullscreen mode

(或者)

为什么函数比对象更受欢迎setState()

为了提高性能, React 可能会将多个setState()调用批量合并到单个更新中。由于this.propsthis.state可能会异步更新,因此不应依赖它们的值来计算下一个状态。

此反例将无法按预期更新:

// Wrong
this.setState({
  counter: this.state.counter + this.props.increment,
});
Enter fullscreen mode Exit fullscreen mode

首选方法是setState()使用函数而不是对象来调用。该函数将接收先前的状态作为第一个参数,并将应用更新时的 props 作为第二个参数。

// Correct
this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment,
}));
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

React 中的严格模式是什么?

React.StrictMode是一个用于突出显示应用程序中潜在问题的有用组件。与 类似<Fragment><StrictMode>它不会渲染任何额外的 DOM 元素。它会为其后代激活额外的检查和警告。这些检查仅适用于开发模式

import React from 'react';

function ExampleApplication() {
  return (
    <div>
      <Header />
      <React.StrictMode>
        <div>
          <ComponentOne />
          <ComponentTwo />
        </div>
      </React.StrictMode>
      <Footer />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

在上面的例子中,严格模式检查仅适用于<ComponentOne><ComponentTwo>组件。

⬆ 返回顶部

React Mixins 是什么?

Mixins是一种将组件完全分离,使其具有通用功能的方法。不应使用Mixins ,可以使用高阶组件装饰器来替代。

最常用的 mixin 之一是PureRenderMixin。你可能会在某些组件中使用它,以防止当 props 和 state 与之前的 props 和 state 浅相等时进行不必要的重新渲染:

const PureRenderMixin = require('react-addons-pure-render-mixin');

const Button = React.createClass({
  mixins: [PureRenderMixin],
  // ...
});
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

为什么是isMounted()反模式以及什么是正确的解决方案?

主要用例isMounted()是避免setState()在组件卸载后调用,因为它会发出警告。

if (this.isMounted()) {
this.setState({...})
}
Enter fullscreen mode Exit fullscreen mode

isMounted()调用前检查setState()确实可以消除警告,但也违背了警告的目的。使用isMounted()是一种代码异味,因为你检查的唯一原因是你认为在组件卸载后可能还持有引用。

最佳解决方案是找到setState()组件卸载后可能被调用的位置,并修复它们。这种情况最常见的原因是回调,即组件在等待数据时,在数据到达之前就被卸载了。理想情况下,任何回调都应该在componentWillUnmount()卸载之前取消。

⬆ 返回顶部

React 支持哪些指针事件?

指针事件提供了一种统一的方式来处理所有输入事件。过去,我们用鼠标和相应的事件监听器来处理它们,但现在我们有很多设备不再需要鼠标,例如带有触控板的手机或触控笔。需要注意的是,这些事件只能在支持指针事件规范的浏览器中工作。

React DOM中现在提供以下事件类型

  1. onPointerDown
  2. onPointerMove
  3. onPointerUp
  4. onPointerCancel
  5. onGotPointerCapture
  6. onLostPointerCapture
  7. onPointerEnter
  8. onPointerLeave
  9. onPointerOver
  10. onPointerOut

⬆ 返回顶部

为什么组件名称要以大写字母开头?

如果你使用 JSX 渲染组件,组件名称必须以大写字母开头,否则 React 会抛出无法识别标签的错误。之所以采用这种约定,是因为只有 HTML 元素和 SVG 标签可以以小写字母开头。

class SomeComponent extends Component {
  // Code goes here
}
Enter fullscreen mode Exit fullscreen mode

你可以定义一个组件类,其名称以小写字母开头,但在导入时必须使用大写字母。以下情况小写字母是可以的:

class myComponent extends Component {
  render() {
    return <div />;
  }
}

export default myComponent;
Enter fullscreen mode Exit fullscreen mode

而当导入另一个文件时,它应该以大写字母开头:

import MyComponent from './MyComponent';
Enter fullscreen mode Exit fullscreen mode

React 组件命名有哪些例外?

组件名称应以大写字母开头,但此约定有一些例外。带有点(属性访问器)的小写标签名称仍被视为有效的组件名称。

例如,下面的标签可以编译为有效的组件,

render(){
  return (
      <obj.component /> // `React.createElement(obj.component)`
      )
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

React v16 是否支持自定义 DOM 属性?

是的。过去,React 会忽略未知的 DOM 属性。如果你编写的 JSX 代码中包含 React 无法识别的属性,React 就会直接跳过它。

例如,让我们看一下下面的属性:

<div mycustomattribute={'something'} />
Enter fullscreen mode Exit fullscreen mode

将使用 React v15 将空的 div 渲染到 DOM:

<div />
Enter fullscreen mode Exit fullscreen mode

在 React v16 中,任何未知属性最终都会出现在 DOM 中:

<div mycustomattribute="something" />
Enter fullscreen mode Exit fullscreen mode

这对于提供特定于浏览器的非标准属性、尝试新的 DOM API 以及与有主见的第三方库集成很有用。

⬆ 返回顶部

构造函数和 getInitialState 有什么区别?

当使用 ES6 类时,应在构造函数中初始化状态,getInitialState()当使用时,应在方法中初始化状态React.createClass()

使用 ES6 类:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      /* initial state */
    };
  }
}
Enter fullscreen mode Exit fullscreen mode

使用React.createClass()

const MyComponent = React.createClass({
  getInitialState() {
    return {
      /* initial state */
    };
  },
});
Enter fullscreen mode Exit fullscreen mode

注意: React.createClass()在 React v16 中已弃用并删除。请改用普通的 JavaScript 类。

⬆ 返回顶部

您可以在不调用 setState 的情况下强制组件重新渲染吗?

默认情况下,当组件的 state 或 props 发生变化时,组件将重新渲染。如果你的render()方法依赖于其他数据,你可以通过调用 来告诉 React 组件需要重新渲染forceUpdate()

component.forceUpdate(callback);
Enter fullscreen mode Exit fullscreen mode

建议避免使用forceUpdate(),而仅从this.propsthis.state中读取render()

⬆ 返回顶部

React 中使用 ES6 类的super()有什么区别?super(props)

当您想要访问this.propsconstructor(),您应该将 props 传递给super()方法。

使用super(props)

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    console.log(this.props); // { name: 'John', ... }
  }
}
Enter fullscreen mode Exit fullscreen mode

使用super()

class MyComponent extends React.Component {
  constructor(props) {
    super();
    console.log(this.props); // undefined
  }
}
Enter fullscreen mode Exit fullscreen mode

外面constructor()两者将显示相同的值this.props

⬆ 返回顶部

如何在 JSX 内部循环?

您可以简单地使用Array.prototype.mapES6箭头函数语法。

例如,items对象数组被映射到组件数组中:

<tbody>
  {items.map((item) => (
    <SomeComponent key={item.id} name={item.name} />
  ))}
</tbody>
Enter fullscreen mode Exit fullscreen mode

但不能使用for循环进行迭代:

<tbody>
for (let i = 0; i < items.length; i++) {
  <SomeComponent key={items[i].id} name={items[i].name} />
}
</tbody>
Enter fullscreen mode Exit fullscreen mode

这是因为 JSX 标签会被转译成函数调用,而表达式内部无法使用语句。由于do表达式(目前处于第一阶段提案)的改进,这种情况可能会有所改变。

⬆ 返回顶部

如何访问属性引号中的 props?

React(或 JSX)不支持在属性值内进行变量插值。以下代码无法正常工作:

<img className="image" src="images/{this.props.image}" />
Enter fullscreen mode Exit fullscreen mode

但是你可以将任何 JS 表达式放在花括号内作为整个属性值。因此,下面的表达式有效:

<img className="image" src={'images/' + this.props.image} />
Enter fullscreen mode Exit fullscreen mode

使用模板字符串也可以:

<img className="image" src={`images/${this.props.image}`} />
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

React proptype 数组的形状是什么?

如果您想将对象数组传递给具有特定形状的组件,则将其用作React.PropTypes.shape()参数React.PropTypes.arrayOf()

ReactComponent.propTypes = {
  arrayWithShape: React.PropTypes.arrayOf(
    React.PropTypes.shape({
      color: React.PropTypes.string.isRequired,
      fontSize: React.PropTypes.number.isRequired,
    }),
  ).isRequired,
};
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如何有条件地应用类属性?

您不应该在引号内使用花括号,因为它将被评估为字符串。

<div className="btn-panel {this.props.visible ? 'show' : 'hidden'}">
Enter fullscreen mode Exit fullscreen mode

相反,您需要将花括号移到外面(不要忘记在类名之间包含空格):

<div className={'btn-panel ' + (this.props.visible ? 'show' : 'hidden')}>
Enter fullscreen mode Exit fullscreen mode

模板字符串也可以起作用:

<div className={`btn-panel ${this.props.visible ? 'show' : 'hidden'}`}>
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

React 和 ReactDOM 有什么区别?

react包包含React.createElement()React.ComponentReact.Children以及其他与元素和组件类相关的帮助器。您可以将它们视为构建组件所需的同构或通用帮助器。该react-dom包包含ReactDOM.render(),并且react-dom/server我们通过和提供服务器端渲染支持ReactDOMServer.renderToString()ReactDOMServer.renderToStaticMarkup()

⬆ 返回顶部

为什么要将 ReactDOM 与 React 分离?

React 团队致力于将所有与 DOM 相关的功能提取到一个名为ReactDOM的独立库中。React v0.14 是首次将库拆分的版本。通过查看一些软件包react-native,、、,我们可以清楚地发现,React 的魅力和本质与浏览器或 DOM 无关。react-artreact-canvasreact-three

为了构建更多 React 可渲染的环境,React 团队计划将主 React 包拆分为两个:reactreact-dom。这为编写可在 Web 版 React 和 React Native 之间共享的组件铺平了道路。

⬆ 返回顶部

如何使用 React 标签元素?

如果您尝试<label>使用标准for属性呈现绑定到文本输入的元素,那么它会生成缺少该属性的 HTML 并向控制台打印警告。

<label for={'user'}>{'User'}</label>
<input type={'text'} id={'user'} />
Enter fullscreen mode Exit fullscreen mode

由于for是 JavaScript 中的保留关键字,htmlFor因此请使用。

<label htmlFor={'user'}>{'User'}</label>
<input type={'text'} id={'user'} />
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如何组合多个内联样式对象?

您可以在常规 React 中使用扩展运算符:

<button style={{ ...styles.panel.button, ...styles.panel.submitButton }}>{'Submit'}</button>
Enter fullscreen mode Exit fullscreen mode

如果您使用的是 React Native,那么您可以使用数组符号:

<button style={[styles.panel.button, styles.panel.submitButton]}>{'Submit'}</button>
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

当浏览器调整大小时如何重新渲染视图?

您可以监听resize中的事件componentDidMount(),然后更新尺寸(widthheight)。您应该删除 方法中的监听器componentWillUnmount()

class WindowDimensions extends React.Component {
  constructor(props) {
    super(props);
    this.updateDimensions = this.updateDimensions.bind(this);
  }

  componentWillMount() {
    this.updateDimensions();
  }

  componentDidMount() {
    window.addEventListener('resize', this.updateDimensions);
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.updateDimensions);
  }

  updateDimensions() {
    this.setState({ width: window.innerWidth, height: window.innerHeight });
  }

  render() {
    return (
      <span>
        {this.state.width} x {this.state.height}
      </span>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

setState()和方法之间有什么区别replaceState()

使用 时,setState()当前状态和先前状态会被合并。replaceState()会丢弃当前状态,并将其替换为您提供的内容。通常setState()使用 ,除非您出于某些原因确实需要删除所有先前的键。您也可以将状态设置为false/ nullsetState()而不是使用replaceState()

⬆ 返回顶部

如何监听状态变化?

当状态发生变化时,生命周期方法componentDidUpdate将被调用。你可以将提供的 state 和 props 值与当前 state 和 props 值进行比较,以确定是否有任何有意义的变化。

componentDidUpdate(object prevProps, object prevState)
Enter fullscreen mode Exit fullscreen mode

注意: ReactJS 的早期版本也使用componentWillUpdate(object nextProps, object nextState)状态更改。它在最新版本中已被弃用。

⬆ 返回顶部

在 React 状态下删除数组元素的推荐方法是什么?

更好的方法是使用Array.prototype.filter()方法。

例如,让我们创建一个removeItem()更新状态的方法。

removeItem(index) {
  this.setState({
    data: this.state.data.filter((item, i) => i !== index)
  })
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

是否可以在不渲染 HTML 的情况下使用 React?

最新版本(>=16.2)可以实现。以下是可能的选项:

render() {
  return false
}
Enter fullscreen mode Exit fullscreen mode
render() {
  return null
}
Enter fullscreen mode Exit fullscreen mode
render() {
  return []
}
Enter fullscreen mode Exit fullscreen mode
render() {
  return <React.Fragment></React.Fragment>
}
Enter fullscreen mode Exit fullscreen mode
render() {
  return <></>
}
Enter fullscreen mode Exit fullscreen mode

回程undefined是行不通的。

⬆ 返回顶部

如何使用 React 漂亮地打印 JSON?

我们可以使用标签,以便保留<pre>格式:JSON.stringify()

const data = { name: 'John', age: 42 };

class User extends React.Component {
  render() {
    return <pre>{JSON.stringify(data, null, 2)}</pre>;
  }
}

React.render(<User />, document.getElementById('container'));
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

为什么你不能在 React 中更新 props?

React 的理念是 props 应该是不可变的自上而下的。这意味着父组件可以向子组件发送任何 props 值,但子组件不能修改接收到的 props。

⬆ 返回顶部

如何在页面加载时聚焦输入元素?

您可以通过创建元素的refinput并在以下位置使用它来实现componentDidMount()

class App extends React.Component {
  componentDidMount() {
    this.nameInput.focus();
  }

  render() {
    return (
      <div>
        <input defaultValue={"Won't focus"} />
        <input ref={(input) => (this.nameInput = input)} defaultValue={'Will focus'} />
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById('app'));
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

有哪些可能的方法可以更新状态中的对象?

  1. 调用setState()一个对象来合并状态:
  • 用于Object.assign()创建对象的副本:

     const user = Object.assign({}, this.state.user, { age: 42 });
     this.setState({ user });
    
  • 使用扩展运算符

     const user = { ...this.state.user, age: 42 };
     this.setState({ user });
    
  1. setState()使用函数调用:
   this.setState((prevState) => ({
     user: {
       ...prevState.user,
       age: 42,
     },
   }));
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

我们如何在浏览器中找到运行时 React 的版本?

您可以使用React.version来获取版本。

const REACT_VERSION = React.version;

ReactDOM.render(<div>{`React version: ${REACT_VERSION}`}</div>, document.getElementById('app'));
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

有哪些方法可以将 polyfill 纳入您的create-react-app

有一些方法可以在 create-react-app 中包含 polyfill,

  1. 手动导入自core-js

创建一个名为(类似)的文件polyfills.js并将其导入到根index.js文件中。运行npm install core-jsyarn add core-js并导入您所需的特定功能。

   import 'core-js/fn/array/find';
   import 'core-js/fn/array/includes';
   import 'core-js/fn/number/is-nan';
Enter fullscreen mode Exit fullscreen mode
  1. 使用 Polyfill 服务:

通过将这一行添加到以下位置,使用 polyfill.io CDN 检索自定义的、特定于浏览器的 polyfill index.html

   <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=default,Array.prototype.includes"></script>
Enter fullscreen mode Exit fullscreen mode

在上面的脚本中,我们必须明确请求该Array.prototype.includes功能,因为它不包含在默认功能集中。

⬆ 返回顶部

如何在 create-react-app 中使用 https 而不是 http?

您只需要使用HTTPS=true配置。您可以编辑package.json脚本部分:

"scripts": {
  "start": "set HTTPS=true && react-scripts start"
}
Enter fullscreen mode Exit fullscreen mode

或者直接运行set HTTPS=true && npm start

⬆ 返回顶部

如何避免在 create-react-app 中使用相对路径导入?

.env在项目根目录中创建一个名为的文件并写入导入路径:

NODE_PATH=src/app
Enter fullscreen mode Exit fullscreen mode

之后重启开发服务器。现在你应该能够导入任何内容,src/app无需相对路径。

⬆ 返回顶部

如何为 React Router 添加 Google Analytics?

在对象上添加一个监听器history来记录每次页面浏览:

history.listen(function (location) {
  window.ga('set', 'page', location.pathname + location.search);
  window.ga('send', 'pageview', location.pathname + location.search);
});
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如何每秒更新一个组件?

您需要使用setInterval()来触发更改,但也需要在组件卸载时清除计时器,以防止错误和内存泄漏。

componentDidMount() {
  this.interval = setInterval(() => this.setState({ time: Date.now() }), 1000)
}

componentWillUnmount() {
  clearInterval(this.interval)
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如何将供应商前缀应用于 React 中的内联样式?

React不会自动应用供应商前缀。你需要手动添加供应商前缀。

<div
  style={{
    transform: 'rotate(90deg)',
    WebkitTransform: 'rotate(90deg)', // note the capital 'W' here
    msTransform: 'rotate(90deg)', // 'ms' is the only lowercase vendor prefix
  }}
/>
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如何使用 React 和 ES6 导入和导出组件?

您应该使用默认值来导出组件

import React from 'react';
import User from 'user';

export default class MyProfile extends React.Component {
  render() {
    return <User type="customer">//...</User>;
  }
}
Enter fullscreen mode Exit fullscreen mode

使用导出说明符,MyProfile 将成为成员并导出到此模块,并且可以在其他组件中导入而无需提及名称。

⬆ 返回顶部

为什么组件构造函数只被调用一次?

React 的协调算法假设,在没有任何相反信息的情况下,如果自定义组件在后续渲染中出现在相同的位置,则它与之前的组件相同,因此会重用之前的实例,而不是创建新的实例。

⬆ 返回顶部

如何在 React 中定义常量?

您可以使用 ES7static字段来定义常量。

class MyComponent extends React.Component {
  static DEFAULT_PAGINATION = 10;
}
Enter fullscreen mode Exit fullscreen mode

静态字段是类字段第 3 阶段提案的一部分

⬆ 返回顶部

如何在 React 中以编程方式触发点击事件?

您可以使用 ref propHTMLInputElement通过回调获取对底层对象的引用,将该引用存储为类属性,然后使用该引用稍后使用该方法从事件处理程序触发点击HTMLElement.click

这可以分两个步骤完成:

  1. 在渲染方法中创建 ref:
   <input ref={(input) => (this.inputElement = input)} />
Enter fullscreen mode Exit fullscreen mode
  1. 在您的事件处理程序中应用点击事件:
   this.inputElement.click();
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

可以在普通 React 中使用 async/await 吗?

如果你想在 React 中使用async/ await,你需要Babeltransform-async-to-generator插件。React Native 附带了 Babel 和一系列转换工具。

⬆ 返回顶部

React 的常见文件夹结构有哪些?

React项目文件结构有两种常见的做法。

  1. 按特征或路线分组:

构建项目的一种常见方法是将 CSS、JS 和测试放在一起,按功能或路线分组。

   common/
   ├─ Avatar.js
   ├─ Avatar.css
   ├─ APIUtils.js
   └─ APIUtils.test.js
   feed/
   ├─ index.js
   ├─ Feed.js
   ├─ Feed.css
   ├─ FeedStory.js
   ├─ FeedStory.test.js
   └─ FeedAPI.js
   profile/
   ├─ index.js
   ├─ Profile.js
   ├─ ProfileHeader.js
   ├─ ProfileHeader.css
   └─ ProfileAPI.js
Enter fullscreen mode Exit fullscreen mode
  1. 按文件类型分组:

构建项目的另一种流行方法是将相似的文件分组在一起。

   api/
   ├─ APIUtils.js
   ├─ APIUtils.test.js
   ├─ ProfileAPI.js
   └─ UserAPI.js
   components/
   ├─ Avatar.js
   ├─ Avatar.css
   ├─ Feed.js
   ├─ Feed.css
   ├─ FeedStory.js
   ├─ FeedStory.test.js
   ├─ Profile.js
   ├─ ProfileHeader.js
   └─ ProfileHeader.css
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

有哪些流行的动画软件包?

React Transition GroupReact Motion是 React 生态系统中流行的动画包。

⬆ 返回顶部

样式模块有什么好处?

建议避免在组件中硬编码样式值。任何可能跨不同 UI 组件使用的值都应提取到各自的模块中。

例如,这些样式可以提取到单独的组件中:

export const colors = {
  white,
  black,
  blue,
};

export const space = [0, 8, 16, 32, 64];
Enter fullscreen mode Exit fullscreen mode

然后在其他组件中单独导入:

import { space, colors } from './styles';
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

有哪些流行的 React 专用 linters?

ESLint 是一款流行的 JavaScript 语法检查工具。它有一些插件可以分析特定的代码风格。React 最常用的插件之一是名为 的 npm 包eslint-plugin-react。默认情况下,它会检查一系列最佳实践,规则涵盖从迭代器中的键到完整的 prop 类型集合。

另一个流行的插件是eslint-plugin-jsx-a11y,它可以帮助解决常见的可访问性问题。由于 JSX 的语法与常规 HTML 略有不同,因此常规插件无法检测到alt文本和等问题。tabindex

⬆ 返回顶部

如何进行 AJAX 调用以及应该在哪些组件生命周期方法中进行 AJAX 调用?

您可以使用 AJAX 库,例如 Axios、jQuery AJAX 和浏览器内置的fetch。您应该在生命周期方法中获取数据componentDidMount()。这样,setState()当数据被检索到时,您就可以用它来更新组件。

例如,从 API 获取员工列表并设置本地状态:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      employees: [],
      error: null,
    };
  }

  componentDidMount() {
    fetch('https://api.example.com/items')
      .then((res) => res.json())
      .then(
        (result) => {
          this.setState({
            employees: result.employees,
          });
        },
        (error) => {
          this.setState({ error });
        },
      );
  }

  render() {
    const { error, employees } = this.state;
    if (error) {
      return <div>Error: {error.message}</div>;
    } else {
      return (
        <ul>
          {employees.map((employee) => (
            <li key={employee.name}>
              {employee.name}-{employee.experience}
            </li>
          ))}
        </ul>
      );
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

什么是渲染道具?

Render Props是一种简单的技术,它使用一个值为函数的 prop 在组件之间共享代码。下面的组件使用了 render prop,它返回一个 React 元素。

<DataProvider render={(data) => <h1>{`Hello ${data.target}`}</h1>} />
Enter fullscreen mode Exit fullscreen mode

React Router 和 DownShift 等库正在使用这种模式。

React 路由器

⬆ 返回顶部

什么是 React Router?

React Router 是一个基于 React 构建的强大的路由库,它可以帮助您以惊人的速度向应用程序添加新的屏幕和流程,同时保持 URL 与页面上显示的内容同步。

⬆ 返回顶部

React Router 与历史库有何不同?

React Router 是该库的包装器,history它通过浏览器和哈希历史记录处理与浏览器的交互window.history。它还提供内存历史记录,这对于没有全局历史记录的环境非常有用,例如移动应用开发(React Native)和使用 Node 的单元测试。

⬆ 返回顶部

<Router>React Router v4 的组件有哪些?

React Router v4 提供以下 3 个<Router>组件:

  1. <BrowserRouter>
  2. <HashRouter>
  3. <MemoryRouter>

上述组件将创建browserhashmemoryhistory history 实例。React Router v4通过对象中的上下文,使与路由器关联的实例的属性和方法可用router

⬆ 返回顶部

的目的push()replace()方法是什么history

历史实例有两种用于导航的方法。

  1. push()
  2. replace()

如果您将历史记录视为访问过的位置的数组,push()则会向数组中添加一个新位置,并replace()用新位置替换数组中的当前位置。

⬆ 返回顶部

如何以编程方式使用 React Router v4 进行导航?

有三种不同的方法可以在组件内实现编程路由/导航。

  1. 使用withRouter()高阶函数:

高阶函数withRouter()会将 history 对象作为组件的 prop 注入。该对象提供了push()replace()方法,以避免使用 context。

   import { withRouter } from 'react-router-dom'; // this also works with 'react-router-native'

   const Button = withRouter(({ history }) => (
     <button
       type="button"
       onClick={() => {
         history.push('/new-location');
       }}
     >
       {'Click Me!'}
     </button>
   ));
Enter fullscreen mode Exit fullscreen mode
  1. 使用<Route>组件和渲染道具模式:

<Route>组件传递与相同的道具withRouter(),因此您将能够通过历史记录道具访问历史记录方法。

   import { Route } from 'react-router-dom';

   const Button = () => (
     <Route
       render={({ history }) => (
         <button
           type="button"
           onClick={() => {
             history.push('/new-location');
           }}
         >
           {'Click Me!'}
         </button>
       )}
     />
   );
Enter fullscreen mode Exit fullscreen mode
  1. 使用上下文:

不推荐使用此选项,并将其视为不稳定的 API。

   const Button = (props, context) => (
     <button
       type="button"
       onClick={() => {
         context.history.push('/new-location');
       }}
     >
       {'Click Me!'}
     </button>
   );

   Button.contextTypes = {
     history: React.PropTypes.shape({
       push: React.PropTypes.func.isRequired,
     }),
   };
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如何在 React Router v4 中获取查询参数?

React Router v4 取消了解析查询字符串的功能,因为多年来用户一直要求支持不同的实现。因此,最终决定权交给了用户,让他们自行选择喜欢的实现。推荐的方法是使用查询字符串库。

const queryString = require('query-string');
const parsed = queryString.parse(props.location.search);
Enter fullscreen mode Exit fullscreen mode

URLSearchParams如果您想要一些原生的东西,您也可以使用:

const params = new URLSearchParams(props.location.search);
const foo = params.get('name');
Enter fullscreen mode Exit fullscreen mode

您应该使用IE11 的polyfill 。

⬆ 返回顶部

为什么会收到“路由器可能只有一个子元素”警告?

您必须将您的路线包装在一个<Switch>块中,因为<Switch>它是唯一的,因为它专门呈现一条路线。

首先,您需要添加以下内容Switch到您的导入中:

import { Switch, Router, Route } from 'react-router';
Enter fullscreen mode Exit fullscreen mode

然后在块内定义路线<Switch>

<Router>
  <Switch>
    <Route {/* ... */} />
    <Route {/* ... */} />
  </Switch>
</Router>
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如何将参数传递给history.pushReact Router v4 中的方法?

导航时,您可以将道具传递给history对象:

this.props.history.push({
  pathname: '/template',
  search: '?name=sudheer',
  state: { detail: response.data },
});
Enter fullscreen mode Exit fullscreen mode

search属性用于在push()方法中传递查询参数。

⬆ 返回顶部

如何实现默认NotFound页面?

A<Switch>渲染第一个<Route>匹配的子元素。<Route>没有路径的 A 始终匹配。因此,您只需删除路径属性即可,如下所示

<Switch>
  <Route exact path="/" component={Home} />
  <Route path="/user" component={User} />
  <Route component={NotFound} />
</Switch>
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如何获取 React Router v4 的历史记录?

以下是在 React Router v4 上获取历史对象的步骤列表,

  1. 创建一个导出history对象的模块并在整个项目中导入该模块。

例如创建history.js文件:

   import { createBrowserHistory } from 'history';

   export default createBrowserHistory({
     /* pass a configuration object here if needed */
   });
Enter fullscreen mode Exit fullscreen mode
  1. 您应该使用<Router>组件而不是内置路由器。导入上述history.js文件index.js
   import { Router } from 'react-router-dom';
   import history from './history';
   import App from './App';

   ReactDOM.render(
     <Router history={history}>
       <App />
     </Router>,
     holder,
   );
Enter fullscreen mode Exit fullscreen mode
  1. 您还可以使用history类似于内置历史对象的对象的推送方法:
   // some-other-file.js
   import history from './history';

   history.push('/go-here');
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如何实现登录后自动重定向?

react-router包提供了<Redirect>React Router 中的组件。渲染<Redirect>将导航到新位置。与服务器端重定向类似,新位置将覆盖历史记录堆栈中的当前位置。

import React, { Component } from 'react';
import { Redirect } from 'react-router';

export default class LoginComponent extends Component {
  render() {
    if (this.state.isLoggedIn === true) {
      return <Redirect to="/your/redirect/page" />;
    } else {
      return <div>{'Login Please'}</div>;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

React 国际化

⬆ 返回顶部

什么是 React Intl?

React Intl让 React 的内部化变得简单易行,它提供现成的组件和 API,能够处理从格式化字符串、日期、数字到复数的所有操作。React Intl 是FormatJS的一部分,FormatJS 通过其组件和 API 提供与 React 的绑定。

⬆ 返回顶部

React Intl 的主要功能是什么?

以下是 React Intl 的主要功能,

  1. 显示带有分隔符的数字。
  2. 正确显示日期和时间。
  3. 显示相对于“现在”的日期。
  4. 将字符串中的标签变为复数。
  5. 支持 150 多种语言。
  6. 在浏览器和 Node 中运行。
  7. 建立在标准之上。

⬆ 返回顶部

React Intl 中有哪两种格式化方式?

该库提供了两种格式化字符串、数字和日期的方法:

  1. 使用反应组件:
   <FormattedMessage id={'account'} defaultMessage={'The amount is less than minimum balance.'} />
Enter fullscreen mode Exit fullscreen mode
  1. 使用 API:
   const messages = defineMessages({
     accountMessage: {
       id: 'account',
       defaultMessage: 'The amount is less than minimum balance.',
     },
   });

   formatMessage(messages.accountMessage);
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如何使用<FormattedMessage>React Intl 用作占位符?

组件返回<Formatted... />react-intl是元素,而不是纯文本,因此它们不能用作占位符、替代文本等。在这种情况下,您应该使用低级 API formatMessage()。您可以intl使用高阶组件将对象注入到组件中injectIntl(),然后使用该对象上的可用方法格式化消息formatMessage()

import React from 'react';
import { injectIntl, intlShape } from 'react-intl';

const MyComponent = ({ intl }) => {
  const placeholder = intl.formatMessage({ id: 'messageId' });
  return <input placeholder={placeholder} />;
};

MyComponent.propTypes = {
  intl: intlShape.isRequired,
};

export default injectIntl(MyComponent);
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如何使用 React Intl 访问当前语言环境?

您可以使用以下方法获取应用程序任何组件中的当前语言环境injectIntl()

import { injectIntl, intlShape } from 'react-intl';

const MyComponent = ({ intl }) => <div>{`The current locale is ${intl.locale}`}</div>;

MyComponent.propTypes = {
  intl: intlShape.isRequired,
};

export default injectIntl(MyComponent);
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如何使用 React Intl 格式化日期?

高阶组件将允许您通过组件中的 propsinjectIntl()访问该方法。该方法由 的实例内部使用,并返回格式化日期的字符串表示形式。formatDate()FormattedDate

import { injectIntl, intlShape } from 'react-intl';

const stringDate = this.props.intl.formatDate(date, {
  year: 'numeric',
  month: 'numeric',
  day: 'numeric',
});

const MyComponent = ({ intl }) => <div>{`The formatted date is ${stringDate}`}</div>;

MyComponent.propTypes = {
  intl: intlShape.isRequired,
};

export default injectIntl(MyComponent);
Enter fullscreen mode Exit fullscreen mode

反应测试

⬆ 返回顶部

React 测试中的浅渲染器是什么?

浅渲染对于在 React 中编写单元测试用例非常有用。它允许你将组件渲染到一层深度,并断言其渲染方法的返回结果,而无需担心未实例化或渲染的子组件的行为。

例如,如果您有以下组件:

function MyComponent() {
  return (
    <div>
      <span className={'heading'}>{'Title'}</span>
      <span className={'description'}>{'Description'}</span>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

然后你可以断言如下:

import ShallowRenderer from 'react-test-renderer/shallow';

// in your test
const renderer = new ShallowRenderer();
renderer.render(<MyComponent />);

const result = renderer.getRenderOutput();

expect(result.type).toBe('div');
expect(result.props.children).toEqual([
  <span className={'heading'}>{'Title'}</span>,
  <span className={'description'}>{'Description'}</span>,
]);
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

React 中的包是什么TestRenderer?

此软件包提供了一个渲染器,可用于将组件渲染为纯 JavaScript 对象,而无需依赖 DOM 或原生移动环境。此软件包可以轻松获取由 ReactDOM 或 React Native 渲染的平台视图层次结构(类似于 DOM 树)的快照,而无需使用浏览器或jsdom

import TestRenderer from 'react-test-renderer';

const Link = ({ page, children }) => <a href={page}>{children}</a>;

const testRenderer = TestRenderer.create(
  <Link page={'https://www.facebook.com/'}>{'Facebook'}</Link>,
);

console.log(testRenderer.toJSON());
// {
//   type: 'a',
//   props: { href: 'https://www.facebook.com/' },
//   children: [ 'Facebook' ]
// }
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

ReactTestUtils 包的用途是什么?

该包中提供了ReactTestUtilswith-addons,允许您针对模拟 DOM 执行操作以进行单元测试。

⬆ 返回顶部

什么是 Jest?

Jest是 Facebook 基于 Jasmine 创建的 JavaScript 单元测试框架,提供自动化模拟创建和jsdom环境。它常用于测试组件。

⬆ 返回顶部

Jest 相对于 Jasmine 有哪些优势?

与 Jasmine 相比,它有几个优点:

  • 自动查找在源代码中执行的测试。
  • 运行测试时自动模拟依赖关系。
  • 允许您同步测试异步代码。
  • 使用伪 DOM 实现(通过jsdom)运行您的测试,以便您的测试可以在命令行上运行。
  • 并行运行测试以便更快地完成。

⬆ 返回顶部

举一个简单的Jest测试用例的例子

让我们为文件中两个数字相加的函数编写一个测试sum.js

const sum = (a, b) => a + b;

export default sum;
Enter fullscreen mode Exit fullscreen mode

创建一个名为的文件sum.test.js,其中包含实际测试:

import sum from './sum';

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});
Enter fullscreen mode Exit fullscreen mode

然后将以下部分添加到您的package.json

{
  "scripts": {
    "test": "jest"
  }
}
Enter fullscreen mode Exit fullscreen mode

最后,运行yarn testnpm test,Jest 将打印结果:

$ yarn test
PASS ./sum.test.js
✓ adds 1 + 2 to equal 3 (2ms)
Enter fullscreen mode Exit fullscreen mode

React Redux

⬆ 返回顶部

什么是助焊剂?

Flux是一种应用程序设计范式,用于替代更传统的 MVC 模式。它不是一个框架或库,而是一种新的架构,是对 React 和单向数据流概念的补充。Facebook 在内部使用 React 时也使用了这种模式。

调度程序、存储和视图组件之间的工作流程具有不同的输入和输出,如下所示:

通量

⬆ 返回顶部

什么是 Redux?

Redux是一个基于Flux 设计模式的 JavaScript 应用可预测状态容器。Redux 可以与 React 或任何其他视图库一起使用。它非常小巧(约 2kB)并且没有任何依赖项。

⬆ 返回顶部

Redux 的核心原则是什么?

Redux 遵循三个基本原则:

  1. 单一事实来源:整个应用程序的状态存储在单个存储区内的对象树中。单一状态树让您能够更轻松地跟踪随时间推移的变化,并调试或检查应用程序。
  2. 状态是只读的:更改状态的唯一方法是发出一个动作(一个描述发生了什么的对象)。这确保了视图和网络回调都不会直接写入状态。
  3. 使用纯函数进行更改:为了指定状态树如何通过操作进行转换,您可以编写 Reducer。Reducer 只是纯函数,它以先前的状态和操作作为参数,并返回下一个状态。

⬆ 返回顶部

与 Flux 相比,Redux 有哪些缺点?

与其说是缺点,不如说是使用 Redux 相比 Flux 有一些缺点。具体如下:

  1. 你需要学习如何避免状态突变: Flux 对数据突变没有意见,但 Redux 不喜欢数据突变,而且许多 Redux 的补充包都假设你永远不会改变状态。你可以使用仅限开发的包(例如redux-immutable-state-invariantImmutable.js)来强制执行,或者指导你的团队编写不改变状态的代码。
  2. 您必须仔细选择您的软件包:虽然 Flux 明确不尝试解决撤消/重做、持久性或表单等问题,但 Redux 具有中间件和存储增强器等扩展点,并且它催生了丰富的生态系统。
  3. 目前还没有很好的 Flow 集成: Flux 目前允许您进行非常令人印象深刻的静态类型检查,但 Redux 尚不支持。

⬆ 返回顶部

mapStateToProps()有什么区别mapDispatchToProps()

mapStateToProps()是一个实用程序,可帮助您的组件获取更新状态(由其他一些组件更新):

const mapStateToProps = (state) => {
  return {
    todos: getVisibleTodos(state.todos, state.visibilityFilter),
  };
};
Enter fullscreen mode Exit fullscreen mode

mapDispatchToProps()是一个实用程序,它将帮助您的组件触发动作事件(调度可能导致应用程序状态改变的动作):

const mapDispatchToProps = (dispatch) => {
  return {
    onTodoClick: (id) => {
      dispatch(toggleTodo(id));
    },
  };
};
Enter fullscreen mode Exit fullscreen mode

建议始终使用“对象简写”形式mapDispatchToProps

Redux 将其包装在另一个类似于 (...args) => dispatch(onTodoClick(...args)) 的函数中,并将该包装函数作为 prop 传递给您的组件。

const mapDispatchToProps = {
  onTodoClick,
};
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

我可以在 Reducer 中发送一个动作吗?

在 Reducer 中调度 Action 是一种反模式。你的 Reducer 应该没有副作用,只需消化 Action 的有效负载并返回一个新的状态对象即可。在 Reducer 中添加监听器并调度 Action 可能会导致 Action 链式执行和其他副作用。

⬆ 返回顶部

如何在组件外部访问 Redux 存储?

您只需要从创建它的模块中导出存储即可createStore()。此外,它不应该污染全局窗口对象。

store = createStore(myReducer);

export default store;
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

MVW 模式有哪些缺点?

  1. DOM 操作非常昂贵,会导致应用程序运行缓慢且效率低下。
  2. 由于循环依赖,围绕模型和视图创建了一个复杂的模型。
  3. 协作应用程序(如 Google Docs)会发生大量数据变化。
  4. 如果不添加太多额外的代码,就无法轻松地撤消(回到过去)。

⬆ 返回顶部

Redux 和 RxJS 之间有什么相似之处吗?

这些库因用途不同而有很大差异,但也存在一些模糊的相似之处。

Redux 是一个用于管理整个应用程序状态的工具。它通常用作 UI 的架构。可以将其视为 Angular 的替代方案(或一半)。RxJS 是一个响应式编程库。它通常用作在 JavaScript 中完成异步任务的工具。可以将其视为 Promises 的替代方案。Redux 使用响应式范式,因为 Store 是响应式的。Store 会远程观察操作并进行自我修改。RxJS 也使用响应式范式,但它并非一种架构,而是提供了基本的构建块——可观察对象 (Observables),来实现这种模式。

⬆ 返回顶部

如何在加载时分派动作?

componentDidMount()您可以在方法中分派动作,并且render()可以在方法中验证数据。

class App extends Component {
  componentDidMount() {
    this.props.fetchData();
  }

  render() {
    return this.props.isLoaded ? <div>{'Loaded'}</div> : <div>{'Not Loaded'}</div>;
  }
}

const mapStateToProps = (state) => ({
  isLoaded: state.isLoaded,
});

const mapDispatchToProps = { fetchData };

export default connect(mapStateToProps, mapDispatchToProps)(App);
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如何connect()从 React Redux 使用?

您需要遵循两个步骤才能在容器中使用商店:

  1. 使用mapStateToProps()它将商店中的状态变量映射到您指定的道具。
  2. 将上述 props 连接到你的容器:函数返回的对象mapStateToProps已连接到容器。你可以connect()从导入react-redux
   import React from 'react';
   import { connect } from 'react-redux';

   class App extends React.Component {
     render() {
       return <div>{this.props.containerData}</div>;
     }
   }

   function mapStateToProps(state) {
     return { containerData: state.data };
   }

   export default connect(mapStateToProps)(App);
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如何在 Redux 中重置状态?

您需要在应用程序中编写一个根减速器,将处理操作委托给由生成的减速器combineReducers()

例如,让我们rootReducer()返回 action 之后的初始状态USER_LOGOUT。众所周知,undefined无论 action 是什么,reducer 在被调用时都应该返回初始状态作为第一个参数。

const appReducer = combineReducers({
  /* your app's top-level reducers */
});

const rootReducer = (state, action) => {
  if (action.type === 'USER_LOGOUT') {
    state = undefined;
  }

  return appReducer(state, action);
};
Enter fullscreen mode Exit fullscreen mode

如果使用redux-persist,您可能还需要清理存储。redux-persist在存储引擎中保存状态副本。首先,您需要导入适当的存储引擎,然后在将状态设置为未定义之前解析状态,并清理每个存储状态键。

const appReducer = combineReducers({
  /* your app's top-level reducers */
});

const rootReducer = (state, action) => {
  if (action.type === 'USER_LOGOUT') {
    Object.keys(state).forEach((key) => {
      storage.removeItem(`persist:${key}`);
    });

    state = undefined;
  }

  return appReducer(state, action);
};
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

atRedux 连接装饰器中的符号有什么用途?

@符号实际上是一个 JavaScript 表达式,用于表示装饰器。装饰器使得在设计时注释和修改类和属性成为可能。

让我们举一个不使用和使用装饰器的 Redux 设置示例。

  • 没有装饰器:
  import React from 'react';
  import * as actionCreators from './actionCreators';
  import { bindActionCreators } from 'redux';
  import { connect } from 'react-redux';

  function mapStateToProps(state) {
    return { todos: state.todos };
  }

  function mapDispatchToProps(dispatch) {
    return { actions: bindActionCreators(actionCreators, dispatch) };
  }

  class MyApp extends React.Component {
    // ...define your main app here
  }

  export default connect(mapStateToProps, mapDispatchToProps)(MyApp);
Enter fullscreen mode Exit fullscreen mode
  • 使用装饰器:
  import React from 'react';
  import * as actionCreators from './actionCreators';
  import { bindActionCreators } from 'redux';
  import { connect } from 'react-redux';

  function mapStateToProps(state) {
    return { todos: state.todos };
  }

  function mapDispatchToProps(dispatch) {
    return { actions: bindActionCreators(actionCreators, dispatch) };
  }

  @connect(mapStateToProps, mapDispatchToProps)
  export default class MyApp extends React.Component {
    // ...define your main app here
  }
Enter fullscreen mode Exit fullscreen mode

除了装饰器的用法之外,上述示例几乎相似。装饰器语法尚未内置于任何 JavaScript 运行时中,并且仍处于实验阶段,可能会发生变化。您可以使用 babel 来获得装饰器支持。

⬆ 返回顶部

React context 和 React Redux 有什么区别?

您可以直接在应用程序中使用Context,它非常适合将数据传递到其设计的深层嵌套组件。

Redux功能更强大,提供了 Context API 所不具备的大量功能。此外,React Redux 内部使用了 context,但并未在公共 API 中公开。

⬆ 返回顶部

为什么 Redux 状态函数被称为 Reducer?

Reducer 始终返回状态的累积(基于所有先前和当前操作)。因此,它们充当状态的 Reducer。每次调用 Redux Reducer 时,状态和操作都会作为参数传递。然后,根据操作减少(或累积)此状态,并返回下一个状态。您可以Reduce一组操作和一个初始状态(存储状态),并在该初始状态上执行这些操作,以获得最终状态。

⬆ 返回顶部

如何在 Redux 中发出 AJAX 请求?

您可以使用redux-thunk允许您定义异步操作的中间件。

让我们举一个使用fetch API通过 AJAX 调用获取特定帐户的示例:

export function fetchAccount(id) {
  return (dispatch) => {
    dispatch(setLoadingAccountState()); // Show a loading spinner
    fetch(`/account/${id}`, (response) => {
      dispatch(doneFetchingAccount()); // Hide loading spinner
      if (response.status === 200) {
        dispatch(setAccount(response.json)); // Use a normal function to set the received state
      } else {
        dispatch(someError);
      }
    });
  };
}

function setAccount(data) {
  return { type: 'SET_Account', data: data };
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

我是否应该将所有组件的状态保存在 Redux 存储中?

将数据保存在 Redux 存储中,并将 UI 相关状态保存在组件内部。

⬆ 返回顶部

访问 Redux 存储的正确方法是什么?

在组件中访问 store 的最佳方式是使用connect()函数,它会创建一个新组件来包装现有组件。这种模式称为高阶组件,通常是在 React 中扩展组件功能的首选方式。它允许你将 state 和 action 创建器映射到组件,并在 store 更新时自动传入它们。

我们来看一个<FilterLink>使用 connect 的组件的例子:

import { connect } from 'react-redux';
import { setVisibilityFilter } from '../actions';
import Link from '../components/Link';

const mapStateToProps = (state, ownProps) => ({
  active: ownProps.filter === state.visibilityFilter,
});

const mapDispatchToProps = (dispatch, ownProps) => ({
  onClick: () => dispatch(setVisibilityFilter(ownProps.filter)),
});

const FilterLink = connect(mapStateToProps, mapDispatchToProps)(Link);

export default FilterLink;
Enter fullscreen mode Exit fullscreen mode

由于它具有相当多的性能优化并且通常不太可能导致错误,Redux 开发人员几乎总是建议使用它connect()而不是直接访问存储(使用上下文 API)。

class MyComponent {
  someMethod() {
    doSomethingWith(this.context.store);
  }
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

React Redux 中的组件和容器有什么区别?

组件是描述应用程序展示部分的类或功能组件。

容器是一个非正式术语,指的是连接到 Redux Store 的组件。容器订阅Redux 状态更新并调度操作,并且通常不渲染 DOM 元素;而是将渲染委托给展示型子组件。

⬆ 返回顶部

Redux 中常量的用途是什么?

常量允许您在使用 IDE 时轻松找到项目中该特定功能的所有用法。它还可以防止您引入由拼写错误引起的愚蠢错误——在这种情况下,您会ReferenceError立即得到一个。

通常我们会将它们保存在一个文件中(constants.jsactionTypes.js)。

export const ADD_TODO = 'ADD_TODO';
export const DELETE_TODO = 'DELETE_TODO';
export const EDIT_TODO = 'EDIT_TODO';
export const COMPLETE_TODO = 'COMPLETE_TODO';
export const COMPLETE_ALL = 'COMPLETE_ALL';
export const CLEAR_COMPLETED = 'CLEAR_COMPLETED';
Enter fullscreen mode Exit fullscreen mode

在 Redux 中,您可以在两个地方使用它们:

  1. 在创建动作期间:

让我们来看看actions.js

   import { ADD_TODO } from './actionTypes';

   export function addTodo(text) {
     return { type: ADD_TODO, text };
   }
Enter fullscreen mode Exit fullscreen mode
  1. 在减速器中:

让我们创建reducer.js

   import { ADD_TODO } from './actionTypes';

   export default (state = [], action) => {
     switch (action.type) {
       case ADD_TODO:
         return [
           ...state,
           {
             text: action.text,
             completed: false,
           },
         ];
       default:
         return state;
     }
   };
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

有哪些不同的书写方式mapDispatchToProps()

有几种方法可以将动作创建者绑定到dispatch()in mapDispatchToProps()

以下是可能的选项:

const mapDispatchToProps = (dispatch) => ({
  action: () => dispatch(action()),
});
Enter fullscreen mode Exit fullscreen mode
const mapDispatchToProps = (dispatch) => ({
  action: bindActionCreators(action, dispatch),
});
Enter fullscreen mode Exit fullscreen mode
const mapDispatchToProps = { action };
Enter fullscreen mode Exit fullscreen mode

第三个选项只是第一个选项的简写。

⬆ 返回顶部

和中ownProps的参数有什么用mapStateToProps()mapDispatchToProps()

如果ownProps指定了参数,React Redux 会将传递给组件的 props 传递到你的connect函数中。因此,如果你使用已连接的组件:

import ConnectedComponent from './containers/ConnectedComponent';

<ConnectedComponent user={'john'} />;
Enter fullscreen mode Exit fullscreen mode

ownProps你的mapStateToProps()和函数内部mapDispatchToProps()将是一个对象:

{
  user: 'john';
}
Enter fullscreen mode Exit fullscreen mode

您可以使用此对象来决定从这些函数返回什么。

⬆ 返回顶部

如何构建 Redux 顶级目录?

大多数应用程序都有如下几个顶级目录:

  1. 组件:用于不知道 Redux 的组件。
  2. 容器:用于连接到 Redux 的智能组件。
  3. 动作:用于所有动作创建者,其中文件名对应于应用程序的一部分。
  4. Reducers:用于所有reducer,其中文件名与状态键相对应。
  5. Store:用于存储初始化。

这种结构非常适合中小型应用程序。

⬆ 返回顶部

什么是 redux-saga?

redux-saga是一个旨在使 React/Redux 应用程序中的副作用(异步事物,如数据获取和不纯事物,如访问浏览器缓存)更容易、更好。

它在 NPM 中可用:

$ npm install --save redux-saga
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

redux-saga 的心理模型是什么?

Saga就像应用程序中的一个单独线程,它完全负责副作用。redux-saga是一个 redux中间件,这意味着这个线程可以通过正常的 Redux 操作从主应用程序启动、暂停和取消,它可以访问完整的 Redux 应用程序状态,也可以分派 Redux 操作。

⬆ 返回顶部

call()redux-saga 中的和有什么区别put()?

call()都是put()效果创建函数。call()函数用于创建效果描述,指示中间件调用承诺。put()函数创建一个效果,指示中间件将动作分派到商店。

让我们举例说明这些效果如何用于获取特定用户数据。

function* fetchUserSaga(action) {
  // `call` function accepts rest arguments, which will be passed to `api.fetchUser` function.
  // Instructing middleware to call promise, it resolved value will be assigned to `userData` variable
  const userData = yield call(api.fetchUser, action.userId);

  // Instructing middleware to dispatch corresponding action.
  yield put({
    type: 'FETCH_USER_SUCCESS',
    userData,
  });
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

什么是 Redux Thunk?

Redux Thunk中间件允许您编写返回函数而非 Action 的 Action 创建器。Thunk 可用于延迟 Action 的调度,或仅在满足特定条件时调度。内部函数接收 store 方法dispatch()getState()作为参数。

⬆ 返回顶部

redux-saga之间有什么区别redux-thunk

Redux ThunkRedux Saga处理副作用。在大多数情况下,Thunk 使用Promises来处理副作用,而 Saga 使用Generators来处理。Thunk 简单易用,Promises 也为许多开发者所熟悉,而 Sagas/Generators 功能更强大,但您需要学习它们。不过,这两种中间件可以共存,因此您可以先使用 Thunk,然后在需要时再引入 Sagas。

⬆ 返回顶部

什么是 Redux DevTools?

Redux DevTools是一个实时编辑的 Redux 时间旅行环境,具有热重载、动作回放和可自定义的 UI。如果您不想费力安装 Redux DevTools 并将其集成到项目中,可以考虑使用适用于 Chrome 和 Firefox 的 Redux DevTools 扩展程序。

⬆ 返回顶部

Redux DevTools 有哪些功能?

Redux DevTools 的一些主要功能如下:

  1. 让您检查每个状态和动作有效载荷。
  2. 让您通过取消操作回到过去。
  3. 如果您更改了 Reducer 代码,则每个分阶段的操作都将被重新评估。
  4. 如果减速器抛出错误,您将看到在哪个操作中发生了该错误,以及错误是什么。
  5. 使用persistState()商店增强器,您可以在页面重新加载时持久保存调试会话。

⬆ 返回顶部

什么是 Redux 选择器以及为什么要使用它们?

选择器是将 Redux 状态作为参数并返回一些数据传递给组件的函数。

例如,从州获取用户详细信息:

const getUserData = (state) => state.user.data;
Enter fullscreen mode Exit fullscreen mode

这些选择器有两个主要优点,

  1. 选择器可以计算派生数据,允许 Redux 存储最小可能状态
  2. 除非其中一个参数发生变化,否则选择器不会重新计算

⬆ 返回顶部

什么是 Redux Form?

Redux Form与 React 和 Redux 协同工作,使 React 中的表单能够使用 Redux 存储其所有状态。Redux Form 可以处理原始 HTML5 输入,但它也能与 Material UI、React Widgets 和 React Bootstrap 等常见的 UI 框架完美兼容。

⬆ 返回顶部

Redux Form 的主要特性是什么?

Redux Form 的一些主要功能包括:

  1. 通过 Redux 存储持久化字段值。
  2. 验证(同步/异步)和提交。
  3. 字段值的格式化、解析和规范化。

⬆ 返回顶部

如何向 Redux 添加多个中间件?

您可以使用applyMiddleware()

例如,您可以添加redux-thunk并将logger它们作为参数传递给applyMiddleware()

import { createStore, applyMiddleware } from 'redux';
const createStoreWithMiddleware = applyMiddleware(ReduxThunk, logger)(createStore);
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如何在 Redux 中设置初始状态?

您需要将初始状态作为第二个参数传递给 createStore:

const rootReducer = combineReducers({
  todos: todos,
  visibilityFilter: visibilityFilter,
});

const initialState = {
  todos: [{ id: 123, name: 'example', completed: false }],
};

const store = createStore(rootReducer, initialState);
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

Relay 与 Redux 有何不同?

Relay 与 Redux 类似,因为它们都使用单个存储。主要区别在于 Relay 仅管理源自服务器的状态,并且所有对状态的访问都通过GraphQL查询(用于读取数据)和突变(用于更改数据)进行。Relay 会为您缓存数据,并通过仅获取更改的数据(仅此而已)来优化数据获取。

Redux 中的动作是什么?

操作是纯 JavaScript 对象或信息负载,用于将数据从您的应用发送到您的商店。它们是商店的唯一信息来源。操作必须具有 type 属性,用于指示正​​在执行的操作的类型。

例如,让我们采取一个表示添加新待办事项的操作:

{
  type: ADD_TODO,
  text: 'Add todo item'
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

反应原生

⬆ 返回顶部

React Native 和 React 有什么区别?

React是一个 JavaScript 库,支持前端 Web 和在服务器上运行,用于构建用户界面和 Web 应用程序。

React Native是一个可编译为本机应用程序组件的移动框架,允许您使用 JavaScript 构建本机移动应用程序(iOS、Android 和 Windows),允许您使用 React 构建组件,并在底层实现 React。

⬆ 返回顶部

如何测试 React Native 应用程序?

React Native 只能在 iOS 和 Android 等移动模拟器上测试。您可以使用 expo app ( https://expo.io ) 在手机上运行该应用。它使用二维码同步,您的手机和电脑应该处于同一无线网络中。

⬆ 返回顶部

如何在 React Native 中进行日志记录?

您可以使用console.logconsole.warn等。从 React Native v0.29 开始,您只需运行以下命令即可在控制台中查看日志:

$ react-native log-ios
$ react-native log-android
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如何调试你的 React Native?

按照以下步骤调试 React Native 应用程序:

  1. 在 iOS 模拟器中运行您的应用程序。
  2. 按下Command + D,网页就会打开http://localhost:8081/debugger-ui
  3. 启用“捕获异常时暂停”以获得更好的调试体验。
  4. 按打开 Chrome 开发者工具,或者通过-> ->Command + Option + I打开ViewDeveloperDeveloper Tools
  5. 您现在应该能够像平常一样进行调试。

React 支持的库和集成

⬆ 返回顶部

什么是重新选择以及它如何工作?

Reselect是一个使用memoization概念的 Redux选择器库。它最初是为了计算类似 Redux 应用程序状态中的派生数据而编写的,但它不能与任何架构或库绑定。

Reselect 会保留上次调用的最后输入/输出的副本,并且仅当其中一个输入发生变化时才重新计算结果。如果连续两次提供相同的输入,Reselect 将返回缓存的输出。它的记忆和缓存功能完全可自定义。

⬆ 返回顶部

什么是 Flow?

Flow是一个静态类型检查器,旨在查找 JavaScript 中的类型错误。与传统类型系统相比,Flow 类型可以表达更细粒度的区分。例如,null与大多数类型系统不同,Flow 可以帮助您捕获涉及 的错误。

⬆ 返回顶部

Flow 和 PropTypes 有什么区别?

Flow 是一个静态分析工具(静态检查器),它使用语言的超集,允许您向所有代码添加类型注释并在编译时捕获一整类错误。

PropTypes 是一个基础类型检查器(运行时检查器),现已添加到 React 中。它只能检查传递给指定组件的 props 的类型。如果您希望为整个项目进行更灵活的类型检查,Flow/TypeScript 是合适的选择。

⬆ 返回顶部

如何在 React 中使用 Font Awesome 图标?

按照以下步骤将 Font Awesome 纳入 React 中:

  1. 安装font-awesome
   $ npm install --save font-awesome
Enter fullscreen mode Exit fullscreen mode
  1. 导入font-awesome您的index.js文件:
   import 'font-awesome/css/font-awesome.min.css';
Enter fullscreen mode Exit fullscreen mode
  1. 在以下位置添加 Font Awesome 类className
   render() {
     return <div><i className={'fa fa-spinner'} /></div>
   }
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

什么是 React Dev Tools?

React 开发者工具可让您检查组件层次结构,包括组件 props 和状态。它既可以作为浏览器扩展(适用于 Chrome 和 Firefox),也可以作为独立应用(适用于其他环境,包括 Safari、IE 和 React Native)。

适用于不同浏览器或环境的官方扩展。

  1. Chrome 扩展程序
  2. Firefox 扩展
  3. 独立应用程序(Safari、React Native 等)

⬆ 返回顶部

为什么 DevTools 无法在 Chrome 中加载本地文件?

如果您在浏览器中打开了本地 HTML 文件(file://...),那么您必须首先打开Chrome 扩展程序并检查Allow access to file URLs

⬆ 返回顶部

如何在 React 中使用 Polymer?

您需要按照以下步骤在 React 中使用 Polymer,

  1. 创建聚合物元素:
   <link rel="import" href="../../bower_components/polymer/polymer.html" />;
   Polymer({
     is: 'calender-element',
     ready: function () {
       this.textContent = 'I am a calender';
     },
   });
Enter fullscreen mode Exit fullscreen mode
  1. 通过将 Polymer 组件 HTML 标签导入 HTML 文档来创建它,例如将其导入到index.htmlReact 应用程序中:
   <link rel="import" href="./src/polymer-components/calender-element.html" />
Enter fullscreen mode Exit fullscreen mode
  1. 在 JSX 文件中使用该元素:
   import React from 'react';

   class MyComponent extends React.Component {
     render() {
       return <calender-element />;
     }
   }

   export default MyComponent;
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

React 相对于 Vue.js 有哪些优势?

React 相比 Vue.js 具有以下优势:

  1. 在大型应用程序开发中提供更大的灵活性。
  2. 更容易测试。
  3. 适用于创建移动应用程序。
  4. 提供更多信息和解决方案。

注:以上优势仅代表个人观点,具体情况会根据专业经验而有所不同。但它们作为基本参数很有用。

⬆ 返回顶部

React 和 Angular 有什么区别?

让我们以表格形式看看 React 和 Angular 之间的区别。

反应 角度
React 是一个库,只有 View 层 Angular 是一个框架,具有完整的 MVC 功能
React 在服务器端处理渲染 AngularJS 仅在客户端渲染,但 Angular 2 及更高版本在服务器端渲染
React 使用 JSX,它看起来像 JS 中的 HTML,这可能会造成混淆 Angular 遵循 HTML 的模板方法,这使得代码更短且易于理解
React Native,是一种 React 类型,用于构建更快、更稳定的移动应用程序 Ionic,Angular 的移动原生应用相对不太稳定,速度较慢
在 React 中,数据仅以单向流动,因此调试很容易 在 Angular 中,数据是双向流动的,即子组件和父组件之间有双向数据绑定,因此调试通常很困难

注意:以上差异列表仅代表个人观点,具体差异会根据专业经验而有所不同。但它们作为基本参数很有用。

⬆ 返回顶部

为什么 React 选项卡没有显示在 DevTools 中?

页面加载时,React DevTools会设置一个名为 的全局变量__REACT_DEVTOOLS_GLOBAL_HOOK__,然后 React 会在初始化期间与该钩子进行通信。如果网站未使用 React,或者 React 无法与 DevTools 通信,则不会显示该标签页。

⬆ 返回顶部

什么是样式组件?

styled-components是一个用于设置 React 应用程序样式的 JavaScript 库。它消除了样式和组件之间的映射,让你能够编写实际的 CSS 代码,并辅以 JavaScript 的支持。

⬆ 返回顶部

给出一个 Styled Components 的例子?

让我们为每个组件创建具有特定样式的<Title>组件<Wrapper>

import React from 'react';
import styled from 'styled-components';

// Create a <Title> component that renders an <h1> which is centered, red and sized at 1.5em
const Title = styled.h1`
  font-size: 1.5em;
  text-align: center;
  color: palevioletred;
`;

// Create a <Wrapper> component that renders a <section> with some padding and a papayawhip background
const Wrapper = styled.section`
  padding: 4em;
  background: papayawhip;
`;
Enter fullscreen mode Exit fullscreen mode

这两个变量TitleWrapper现在是您可以像任何其他反应组件一样渲染的组件。

<Wrapper>
  <Title>{'Lets start first styled component!'}</Title>
</Wrapper>
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

什么是 Relay?

Relay 是一个 JavaScript 框架,用于使用 React 视图层为 Web 应用程序提供数据层和客户端-服务器通信。

⬆ 返回顶部

如何在create-react-app应用程序中使用 TypeScript?

从react-scripts@2.1.0或更高版本开始,内置了对 TypeScript 的支持。也就是说,create-react-app现在原生支持 TypeScript。您只需传递--typescript以下选项即可:

npx create-react-app my-app --typescript

# or

yarn create react-app my-app --typescript
Enter fullscreen mode Exit fullscreen mode

但是对于较低版本的反应脚本,只需在创建新项目时提供--scripts-version选项即可。是一组调整,采用标准项目管道并将 TypeScript 融入其中。react-scripts-tsreact-scripts-tscreate-react-app

现在项目布局应该如下所示:

my-app/
├─ .gitignore
├─ images.d.ts
├─ node_modules/
├─ public/
├─ src/
│  └─ ...
├─ package.json
├─ tsconfig.json
├─ tsconfig.prod.json
├─ tsconfig.test.json
└─ tslint.json
Enter fullscreen mode Exit fullscreen mode

各种各样的

⬆ 返回顶部

Reselect 库的主要功能是什么?

让我们看看 Reselect 库的主要功能,

  1. 选择器可以计算派生数据,从而允许 Redux 存储尽可能小的状态。
  2. 选择器非常高效。除非参数发生变化,否则选择器不会重新计算。
  3. 选择器是可组合的。它们可以用作其他选择器的输入。

举一个Reselect用法的例子?

让我们使用 Reselect 的简化用法来计算装运订单的不同金额:

import { createSelector } from 'reselect';

const shopItemsSelector = (state) => state.shop.items;
const taxPercentSelector = (state) => state.shop.taxPercent;

const subtotalSelector = createSelector(shopItemsSelector, (items) =>
  items.reduce((acc, item) => acc + item.value, 0),
);

const taxSelector = createSelector(
  subtotalSelector,
  taxPercentSelector,
  (subtotal, taxPercent) => subtotal * (taxPercent / 100),
);

export const totalSelector = createSelector(subtotalSelector, taxSelector, (subtotal, tax) => ({
  total: subtotal + tax,
}));

let exampleState = {
  shop: {
    taxPercent: 8,
    items: [
      { name: 'apple', value: 1.2 },
      { name: 'orange', value: 0.95 },
    ],
  },
};

console.log(subtotalSelector(exampleState)); // 2.15
console.log(taxSelector(exampleState)); // 0.172
console.log(totalSelector(exampleState)); // { total: 2.322 }
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

静态对象可以与 React 中的 ES6 类一起使用吗?

否,statics仅适用于React.createClass()

someComponent = React.createClass({
  statics: {
    someMethod: function () {
      // ..
    },
  },
});
Enter fullscreen mode Exit fullscreen mode

但是你可以在 ES6+ 类中编写静态代码,如下所示,

class Component extends React.Component {
  static propTypes = {
    // ...
  };

  static someMethod() {
    // ...
  }
}
Enter fullscreen mode Exit fullscreen mode

或者在课外写如下,

class Component extends React.Component {
  ....
}

Component.propTypes = {...}
Component.someMethod = function(){....}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

Redux 只能与 React 一起使用吗?

Redux 可以用作任何 UI 层的数据存储。最常见的用法是与 React 和 React Native 配合使用,但也为 Angular、Angular 2、Vue、Mithril 等提供绑定。Redux 仅提供了一种订阅机制,可供任何其他代码使用。

⬆ 返回顶部

您是否需要特定的构建工具才能使用 Redux?

Redux 最初是用 ES6 编写的,并使用 Webpack 和 Babel 将其转译为 ES5 以供生产环境使用。无论您的 JavaScript 构建过程如何,都应该能够使用它。Redux 还提供了 UMD 构建,无需任何构建过程即可直接使用。

⬆ 返回顶部

Redux Form 如何initialValues从状态获取更新?

您需要添加enableReinitialize : true设置。

const InitializeFromStateForm = reduxForm({
  form: 'initializeFromState',
  enableReinitialize: true,
})(UserEdit);
Enter fullscreen mode Exit fullscreen mode

如果您的initialValues道具更新,您的表格也会更新。

⬆ 返回顶部

React PropTypes 如何允许一个 prop 具有不同的类型?

您可以使用oneOfType()的方法PropTypes

例如,高度属性可以用stringnumber类型定义,如下所示:

Component.PropTypes = {
  size: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
};
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

我可以导入 SVG 文件作为反应组件吗?

您可以直接将 SVG 作为组件导入,而无需将其作为文件加载。此功能适用于 32 位react-scripts@2.0.0及更高版本。

import { ReactComponent as Logo } from './logo.svg';

const App = () => (
  <div>
    {/* Logo is an actual react component */}
    <Logo />
  </div>
);
Enter fullscreen mode Exit fullscreen mode

注意:不要忘记导入中的花括号。

⬆ 返回顶部

为什么不推荐使用内联 ref 回调或函数?

如果将 ref 回调定义为内联函数,它将在更新过程中被调用两次,第一次使用 null,第二次使用 DOM 元素。这是因为每次渲染时都会创建一个新的函数实例,因此 React 需要清除旧的 ref 并设置新的 ref。

class UserForm extends Component {
  handleSubmit = () => {
    console.log('Input Value is: ', this.input.value);
  };

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <input type="text" ref={(input) => (this.input = input)} /> // Access DOM input in handle
        submit
        <button type="submit">Submit</button>
      </form>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

但我们的期望是,ref 回调在组件挂载时被调用一次。一个快速的解决方法是使用 ES7 的类属性语法来定义函数

class UserForm extends Component {
  handleSubmit = () => {
    console.log('Input Value is: ', this.input.value);
  };

  setSearchInput = (input) => {
    this.input = input;
  };

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <input type="text" ref={this.setSearchInput} /> // Access DOM input in handle submit
        <button type="submit">Submit</button>
      </form>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

注意:在 React v16.3 中,⬆ 返回顶部

React 中的渲染劫持是什么?

渲染劫持的概念是指能够控制一个组件从另一个组件输出什么内容。它实际上意味着你通过将组件包装到高阶组件中来装饰它。通过包装,你可以注入额外的 props 或进行其他更改,从而改变渲染逻辑。它实际上并不启用渲染劫持,但通过使用 HOC,你可以让你的组件以不同的方式运行。

⬆ 返回顶部

HOC 工厂实现有哪些?

在 React 中实现 HOC 主要有两种方式。

  1. 道具代理(PP)和
  2. 继承反转(二)。

但它们遵循不同的方法来操作WrappedComponent

道具代理

在这个方法中,HOC 的 render 方法返回一个 WrappedComponent 类型的 React Element。我们还会传递 HOC 接收到的 props,因此得名Props Proxy

function ppHOC(WrappedComponent) {
  return class PP extends React.Component {
    render() {
      return <WrappedComponent {...this.props} />;
    }
  };
}
Enter fullscreen mode Exit fullscreen mode

继承反转

在这种方法中,返回的 HOC 类(Enhancer)会扩展 WrappedComponent。之所以称之为反向继承,是因为 WrappedComponent 不是扩展某个 Enhancer 类,而是被动地被 Enhancer 扩展。这样一来,它们之间的关系看起来似乎是反向的

function iiHOC(WrappedComponent) {
  return class Enhancer extends WrappedComponent {
    render() {
      return super.render();
    }
  };
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如何将数字传递给 React 组件?

您应该通过花括号({})传递数字,而将字符串放在引号中

React.render(<User age={30} department={'IT'} />, document.getElementById('container'));
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

我需要把所有状态都保存到 Redux 中吗?我应该使用 React 内部状态吗?

这取决于开发人员的决定。也就是说,开发人员需要确定应用程序由哪些类型的状态组成,以及每种状态应该存放在何处。有些用户倾向于将每条数据都保存在 Redux 中,以便始终保持应用程序完全可序列化且受控的版本。而另一些用户则倾向于将非关键状态或 UI 状态(例如“此下拉菜单当前是否打开”)保存在组件的内部状态中。

以下是确定应将哪种类型的数据放入 Redux 的经验法则

  1. 应用程序的其他部分是否关心这些数据?
  2. 您是否需要能够基于这些原始数据创建进一步的派生数据?
  3. 是否使用相同的数据来驱动多个组件?
  4. 能够将此状态恢复到给定的时间点(即时间旅行调试)对您来说有价值吗?
  5. 您是否要缓存数据(即,如果数据已经存在则使用当前状态,而不是重新请求它)?

⬆ 返回顶部

React 中 registerServiceWorker 的用途是什么?

React 默认会创建一个 Service Worker,无需任何配置。Service Worker 是一个 Web API,它能帮助你缓存资源和其他文件,以便用户在离线或网络速度较慢时仍能在屏幕上看到结果,从而提升用户体验。以上就是你目前需要了解的 Service Worker 的全部内容。它主要讲的是为网站添加离线功能。

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import registerServiceWorker from './registerServiceWorker';

ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

React 备忘录功能是什么?

当类组件的输入 props 相同时,可以使用PureComponent 或 shouldComponentUpdate限制其渲染。现在,你可以将函数组件包装在React.memo中,从而实现同样的效果。

const MyComponent = React.memo(function MyComponent(props) {
  /* only rerenders if props change */
});
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

什么是 React 惰性函数?

React.lazy函数允许你将动态导入的组件渲染为常规组件。当组件渲染时,它将自动加载包含 OtherComponent 的 bundle。它必须返回一个 Promise,该 Promise 解析为一个默认导出的模块,该模块包含一个 React 组件。

const OtherComponent = React.lazy(() => import('./OtherComponent'));

function MyComponent() {
  return (
    <div>
      <OtherComponent />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

注意: React.lazy 和 Suspense 尚不支持服务端渲染。如果您想在服务端渲染的应用中进行代码拆分,我们仍然推荐使用 React Loadable。

⬆ 返回顶部

如何防止使用 setState 进行不必要的更新?

您可以将状态的当前值与现有状态值进行比较,并决定是否重新渲染页面。如果值相同,则需要返回null以停止重新渲染,否则返回最新的状态值。

例如,用户个人资料信息有条件地呈现如下,

getUserProfile = (user) => {
  const latestAddress = user.address;
  this.setState((state) => {
    if (state.address === latestAddress) {
      return null;
    } else {
      return { title: latestAddress };
    }
  });
};
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如何在 React 16 版本中渲染数组、字符串和数字?

数组:与旧版本不同,在 React16 中,你无需确保render方法返回单个元素。你可以通过返回数组来返回多个兄弟元素,而无需使用包装元素。

例如,让我们来看看下面的开发人员列表,

const ReactJSDevs = () => {
  return [<li key="1">John</li>, <li key="2">Jackie</li>, <li key="3">Jordan</li>];
};
Enter fullscreen mode Exit fullscreen mode

您还可以将此项目数组合并到另一个数组组件中。

const JSDevs = () => {
  return (
    <ul>
      <li>Brad</li>
      <li>Brodge</li>
      <ReactJSDevs />
      <li>Brandon</li>
    </ul>
  );
};
Enter fullscreen mode Exit fullscreen mode

字符串和数字:您还可以从渲染方法返回字符串和数字类型。

render() {
return 'Welcome to ReactJS questions';
}
// Number
render() {
return 2018;
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如何在 React 类中使用类字段声明语法?

使用类字段声明可以使 React 类组件更加简洁。您可以无需使用构造函数来初始化本地状态,并使用箭头函数声明类方法,而无需额外绑定它们。

让我们举一个反例来演示不使用构造函数和不绑定方法的状态的类字段声明,

class Counter extends Component {
  state = { value: 0 };

  handleIncrement = () => {
    this.setState((prevState) => ({
      value: prevState.value + 1,
    }));
  };

  handleDecrement = () => {
    this.setState((prevState) => ({
      value: prevState.value - 1,
    }));
  };

  render() {
    return (
      <div>
        {this.state.value}

        <button onClick={this.handleIncrement}>+</button>
        <button onClick={this.handleDecrement}>-</button>
      </div>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

什么是钩子?

Hooks 是一项新功能(React 16.8),它允许您无需编写类即可使用状态和其他 React 功能。

让我们看一个 useState hook 的例子,

import { useState } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

钩子需要遵循什么规则?

使用钩子需要遵循两个规则,

  1. 仅在 React 函数的顶层调用 Hook。也就是说,不应在循环、条件或嵌套函数中调用 Hook。这将确保每次组件渲染时 Hook 都以相同的顺序被调用,并在多次 useState 和 useEffect 调用之间保留 Hook 的状态。
  2. 仅从 React 函数调用 Hooks。即,您不应该从常规 JavaScript 函数调用 Hooks。

⬆ 返回顶部

如何确保钩子遵循项目中的规则?

React 团队发布了一个名为eslint-plugin-react-hooks的 ESLint 插件,它强制执行这两条规则。你可以使用以下命令将此插件添加到你的项目中:

npm install eslint-plugin-react-hooks@next
Enter fullscreen mode Exit fullscreen mode

并在你的 ESLint 配置文件中应用以下配置,

// Your ESLint configuration
{
  "plugins": [
    // ...
    "react-hooks"
  ],
  "rules": {
    // ...
    "react-hooks/rules-of-hooks": "error"
  }
}
Enter fullscreen mode Exit fullscreen mode

注意:此插件默认在 Create React App 中使用。

⬆ 返回顶部

Flux 和 Redux 之间有什么区别?

以下是 Flux 和 Redux 之间的主要区别

通量 Redux
状态是可变的 状态是不可变的
Store 包含状态和变更逻辑 商店和更改逻辑是分开的
存在多个商店 仅存在一家商店
所有商店均断开且平坦 具有分层 Reducer 的单一存储
它有一个单例调度程序 没有调度员的概念
React 组件订阅 store 容器组件使用 connect 函数

⬆ 返回顶部

React Router V4 有哪些好处?

以下是 React Router V4 模块的主要优点,

  1. 在 React Router v4(版本 4)中,API 完全与组件相关。路由器可以被视为一个单独的组件(<BrowserRouter>),它包装了特定的子路由器组件(<Route>)。
  2. 您无需手动设置历史记录。路由器模块会通过使用<BrowserRouter>组件包装路由来处理历史记录。
  3. 通过仅添加特定的路由器模块(Web,核心或本机)来减小应用程序大小

⬆ 返回顶部

您能描述一下 componentDidCatch 生命周期方法签名吗?

componentDidCatch生命周期方法在后代组件抛出错误后调用。该方法接收两个参数:

  1. 错误:- 抛出的错误对象
  2. 信息: - 带有 componentStack 键的对象包含有关哪个组件引发错误的信息。

方法结构如下

componentDidCatch(error, info);
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

在哪些情况下错误边界不会捕获错误?

以下是错误边界不起作用的情况,

  1. 事件处理程序内部
  2. 使用setTimeout 或 requestAnimationFrame回调的异步代码
  3. 在服务器端渲染期间
  4. 当错误边界代码本身抛出错误时

⬆ 返回顶部

为什么事件处理程序不需要错误边界?

错误边界无法捕获事件处理程序中的错误。与渲染方法或生命周期方法不同,事件处理程序不会在渲染期间发生或调用。因此,React 知道如何在事件处理程序中恢复此类错误。如果您仍然需要在事件处理程序中捕获错误,请使用常规 JavaScript try / catch 语句,如下所示

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { error: null };
  }

  handleClick = () => {
    try {
      // Do something that could throw
    } catch (error) {
      this.setState({ error });
    }
  };

  render() {
    if (this.state.error) {
      return <h1>Caught an error.</h1>;
    }
    return <div onClick={this.handleClick}>Click Me</div>;
  }
}
Enter fullscreen mode Exit fullscreen mode

上述代码使用原始 javascript try/catch 块而不是错误边界来捕获错误。

⬆ 返回顶部

try catch 块和错误边界之间有什么区别?

Try catch 块与命令式代码一起工作,而错误边界则用于在屏幕上呈现声明式代码。

例如,用于以下命令式代码的 try catch 块

try {
  showButton();
} catch (error) {
  // ...
}
Enter fullscreen mode Exit fullscreen mode

错误边界包装声明性代码如下,

<ErrorBoundary>
  <MyComponent />
</ErrorBoundary>
Enter fullscreen mode Exit fullscreen mode

因此,如果在组件树深处的某个地方,由setState导致的componentDidUpdate方法中发生错误,它仍然会正确传播到最近的错误边界。

⬆ 返回顶部

React 16 中未捕获错误的行为是怎样的?

在 React 16 中,任何未被错误边界捕获的错误都将导致整个 React 组件树被卸载。这样做的原因是,保留损坏的 UI 比彻底移除它更糟糕。例如,对于支付应用来说,显示错误的金额比什么都不渲染更糟糕。

⬆ 返回顶部

错误边界的正确位置是什么?

错误边界使用的粒度取决于开发人员的项目需求。您可以采用以下任一方法:

  1. 您可以包装顶级路由组件来显示整个应用程序的通用错误消息。
  2. 您还可以将单个组件包装在错误边界中,以防止它们导致应用程序的其余部分崩溃。

⬆ 返回顶部

从错误边界进行组件堆栈跟踪有什么好处?

除了错误消息和 JavaScript 堆栈之外,React16 还将使用错误边界概念显示带有文件名和行号的组件堆栈跟踪。

例如,BuggyCounter 组件显示组件堆栈跟踪如下,

堆栈跟踪

⬆ 返回顶部

类组件需要定义什么方法?

render()方法是类组件中唯一必需的方法。即,对于类组件来说,除了 render 方法之外的所有方法都是可选的。

⬆ 返回顶部

render 方法可能的返回类型有哪些?

以下是使用并从渲染方法返回的类型的列表,

  1. React 元素:指示 React 渲染 DOM 节点的元素。它包括 HTML 元素,例如 JavaScript 元素<div/>和用户定义元素。
  2. 数组和片段:返回多个元素以呈现为数组和片段来包装多个元素
  3. 门户:将子项渲染到不同的 DOM 子树中。
  4. 字符串和数字:将字符串和数字渲染为 DOM 中的文本节点
  5. 布尔值或空值:不渲染任何内容,但这些类型用于有条件地渲染内容。

⬆ 返回顶部

构造函数的主要用途是什么?

构造函数主要用于两个目的,

  1. 通过将对象赋值给 this.state 来初始化本地状态
  2. 将事件处理程序方法绑定到实例例如,下面的代码涵盖了上述两种情况,
constructor(props) {
  super(props);
  // Don't call this.setState() here!
  this.state = { counter: 0 };
  this.handleClick = this.handleClick.bind(this);
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

是否必须为 React 组件定义构造函数?

不,这不是强制性的。即,如果您不初始化状态并且不绑定方法,则不需要为 React 组件实现构造函数。

⬆ 返回顶部

什么是默认道具?

defaultProps 是组件类的一个属性,用于设置该类的默认 props。它用于未定义的 props,但不用于 null props。

例如,让我们为按钮组件创建颜色默认属性,

class MyButton extends React.Component {
  // ...
}

MyButton.defaultProps = {
  color: 'red',
};
Enter fullscreen mode Exit fullscreen mode

如果未提供 props.color,则它将默认值设置为“红色”。即,每当您尝试访问颜色属性时,它都会使用默认值

render() {
  return <MyButton /> ; // props.color will be set to red
}
Enter fullscreen mode Exit fullscreen mode

注意:如果您提供空值,那么它仍保持空值。

⬆ 返回顶部

为什么不应该在 componentWillUnmount 中调用 setState?

您不应该调用setState()componentWillUnmount()因为一旦组件实例被卸载,它将永远不会再次被安装。

⬆ 返回顶部

getDerivedStateFromError 的目的是什么?

此生命周期方法在后代组件抛出错误后调用。它接收抛出的错误作为参数,并返回一个值来更新状态。

生命周期方法的签名如下,

static getDerivedStateFromError(error)
Enter fullscreen mode Exit fullscreen mode

让我们以上述生命周期方法的错误边界用例为例进行演示,

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // Update state so the next render will show the fallback UI.
    return { hasError: true };
  }

  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return <h1>Something went wrong.</h1>;
    }

    return this.props.children;
  }
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

组件重新渲染时的方法顺序是什么?

更新可能由 props 或 state 的更改引起。当组件重新渲染时,将按以下顺序调用以下方法。

  1. 静态 getDerivedStateFromProps()
  2. 应该组件更新()
  3. 使成为()
  4. 获取更新前的快照()
  5. 组件更新()

⬆ 返回顶部

错误处理期间调用哪些方法?

当渲染过程中、生命周期方法中或任何子组件的构造函数中出现错误时,将调用以下方法。

  1. 静态 getDerivedStateFromError()
  2. 组件DidCatch()

⬆ 返回顶部

displayName 类属性的用途是什么?

displayName 字符串用于调试消息。通常情况下,您无需显式设置它,因为它是根据定义组件的函数或类的名称推断出来的。如果您希望为了调试目的或创建高阶组件时显示不同的名称,则可能需要显式设置它。

例如,为了便于调试,请选择一个显示名称来表明它是 withSubscription HOC 的结果。

function withSubscription(WrappedComponent) {
  class WithSubscription extends React.Component {
    /* ... */
  }
  WithSubscription.displayName = `WithSubscription(${getDisplayName(WrappedComponent)})`;
  return WithSubscription;
}
function getDisplayName(WrappedComponent) {
  return WrappedComponent.displayName || WrappedComponent.name || 'Component';
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

哪些浏览器支持 React 应用程序?

React 支持所有流行的浏览器,包括 Internet Explorer 9 及更高版本,尽管旧版浏览器(如 IE 9 和 IE 10)需要一些 polyfill。如果使用es5-shim 和 es5-sham polyfill,它甚至支持不支持 ES5 方法的旧版浏览器。

⬆ 返回顶部

unmountComponentAtNode 方法的目的是什么?

此方法来自 react-dom 包,它会从 DOM 中移除已挂载的 React 组件,并清理其事件处理程序和状态。如果容器中未挂载任何组件,则调用此函数不会执行任何操作。如果组件已卸载,则返回 true;如果没有可卸载的组件,则返回 false。

方法签名如下,

ReactDOM.unmountComponentAtNode(container);
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

什么是代码分割?

代码拆分是 Webpack 和 Browserify 等打包工具支持的功能,它可以创建多个可在运行时动态加载的包。React 项目通过动态 import() 功能支持代码拆分。

例如,在下面的代码片段中,它将 moduleA.js 及其所有唯一依赖项作为一个单独的块,仅在用户单击“加载”按钮后加载。moduleA.js

const moduleA = 'Hello';

export { moduleA };
Enter fullscreen mode Exit fullscreen mode

App.js

import React, { Component } from 'react';

class App extends Component {
  handleClick = () => {
    import('./moduleA')
      .then(({ moduleA }) => {
        // Use moduleA
      })
      .catch((err) => {
        // Handle failure
      });
  };

  render() {
    return (
      <div>
        <button onClick={this.handleClick}>Load</button>
      </div>
    );
  }
}

export default App;
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

严格模式有什么好处?

这在以下情况下会有所帮助

  1. 识别具有不安全生命周期方法的组件。
  2. 关于旧字符串引用API 使用的警告。
  3. 检测意外的副作用
  4. 检测遗留上下文API。
  5. 关于弃用 findDOMNode 用法的警告

⬆ 返回顶部

什么是 Keyed Fragments?

使用显式语法声明的 Fragment 可以包含键。一般用例是将集合映射到 Fragment 数组,如下所示:

function Glossary(props) {
  return (
    <dl>
      {props.items.map((item) => (
        // Without the `key`, React will fire a key warning
        <React.Fragment key={item.id}>
          <dt>{item.term}</dt>
          <dd>{item.description}</dd>
        </React.Fragment>
      ))}
    </dl>
  );
}
Enter fullscreen mode Exit fullscreen mode

注意: key 是唯一可以传递给 Fragment 的属性。未来可能会支持其他属性,例如事件处理程序。

⬆ 返回顶部

React 是否支持所有 HTML 属性?

从 React 16 开始,标准或自定义 DOM 属性均已完全支持。由于 React 组件通常同时使用自定义属性和 DOM 相关属性,因此 React 像 DOM API 一样使用了驼峰命名约定。

让我们针对标准 HTML 属性采取一些措施,

<div tabIndex="-1" />      // Just like node.tabIndex DOM API
<div className="Button" /> // Just like node.className DOM API
<input readOnly={true} />  // Just like node.readOnly DOM API
Enter fullscreen mode Exit fullscreen mode

这些 props 的作用与相应的 HTML 属性类似,除了特殊情况外。它也支持所有 SVG 属性。

⬆ 返回顶部

HOC 有哪些局限性?

高阶组件除了其优点之外,还有一些注意事项。以下按顺序列出:

  1. 不要在渲染方法中使用 HOC:不建议在组件的渲染方法中将 HOC 应用于组件。
render() {
  // A new version of EnhancedComponent is created on every render
  // EnhancedComponent1 !== EnhancedComponent2
  const EnhancedComponent = enhance(MyComponent);
  // That causes the entire subtree to unmount/remount each time!
  return <EnhancedComponent />;
}
Enter fullscreen mode Exit fullscreen mode

上述代码会重新挂载组件,导致该组件及其所有子组件的状态丢失,从而影响性能。建议在组件定义之外使用 HOC,这样生成的组件只需创建一次。

  1. 静态方法必须复制:当你将 HOC 应用于组件时,新组件不具有原始组件的任何静态方法
// Define a static method
WrappedComponent.staticMethod = function () {
  /*...*/
};
// Now apply a HOC
const EnhancedComponent = enhance(WrappedComponent);

// The enhanced component has no static method
typeof EnhancedComponent.staticMethod === 'undefined'; // true
Enter fullscreen mode Exit fullscreen mode

您可以通过在返回容器之前将方法复制到容器上来解决这个问题,

function enhance(WrappedComponent) {
  class Enhance extends React.Component {
    /*...*/
  }
  // Must know exactly which method(s) to copy :(
  Enhance.staticMethod = WrappedComponent.staticMethod;
  return Enhance;
}
Enter fullscreen mode Exit fullscreen mode
  1. Refs 不会被传递:对于 HOC,你需要将所有 props 传递给被包装的组件,但这不适用于 ref。这是因为 ref 并非真正类似于 key 的 prop。在这种情况下,你需要使用 React.forwardRef API。

⬆ 返回顶部

如何在 DevTools 中调试 forwardRefs?

React.forwardRef接受渲染函数作为参数,DevTools 使用此函数来确定为 ref 转发组件显示什么。

例如,如果您没有命名渲染函数或不使用 displayName 属性,那么它将在 DevTools 中显示为“ForwardRef”,

const WrappedComponent = React.forwardRef((props, ref) => {
  return <LogProps {...props} forwardedRef={ref} />;
});
Enter fullscreen mode Exit fullscreen mode

但是如果你命名渲染函数,那么它将显示为“ForwardRef(myFunction)”

const WrappedComponent = React.forwardRef(function myFunction(props, ref) {
  return <LogProps {...props} forwardedRef={ref} />;
});
Enter fullscreen mode Exit fullscreen mode

另外,您还可以为 forwardRef 函数设置 displayName 属性,

function logProps(Component) {
  class LogProps extends React.Component {
    // ...
  }

  function forwardRef(props, ref) {
    return <LogProps {...props} forwardedRef={ref} />;
  }

  // Give this component a more helpful display name in DevTools.
  // e.g. "ForwardRef(logProps(MyComponent))"
  const name = Component.displayName || Component.name;
  forwardRef.displayName = `logProps(${name})`;

  return React.forwardRef(forwardRef);
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

组件 props 何时默认为 true?

如果未传递任何 prop 值,则默认为 true。此行为是为了与 HTML 的行为相匹配。

例如,以下表达式是等效的,

<MyInput autocomplete />

<MyInput autocomplete={true} />
Enter fullscreen mode Exit fullscreen mode

注意:不建议使用此方法,因为它可能与 ES6 对象简写混淆(例如,{name}它是 的缩写{name: name}

⬆ 返回顶部

什么是 NextJS 以及它的主要功能?

Next.js 是一个流行的轻量级框架,用于使用 React 构建静态和服务器渲染应用程序。它还提供样式和路由解决方案。以下是 NextJS 提供的主要功能:

  1. 默认服务器渲染
  2. 自动代码分割,加快页面加载速度
  3. 简单的客户端路由(基于页面)
  4. 基于 Webpack 的开发环境,支持(HMR)
  5. 能够使用 Express 或任何其他 Node.js HTTP 服务器实现
  6. 可使用您自己的 Babel 和 Webpack 配置进行定制

⬆ 返回顶部

如何将事件处理程序传递给组件?

你可以将事件处理程序和其他函数作为 props 传递给子组件。它可以在子组件中按如下方式使用:

<button onClick="{this.handleClick}"></button>
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

在渲染方法中使用箭头函数好吗?

是的,你可以使用。这通常是向回调函数传递参数最简单的方法。但是你需要在使用它时优化性能。

class Foo extends Component {
  handleClick() {
    console.log('Click happened');
  }
  render() {
    return <button onClick={() => this.handleClick()}>Click Me</button>;
  }
}
Enter fullscreen mode Exit fullscreen mode

注意:在 render 方法中使用箭头函数会在每次组件渲染时创建一个新函数,这可能会对性能产生影响

⬆ 返回顶部

如何防止一个函数被多次调用?

如果您使用onClick 或 onScroll等事件处理程序,并希望防止回调触发过快,则可以限制回调的执行速率。您可以通过以下方式实现:

  1. 节流:根据时间频率进行更改。例如,可以使用 lodash 函数 _.throttle 来使用它
  2. 去抖动:在一段时间不活动后发布更改。例如,可以使用 _.debounce lodash 函数
  3. RequestAnimationFrame 节流:基于 requestAnimationFrame 进行更改。例如,可以使用 raf-schd lodash 函数

⬆ 返回顶部

JSX 如何防止注入攻击?

React DOM 在渲染 JSX 中嵌入的任何值之前都会进行转义。这样可以确保你永远不会注入任何未在应用程序中明确编写的内容。所有内容在渲染之前都会被转换为字符串。

例如,您可以嵌入如下所示的用户输入,

const name = response.potentiallyMaliciousInput;
const element = <h1>{name}</h1>;
Enter fullscreen mode Exit fullscreen mode

这样您就可以防止应用程序中的 XSS(跨站点脚本)攻击。

⬆ 返回顶部

如何更新渲染元素?

您可以通过将新创建的元素传递给 ReactDOM 的 render 方法来更新 UI(由渲染的元素表示)。

例如,让我们举一个滴答作响的时钟示例,它通过多次调用渲染方法来更新时间,

function tick() {
  const element = (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {new Date().toLocaleTimeString()}.</h2>
    </div>
  );
  ReactDOM.render(element, document.getElementById('root'));
}

setInterval(tick, 1000);
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

怎么说道具是只读的?

当你将组件声明为函数或类时,它绝不能修改其自身的 props。

让我们采取低于资本的函数,

function capital(amount, interest) {
  return amount + interest;
}
Enter fullscreen mode Exit fullscreen mode

上述函数被称为“纯函数”,因为它不会尝试改变输入,并且对于相同的输入始终返回相同的结果。因此,React 有一条规则:“所有 React 组件在处理其 props 时都必须表现得像纯函数。”

⬆ 返回顶部

您如何说状态更新已合并?

当你在组件中调用 setState() 时,React 会将你提供的对象合并到当前状态中。

例如,让我们以 Facebook 用户的帖子和评论详细信息作为状态变量,

  constructor(props) {
    super(props);
    this.state = {
      posts: [],
      comments: []
    };
  }
Enter fullscreen mode Exit fullscreen mode

现在,您可以使用下面的单独调用来独立更新它们setState()

componentDidMount() {
    fetchPosts().then(response => {
      this.setState({
        posts: response.posts
      });
    });

    fetchComments().then(response => {
      this.setState({
        comments: response.comments
      });
    });
  }
Enter fullscreen mode Exit fullscreen mode

如上面的代码片段所述,this.setState({comments})仅更新评论变量而不修改或替换帖子变量。

⬆ 返回顶部

如何将参数传递给事件处理程序?

在迭代或循环期间,通常需要向事件处理程序传递一个额外的参数。这可以通过箭头函数或 bind 方法实现。

让我们以网格中更新的用户详细信息为例,

<button onClick={(e) => this.updateUser(userId, e)}>Update User details</button>
<button onClick={this.updateUser.bind(this, userId)}>Update User details</button>
Enter fullscreen mode Exit fullscreen mode

在这两种方法中,合成参数 e 都作为第二个参数传递。对于箭头函数,你需要显式地传递它;对于 bind 方法,它会自动转发。

⬆ 返回顶部

如何防止组件渲染?

你可以通过根据特定条件返回 null 来阻止组件渲染。这样就可以有条件地渲染组件。

function Greeting(props) {
  if (!props.loggedIn) {
    return null;
  }

  return <div className="greeting">welcome, {props.name}</div>;
}
Enter fullscreen mode Exit fullscreen mode
class User extends React.Component {
  constructor(props) {
    super(props);
    this.state = {loggedIn: false, name: 'John'};
  }

  render() {
  return (
      <div>
        //Prevent component render if it is not loggedIn
        <Greeting loggedIn={this.state.loggedIn} />
        <UserDetails name={this.state.name}>
      </div>
  );
  }
Enter fullscreen mode Exit fullscreen mode

在上面的例子中,greeting 组件通过应用条件并返回空值来跳过其渲染部分。

⬆ 返回顶部

安全地使用索引作为键的条件是什么?

有三个条件可以确保使用索引作为键是安全的。

  1. 列表和项目是静态的——它们不会被计算,也不会改变
  2. 列表中的项目没有 ID
  3. 该列表从未被重新排序或过滤。

⬆ 返回顶部

密钥应该是全局唯一的吗?

数组中使用的键在其兄弟数组中应该是唯一的,但它们不需要是全局唯一的。即,您可以在两个不同的数组中使用相同的键。

例如,下面的书籍组件使用两个具有不同数组的数组,

function Book(props) {
  const index = (
    <ul>
      {props.pages.map((page) => (
        <li key={page.id}>{page.title}</li>
      ))}
    </ul>
  );
  const content = props.pages.map((page) => (
    <div key={page.id}>
      <h3>{page.title}</h3>
      <p>{page.content}</p>
      <p>{page.pageNumber}</p>
    </div>
  ));
  return (
    <div>
      {index}
      <hr />
      {content}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

表单处理的流行选择是什么?

Formik是一个用于 React 的表单库,它提供验证、跟踪访问的字段和处理表单提交等解决方案。

具体来说,您可以将其分类如下,

  1. 获取表单状态中的值和从表单状态中获取值
  2. 验证和错误消息
  3. 处理表单提交

它用于创建一个可扩展、高性能的表单助手,并使用最少的 API 来解决烦人的问题。

⬆ 返回顶部

formik 相对于 redux 表单库有哪些优势?

以下是推荐 formik 而不是 redux 表单库的主要原因,

  1. 表单状态本质上是短期和本地的,因此在 Redux(或任何类型的 Flux 库)中跟踪它是不必要的。
  2. Redux-Form 每次按键都会多次调用整个顶层 Redux Reducer。这会增加大型应用的输入延迟。
  3. Redux-Form 压缩后大小为 22.5 kB,而 Formik 压缩后大小为 12.7 kB

⬆ 返回顶部

为什么不需要使用继承?

在 React 中,建议使用组合而不是继承来实现组件间的代码复用。Props 和组合都提供了所需的灵活性,让您能够以明确且安全的方式自定义组件的外观和行为。然而,如果您想在组件间复用非 UI 功能,建议将其提取到单独的 JavaScript 模块中。后续组件可以导入并使用该函数、对象或类,而无需对其进行扩展。

⬆ 返回顶部

我可以在 React 应用程序中使用 Web 组件吗?

是的,你可以在 React 应用程序中使用 Web Components。虽然很多开发者不会使用这种组合,但当你使用基于 Web Components 编写的第三方 UI 组件时,可能需要这样做。

例如,让我们使用Vaadin如下所示的日期选择器 Web 组件,

import React, { Component } from 'react';
import './App.css';
import '@vaadin/vaadin-date-picker';
class App extends Component {
  render() {
    return (
      <div className="App">
        <vaadin-date-picker label="When were you born?"></vaadin-date-picker>
      </div>
    );
  }
}
export default App;
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

什么是动态导入?

动态 import() 语法是 ECMAScript 的一个提案,目前并非语言标准的一部分。预计不久的将来会被接受。您可以使用动态导入在应用中实现代码拆分。

让我们举一个加法的例子,

  1. 正常导入
import { add } from './math';
console.log(add(10, 20));
Enter fullscreen mode Exit fullscreen mode
  1. 动态导入
import('./math').then((math) => {
  console.log(math.add(10, 20));
});
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

什么是可加载组件?

如果要在服务器渲染的应用中进行代码拆分,建议使用可加载组件 (Loadable Components),因为 React.lazy 和 Suspense 尚不支持服务器端渲染。可加载组件 (Loadable Components) 允​​许你将动态导入的组件渲染为常规组件。

让我们举个例子,

import loadable from '@loadable/component';

const OtherComponent = loadable(() => import('./OtherComponent'));

function MyComponent() {
  return (
    <div>
      <OtherComponent />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

现在 OtherComponent 将被加载到单独的 bundle 中

⬆ 返回顶部

什么是悬念组件?

如果包含动态导入的模块在父组件渲染时尚未加载,则必须在等待其加载期间使用加载指示器显示一些后备内容。这可以使用Suspense组件来实现。

例如,下面的代码使用了 Suspense 组件,

const OtherComponent = React.lazy(() => import('./OtherComponent'));

function MyComponent() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <OtherComponent />
      </Suspense>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

如上面的代码所述,Suspense 被包裹在惰性组件之上。

⬆ 返回顶部

什么是基于路由的代码拆分?

代码拆分的最佳位置之一是路由。整个页面将立即重新渲染,因此用户不太可能同时与页面中的其他元素进行交互。因此,用户体验不会受到影响。

让我们以使用 React Router 和 React.lazy 等库的基于路由的网站为例,

import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import React, { Suspense, lazy } from 'react';

const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));

const App = () => (
  <Router>
    <Suspense fallback={<div>Loading...</div>}>
      <Switch>
        <Route exact path="/" component={Home} />
        <Route path="/about" component={About} />
      </Switch>
    </Suspense>
  </Router>
);
Enter fullscreen mode Exit fullscreen mode

在上面的代码中,代码拆分将在每个路由级别发生。

⬆ 返回顶部

举一个如何使用上下文的例子?

Context旨在共享可被视为React 组件树的全局数据。

例如,在下面的代码中,可以手动穿过“主题”道具来设置按钮组件的样式。

//Lets create a context with a default theme value "luna"
const ThemeContext = React.createContext('luna');
// Create App component where it uses provider to pass theme value in the tree
class App extends React.Component {
  render() {
    return (
      <ThemeContext.Provider value="nova">
        <Toolbar />
      </ThemeContext.Provider>
    );
  }
}
// A middle component where you don't need to pass theme prop anymore
function Toolbar(props) {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}
// Lets read theme value in the button component to use
class ThemedButton extends React.Component {
  static contextType = ThemeContext;
  render() {
    return <Button theme={this.context} />;
  }
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

上下文中默认值的目的是什么?

defaultValue 参数仅当组件树中没有匹配的上级 Provider 时使用。这有助于在不包装组件的情况下单独测试组件。

下面的代码片段提供了默认主题值 Luna。

const MyContext = React.createContext(defaultValue);
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

如何使用 contextType?

ContextType 用于使用上下文对象。contextType 属性有两种使用方式:

  1. contextType 作为类的属性:类的 contextType 属性可以赋值给 React.createContext() 创建的 Context 对象。之后,你可以在任何生命周期方法和渲染函数中使用 this.context 来获取该 Context 类型最接近的当前值。

让我们在 MyClass 上分配 contextType 属性,如下所示,

   class MyClass extends React.Component {
     componentDidMount() {
       let value = this.context;
       /* perform a side-effect at mount using the value of MyContext */
     }
     componentDidUpdate() {
       let value = this.context;
       /* ... */
     }
     componentWillUnmount() {
       let value = this.context;
       /* ... */
     }
     render() {
       let value = this.context;
       /* render something based on the value of MyContext */
     }
   }
   MyClass.contextType = MyContext;
Enter fullscreen mode Exit fullscreen mode
  1. 静态字段您可以使用静态类字段通过公共类字段语法来初始化您的 contextType。
   class MyClass extends React.Component {
     static contextType = MyContext;
     render() {
       let value = this.context;
       /* render something based on the value */
     }
   }
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

什么是消费者?

Consumer 是一个订阅上下文变化的 React 组件。它需要一个子函数作为子函数,该函数接收当前上下文值作为参数,并返回一个 React 节点。传递给该函数的 value 参数将等于树中距离此上下文最近的 Provider 的 value prop。

让我们举一个简单的例子,

<MyContext.Consumer>
  {value => /* render something based on the context value */}
</MyContext.Consumer>
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

在使用上下文时如何解决性能极端情况?

上下文使用参考标识来确定何时重新渲染,当提供商的父级重新渲染时,有些陷阱可能会触发消费者的无意渲染。

例如,下面的代码将在每次提供程序重新渲染时重新渲染所有消费者,因为总是为值创建一个新对象。

class App extends React.Component {
  render() {
    return (
      <Provider value={{ something: 'something' }}>
        <Toolbar />
      </Provider>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

这可以通过将值提升到父状态来解决,

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: { something: 'something' },
    };
  }

  render() {
    return (
      <Provider value={this.state.value}>
        <Toolbar />
      </Provider>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

HOC 中的 forward ref 的用途是什么?

Refs 不会被传递,因为 ref 不是 prop。React 的处理方式与key不同。如果将 ref 添加到 HOC,则 ref 将引用最外层的容器组件,而不是被包装的组件。在这种情况下,可以使用 Forward Ref API。例如,我们可以使用 React.forwardRef API 将 ref 显式转发到内部的 FancyButton 组件。

下面的 HOC 记录了所有的 props,

```javascript
function logProps(Component) {
  class LogProps extends React.Component {
    componentDidUpdate(prevProps) {
      console.log('old props:', prevProps);
      console.log('new props:', this.props);
    }

    render() {
      const {forwardedRef, ...rest} = this.props;

      // Assign the custom prop "forwardedRef" as a ref
      return <Component ref={forwardedRef} {...rest} />;
    }
  }

  return React.forwardRef((props, ref) => {
    return <LogProps {...props} forwardedRef={ref} />;
  });
}
```
Enter fullscreen mode Exit fullscreen mode

让我们使用这个 HOC 来记录传递给“花式按钮”组件的所有 props,

```javascript
class FancyButton extends React.Component {
  focus() {
    // ...
  }

  // ...
}
export default logProps(FancyButton);
```
Enter fullscreen mode Exit fullscreen mode

现在让我们创建一个 ref 并将其传递给 FancyButton 组件。这样,你就可以将焦点设置到按钮元素上了。

```javascript
import FancyButton from './FancyButton';

const ref = React.createRef();
ref.current.focus();
<FancyButton
  label="Click Me"
  handleClick={handleClick}
  ref={ref}
/>;
```
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

ref 参数是否适用于所有函数或类组件?

常规函数或类组件不会接收 ref 参数,并且 ref 在 props 中也不可用。第二个 ref 参数仅在使用 React.forwardRef 调用定义组件时才存在。

⬆ 返回顶部

为什么在使用前向引用时需要额外注意组件库?

当您开始在组件库中使用 forwardRef 时,应将其视为重大变更,并发布库的新主要版本。这是因为您的库可能具有不同的行为,例如将 ref 赋值给哪些对象以及导出哪些类型。这些更改可能会破坏依赖旧行为的应用和其他库。

⬆ 返回顶部

如何在没有 ES6 的情况下创建 React 类组件?

如果您不使用 ES6,则可能需要使用 create-react-class 模块。对于默认 props,您需要将 getDefaultProps() 定义为传入对象的函数。而对于初始状态,您必须提供一个单独的 getInitialState 方法来返回初始状态。

var Greeting = createReactClass({
  getDefaultProps: function () {
    return {
      name: 'Jhohn',
    };
  },
  getInitialState: function () {
    return { message: this.props.message };
  },
  handleClick: function () {
    console.log(this.state.message);
  },
  render: function () {
    return <h1>Hello, {this.props.name}</h1>;
  },
});
Enter fullscreen mode Exit fullscreen mode

注意:如果您使用 createReactClass,则自动绑定可用于所有方法。即,您不需要.bind(this)在事件处理程序的构造函数中使用。

⬆ 返回顶部

不使用 JSX 可以使用 React 吗?

是的,使用 React 时 JSX 并非必需。实际上,当你不想在构建环境中设置编译时,它很方便。每个 JSX 元素只是调用 的语法糖React.createElement(component, props, ...children)

例如,让我们用 JSX 来举一个问候语的例子,

class Greeting extends React.Component {
  render() {
    return <div>Hello {this.props.message}</div>;
  }
}

ReactDOM.render(<Greeting message="World" />, document.getElementById('root'));
Enter fullscreen mode Exit fullscreen mode

您可以像下面这样编写不使用 JSX 的代码,

class Greeting extends React.Component {
  render() {
    return React.createElement('div', null, `Hello ${this.props.message}`);
  }
}

ReactDOM.render(
  React.createElement(Greeting, { message: 'World' }, null),
  document.getElementById('root'),
);
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

什么是 diffing 算法?

React 需要使用算法来找出如何高效地更新 UI 以匹配最新的树。差异算法旨在生成将一棵树转换为另一棵树的最少操作数。然而,这些算法的复杂度约为 O(n3),其中 n 是树中元素的数量。

在这种情况下,显示 1000 个元素需要进行大约十亿次比较。这太昂贵了。因此,React 基于两个假设实现了启发式 O(n) 算法:

  1. 两种不同类型的元素将产生不同的树。
  2. 开发人员可以使用关键属性暗示哪些子元素可能在不同的渲染中保持稳定。

⬆ 返回顶部

差异算法涵盖哪些规则?

在比较两棵树的差异时,React 首先比较两个根元素。根据根元素的类型,其行为会有所不同。在协调算法中,它涵盖了以下规则:

  1. 不同类型的元素:当根元素的类型不同时,React 会拆除旧树并从头开始构建新树。例如,如果元素,或 从 到 的类型不同,则会导致完全重建。
  2. 相同类型的 DOM 元素:当比较两个相同类型的 React DOM 元素时,React 会比较两者的属性,保留相同的底层 DOM 节点,并仅更新更改的属性。让我们举一个除了 className 属性之外其他属性相同的 DOM 元素的例子:
<div className="show" title="ReactJS" />

<div className="hide" title="ReactJS" />
Enter fullscreen mode Exit fullscreen mode
  1. 相同类型的组件元素:当组件更新时,实例保持不变,因此状态在渲染过程中保持不变。React 会更新底层组件实例的 props 以匹配新元素,并在底层实例上调用 componentWillReceiveProps() 和 componentWillUpdate()。之后,会调用 render() 方法,diff 算法会针对先前的结果和新结果进行递归。
  2. 递归子节点:当对 DOM 节点的子节点进行递归时,React 会同时迭代两个子节点列表,并在出现差异时生成一个突变。例如,在子节点末尾添加一个元素时,在这两棵树之间进行转换效果很好。
<ul>
  <li>first</li>
  <li>second</li>
</ul>

<ul>
  <li>first</li>
  <li>second</li>
  <li>third</li>
</ul>

Enter fullscreen mode Exit fullscreen mode
  1. 处理键: React 支持 key 属性。当子节点拥有键时,React 会使用该键将原始树中的子节点与后续树中的子节点进行匹配。例如,添加键可以提高树的转换效率,
<ul>
  <li key="2015">Duke</li>
  <li key="2016">Villanova</li>
</ul>

<ul>
  <li key="2014">Connecticut</li>
  <li key="2015">Duke</li>
  <li key="2016">Villanova</li>
</ul>
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

什么时候需要使用 ref?

参考用例很少,

  1. 管理焦点、文本选择或媒体播放。
  2. 触发命令式动画。
  3. 与第三方 DOM 库集成。

⬆ 返回顶部

对于渲染 props,prop 是否必须命名为 render?

尽管该模式名为“render props”,但你不必使用名为 render 的 prop 来使用此模式。也就是说,任何组件用来判断需要渲染什么的函数 prop,从技术上来说都属于“render prop”。让我们以 children prop 为例,

<Mouse
  children={(mouse) => (
    <p>
      The mouse position is {mouse.x}, {mouse.y}
    </p>
  )}
/>
Enter fullscreen mode Exit fullscreen mode

实际上,children 属性不需要在 JSX 元素的“属性”列表中命名。相反,你可以直接将其放在元素内部,

<Mouse>
  {(mouse) => (
    <p>
      The mouse position is {mouse.x}, {mouse.y}
    </p>
  )}
</Mouse>
Enter fullscreen mode Exit fullscreen mode

在使用上述技术(没有任何名称)时,明确指出 children 应该是 propTypes 中的一个函数。

Mouse.propTypes = {
  children: PropTypes.func.isRequired,
};
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

使用纯组件的渲染道具有什么问题?

如果在 render 方法中创建一个函数,则会违背纯组件的初衷。因为浅层 prop 比较对于新的 props 总是会返回 false,而在这种情况下,每次渲染都会为 render props 生成一个新值。你可以通过将 render 函数定义为实例方法来解决这个问题。

⬆ 返回顶部

如何使用渲染道具创建 HOC?

你可以使用带有 render prop 的常规组件来实现大多数高阶组件 (HOC)。例如,如果你更喜欢 withMouse HOC 而不是组件,那么你可以轻松地使用带有 render prop 的常规组件来创建一个。

function withMouse(Component) {
  return class extends React.Component {
    render() {
      return <Mouse render={(mouse) => <Component {...this.props} mouse={mouse} />} />;
    }
  };
}
Enter fullscreen mode Exit fullscreen mode

通过这种方式,渲染道具可以灵活地使用任一模式。

⬆ 返回顶部

什么是开窗技术?

窗口化是一种在给定时间内仅渲染一小部分行的技术,可以显著减少重新渲染组件所需的时间以及创建的 DOM 节点数量。如果您的应用程序需要渲染长列表数据,则建议使用此技术。react-window 和 react-virtualized 都是流行的窗口化库,它们提供了一些可复用的组件来显示列表、网格和表格数据。

⬆ 返回顶部

如何在 JSX 中打印虚假值?

诸如 false、null、undefined 和 true 之类的虚假值是有效的子元素,但它们不会渲染任何内容。如果您仍然想显示它们,则需要将其转换为字符串。让我们举一个如何转换为字符串的例子,

<div>My JavaScript variable is {String(myVariable)}.</div>
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

门户的典型用例是什么?

当父组件具有溢出:隐藏或具有影响堆叠上下文(z-index、position、opacity 等样式)的属性并且您需要在视觉上“突破”其容器时,React 门户非常有用。

例如,对话框、全局消息通知、悬停卡和工具提示。

⬆ 返回顶部

如何为不受控制的组件设置默认值?

在 React 中,表单元素的 value 属性会覆盖 DOM 中的值。对于非受控组件,你可能希望 React 指定初始值,但后续更新不受控制。为了处理这种情况,你可以指定defaultValue属性来代替value 属性

render() {
  return (
    <form onSubmit={this.handleSubmit}>
      <label>
        User Name:
        <input
          defaultValue="John"
          type="text"
          ref={this.input} />
      </label>
      <input type="submit" value="Submit" />
    </form>
  );
}
Enter fullscreen mode Exit fullscreen mode

同样适用于selecttextArea输入。但是您需要输入使用defaultChecked 。checkboxradio

⬆ 返回顶部

你最喜欢的 React 堆栈是什么?

尽管不同开发者的技术栈各不相同,但 React Boilerplate 项目代码中使用的是最流行的技术栈。它主要使用 Redux 和 redux-saga 进行状态管理和异步副作用,使用 react-router 进行路由,使用 styled-components 进行 React 组件样式设置,使用 axios 调用 REST API,以及其他受支持的技术栈,例如 webpack、reselect、ESNext 和 Babel。您可以克隆项目https://github.com/react-boilerplate/react-boilerplate并开始开发任何新的 React 项目。

⬆ 返回顶部

真实 DOM 和虚拟 DOM 有什么区别?

以下是真实 DOM 和虚拟 DOM 之间的主要区别,

真实 DOM 虚拟 DOM
更新很慢 更新很快
DOM 操作非常昂贵。 DOM 操作非常简单
您可以直接更新 HTML。 你不能直接更新 HTML
造成过多的内存浪费 没有内存浪费
如果元素更新则创建一个新的 DOM 如果元素更新,它会更新 JSX

⬆ 返回顶部

如何将 Bootstrap 添加到 React 应用程序?

可以通过三种方式将 Bootstrap 添加到你的 React 应用中,

  1. 使用 Bootstrap CDN:这是添加 Bootstrap 最简单的方法。在 head 标签中添加 Bootstrap 的 CSS 和 JS 资源。
  2. Bootstrap 作为依赖项:如果您正在使用构建工具或模块捆绑器(例如 Webpack),那么这是将 Bootstrap 添加到 React 应用程序的首选选项
npm install bootstrap
Enter fullscreen mode Exit fullscreen mode
  1. React Bootstrap 包:在这种情况下,你可以使用一个已重建 Bootstrap 组件的包,将其添加到我们的 React 应用中,使其能够像 React 组件一样工作。以下是此类中比较流行的包:
  2. 反应引导
  3. 反应带

⬆ 返回顶部

你能列出使用 React 作为前端框架的顶级网站或应用程序吗?

以下是top 10 websites使用 React 作为前端框架的,

  1. Facebook
  2. 优步
  3. Instagram
  4. WhatsApp
  5. 可汗学院
  6. Airbnb
  7. Dropbox
  8. Flipboard
  9. Netflix
  10. PayPal

⬆ 返回顶部

建议在 React 中使用 CSS In JS 技术吗?

React 对于样式的定义方式没有任何意见,但如果你是初学者,那么一个好的起点是像往常一样在单独的 *.css 文件中定义样式,并使用 className 引用它们。此功能并非 React 的一部分,而是来自第三方库。但如果你想尝试不同的方法(CSS-In-JS),那么 styled-components 库是一个不错的选择。

⬆ 返回顶部

我是否需要用钩子重写所有类组件?

不。但是你可以在一些组件(或新组件)中尝试使用 Hook,而无需重写任何现有代码。因为 ReactJS 中没有移除类的计划。

⬆ 返回顶部

如何使用 React Hooks 获取数据?

调用的效果钩子useEffect用于通过 axios 从 API 中获取数据,并使用状态钩子的更新功能将数据设置到组件的本地状态中。

让我们举一个例子,它从 API 中获取 React 文章列表

import React, { useState, useEffect } from 'react';
import axios from 'axios';

function App() {
  const [data, setData] = useState({ hits: [] });

  useEffect(async () => {
    const result = await axios('http://hn.algolia.com/api/v1/search?query=react');

    setData(result.data);
  }, []);

  return (
    <ul>
      {data.hits.map((item) => (
        <li key={item.objectID}>
          <a href={item.url}>{item.title}</a>
        </li>
      ))}
    </ul>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

请记住,我们为效果钩子提供了一个空数组作为第二个参数,以避免在组件更新时激活它,而仅用于组件的安装。即,它仅为组件安装而获取。

⬆ 返回顶部

Hooks 是否涵盖了类的所有用例?

Hooks 并未涵盖所有类的用例,但我们计划很快添加它们。目前,尚无与不常用的getSnapshotBeforeUpdatecomponentDidCatch生命周期等效的 Hook 实现。

⬆ 返回顶部

钩子支持的稳定版本是什么?

React 在 16.8 版本中为以下软件包提供了 React Hooks 的稳定实现

  1. React DOM
  2. React DOM 服务器
  3. React 测试渲染器
  4. React 浅渲染器

⬆ 返回顶部

为什么我们在中使用数组解构(方括号符号)useState

当我们用 声明一个状态变量时useState,它会返回一个包含两个元素的数组,即一个 pair 。第一个元素是当前值,第二个元素是更新该值的函数。使用 [0] 和 [1] 来访问它们有点令人困惑,因为它们有特定的含义。这就是为什么我们使用数组解构来代替。

例如,数组索引访问如下所示:

var userStateVariable = useState('userProfile'); // Returns an array pair
var user = userStateVariable[0]; // Access first item
var setUser = userStateVariable[1]; // Access second item
Enter fullscreen mode Exit fullscreen mode

而通过数组解构,可以按如下方式访问变量:

const [user, setUser] = useState('userProfile');
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

引入钩子的来源有哪些?

Hooks 的灵感来源于多个不同的来源。以下是其中一些:

  1. 之前在 react-future 仓库中使用函数式 API 进行的实验
  2. 社区对 Reactions 组件等渲染属性 API 进行了实验
  3. DisplayScript 中的状态变量和状态单元。
  4. Rx 中的订阅。
  5. ReasonReact 中的 Reducer 组件。

⬆ 返回顶部

如何访问 Web 组件的命令式 API?

Web 组件通常会公开命令式 API 来实现其功能。如果您想访问 Web 组件的命令式 API,则需要使用ref直接与 DOM 节点交互。但是,如果您使用的是第三方 Web 组件,那么最好的解决方案是编写一个 React 组件,将其作为Web 组件的包装器。

⬆ 返回顶部

什么是 formik?

Formik 是一个小型的 React 表单库,可以帮你解决三大问题,

  1. 获取表单状态中的值和从表单状态中获取值
  2. 验证和错误消息
  3. 处理表单提交

⬆ 返回顶部

在 Redux 中处理异步调用的典型中间件选择有哪些?

Redux 生态系统中用于处理异步调用的一些流行中间件选择是Redux Thunk, Redux Promise, Redux Saga

⬆ 返回顶部

浏览器能理解 JSX 代码吗?

不,浏览器无法理解 JSX 代码。你需要一个转译器将 JSX 代码转换为浏览器可以理解的常规 JavaScript 代码。目前使用最广泛的转译器是 Babel。

⬆ 返回顶部

描述一下 React 中的数据流?

React 使用 props 实现单向响应数据流,这减少了样板并且比传统的双向数据绑定更容易理解。

⬆ 返回顶部

什么是反应脚本?

react-scripts软件包是 create-react-app 入门包中的一组脚本,可帮助您无需配置即可启动项目。该react-scripts start命令设置开发环境并启动服务器,以及热模块重新加载。

⬆ 返回顶部

create react app 有哪些功能?

以下是 create react app 提供的一些功能的列表。

  1. React、JSX、ES6、Typescript 和 Flow 语法支持。
  2. 自动添加前缀的 CSS
  3. CSS 重置/标准化
  4. 实时开发服务器
  5. 一个快速交互式单元测试运行器,内置覆盖率报告支持
  6. 一个用于捆绑 JS、CSS 和图像以供生产的构建脚本,其中包含哈希和源映射
  7. 离线优先服务工作者和 Web 应用程序清单,满足所有渐进式 Web 应用程序标准。

⬆ 返回顶部

renderToNodeStream 方法的目的是什么?

ReactDOMServer#renderToNodeStream方法用于在服务器上生成 HTML,并在初始请求时将标记发送至服务器,以加快页面加载速度。它还能帮助搜索引擎轻松抓取您的页面,从而实现 SEO 目标。注意:请记住,此方法仅在服务器端可用,在浏览器中不可用。

⬆ 返回顶部

什么是 MobX?

MobX 是一个简单、可扩展且久经考验的状态管理解决方案,适用于函数式响应式编程 (TFRP)。对于 ReactJS 应用程序,你需要安装以下软件包:

npm install mobx --save
npm install mobx-react --save
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

Redux 和 MobX 之间有什么区别?

以下是 Redux 和 MobX 之间的主要区别,

话题 Redux MobX
定义 它是一个用于管理应用程序状态的 JavaScript 库 它是一个用于被动管理应用程序状态的库
编程 它主要用 ES6 编写 它是用 JavaScript(ES5)编写的
数据存储 只有一个大型存储用于数据存储 有多个商店可供存储
用法 主要用于大型复杂的应用 用于简单的应用程序
表现 需要改进 提供更好的性能
如何存储 使用 JS 对象来存储 使用可观察对象来存储数据

⬆ 返回顶部

在学习 ReactJS 之前我应该​​学习 ES6 吗?

不,你不必学习 ES2015/ES6 来学习 React。但你可能会发现许多资源或 React 生态系统广泛使用 ES6。让我们来看看一些常用的 ES6 特性,

  1. 解构:获取 props 并在组件中使用它们
   // in es 5
   var someData = this.props.someData;
   var dispatch = this.props.dispatch;

   // in es6
   const { someData, dispatch } = this.props;
Enter fullscreen mode Exit fullscreen mode
  1. 扩展运算符:帮助将 props 传递到组件中
   // in es 5
   <SomeComponent someData={this.props.someData} dispatch={this.props.dispatch} />

   // in es6
   <SomeComponent {...this.props} />
Enter fullscreen mode Exit fullscreen mode
  1. 箭头函数:语法紧凑
   // es 5
   var users = usersList.map(function (user) {
     return <li>{user.name}</li>;
   });
   // es 6
   const users = usersList.map((user) => <li>{user.name}</li>);
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

什么是并发渲染?

并发渲染功能可在不阻塞主 UI 线程的情况下渲染组件树,从而提高 React 应用的响应速度。它允许 React 中断长时间运行的渲染以处理高优先级事件。也就是说,启用并发模式后,React 会密切关注其他需要完成的任务,如果有更高优先级的任务,它会暂停当前正在渲染的任务,并让其他任务优先完成。您可以通过两种方式启用此功能:

// 1. Part of an app by wrapping with ConcurrentMode
<React.unstable_ConcurrentMode>
  <Something />
</React.unstable_ConcurrentMode>;

// 2. Whole app using createRoot
ReactDOM.unstable_createRoot(domNode).render(<App />);
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

异步模式和并发模式有什么区别?

两者指的是同一件事。之前,React 团队将并发模式称为“异步模式”。现在更名是为了突出 React 能够以不同的优先级执行任务的能力。这样可以避免与其他异步渲染方法混淆。

⬆ 返回顶部

我可以在 react16.9 中使用 javascript url 吗?

是的,您可以使用 javascript: URL,但它会在控制台中记录警告。因为以 javascript: 开头的 URL 很危险,因为它们会在类似这样的标签中包含未经过滤的输出,<a href>从而造成安全漏洞。

const companyProfile = {
  website: "javascript: alert('Your website is hacked')",
};
// It will log a warning
<a href={companyProfile.website}>More details</a>;
Enter fullscreen mode Exit fullscreen mode

请记住,未来的版本将会引发 javascript URL 错误。

⬆ 返回顶部

eslint 插件的 hooks 用途是什么?

ESLint 插件强制执行 Hook 规则以避免 bug。它假定任何以 ”use” 开头且紧跟其后的大写字母的函数都是 Hook。具体来说,该规则强制执行:

  1. 对 Hooks 的调用要么在 PascalCase 函数(假定为组件)内,要么在另一个 useSomething 函数(假定为自定义 Hook)内。
  2. 每次渲染时都会按照相同的顺序调用钩子。

⬆ 返回顶部

React 中的命令式和声明式有什么区别?

想象一下一个简单的 UI 组件,比如一个“赞”按钮。当你点击它时,如果它之前是灰色的,它会变成蓝色;如果它之前是蓝色的,它会变成灰色。

执行此操作的必要方式是:

if (user.likes()) {
  if (hasBlue()) {
    removeBlue();
    addGrey();
  } else {
    removeGrey();
    addBlue();
  }
}
Enter fullscreen mode Exit fullscreen mode

基本上,你必须检查屏幕上当前的内容,并处理所有必要的更改,以便根据当前状态重新绘制,包括撤消先前状态的更改。你可以想象这在实际场景中会多么复杂。

相反,声明式方法将是:

if (this.state.liked) {
  return <blueLike />;
} else {
  return <greyLike />;
}
Enter fullscreen mode Exit fullscreen mode

因为声明式方法分离了关注点,所以这部分只需要处理 UI 在特定状态下的外观,因此更容易理解。

⬆ 返回顶部

使用 typescript 和 reactjs 有什么好处?

以下是在 React.js 中使用 TypeScript 的一些好处,

  1. 可以使用最新的 JavaScript 功能
  2. 使用接口进行复杂类型定义
  3. VS Code 等 IDE 是为 TypeScript 开发的
  4. 通过易读性和验证来避免错误

⬆ 返回顶部

使用 Context API 状态管理时,如何确保用户在页面刷新时仍保持身份验证?

当用户登录并重新加载时,为了保持状态,我们通常会在主 App.js 的 useEffect 钩子中添加加载用户操作。使用 Redux 时,可以轻松访问 loadUser 操作。

App.js

import { loadUser } from '../actions/auth';
store.dispatch(loadUser());
Enter fullscreen mode Exit fullscreen mode
  • 但是,在使用Context API访问 App.js 中的上下文时,需要将 AuthState 包装在 index.js 中,以便 App.js 可以访问身份验证上下文。现在,无论何时页面重新加载,无论您在哪个路由上,用户都将通过身份验证,因为每次重新渲染时都会触发loadUser操作。

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import AuthState from './context/auth/AuthState';

ReactDOM.render(
  <React.StrictMode>
    <AuthState>
      <App />
    </AuthState>
  </React.StrictMode>,
  document.getElementById('root'),
);
Enter fullscreen mode Exit fullscreen mode

App.js

const authContext = useContext(AuthContext);

const { loadUser } = authContext;

useEffect(() => {
  loadUser();
}, []);
Enter fullscreen mode Exit fullscreen mode

加载用户

const loadUser = async () => {
  const token = sessionStorage.getItem('token');

  if (!token) {
    dispatch({
      type: ERROR,
    });
  }
  setAuthToken(token);

  try {
    const res = await axios('/api/auth');

    dispatch({
      type: USER_LOADED,
      payload: res.data.data,
    });
  } catch (err) {
    console.error(err);
  }
};
Enter fullscreen mode Exit fullscreen mode

⬆ 返回顶部

新的 JSX 转换有哪些好处?

新的 JSX 转换有三大好处,

  1. 无需导入 React 包即可使用 JSX
  2. 编译后的输出可能会稍微改善包的大小
  3. 未来的改进提供了灵活性,可以减少学习 React 的概念数量。

新的 JSX 转换与旧的转换有何不同?

新的 JSX 转换不需要 React 在范围内。即,您不需要为简单的场景导入 React 包。

让我们举个例子来看看新旧变换之间的主要区别,

旧变换:

import React from 'react';

function App() {
  return <h1>Good morning!!</h1>;
}
Enter fullscreen mode Exit fullscreen mode

现在 JSX 转换将上述代码转换为常规 JavaScript,如下所示,

import React from 'react';

function App() {
  return React.createElement('h1', null, 'Good morning!!');
}
Enter fullscreen mode Exit fullscreen mode

新变换:

新的 JSX 转换不需要任何 React 导入

function App() {
  return <h1>Good morning!!</h1>;
}
Enter fullscreen mode Exit fullscreen mode

JSX 转换在底层编译为以下代码

import { jsx as _jsx } from 'react/jsx-runtime';

function App() {
  return _jsx('h1', { children: 'Good morning!!' });
}
Enter fullscreen mode Exit fullscreen mode

注意:您仍然需要导入 React 才能使用 Hooks。

文章来源:https://dev.to/sakhnyuk/300-react-interview-questions-2ko4
PREV
JS 数组速查表
NEXT
如何在 2020 年创建博客并提升浏览量(0 - 8 万)