本文原载于SegmentFault专栏"终身学习者"
翻译自 Learn Enough React For The Interview
翻译:前端小智
整理编辑:SegmentFault
React是流行的javascript框架之一,在2019年及以后将会更加流行。React于2013年首次发布,多年来广受欢迎。它是一个声明性的、基于组件的、用于构建用户界面的高效javascript库。
以下是面试前必须了解的话题,
今天我们为大家分享其中的下半部分——
什么是声明式编程
声明式编程 vs 命令式编程
什么是函数式编程
什么是组件设计模式
React 是什么
React 和 Angular 有什么不同
什么是虚拟DOM及其工作原理
什么是JSX
组件和不同类型
Props 和 State
什么是 PropTypes
如何更新状态和不更新状态
组件生命周期方法
超越继承的组合
如何在React中应用样式
什么是Redux及其工作原理
什么是React路由器及其工作原理
什么是错误边界
什么是 Fragments
什么是传送门(Portals)
什么是 Context
什么是 Hooks
如何提高性能
如何在重新加载页面时保留数据
如何从React中调用API
总结
相关阅读:
应对React面试前,必须要了解的25个话题(上)
超越继承的组合
在React中,我们总是使用组合而不是继承。我们已经在函数式编程部分讨论了什么是组合。这是一种结合简单的可重用函数来生成高阶组件的技术。下面是一个组合的例子,我们在 dashboard 组件中使用两个小组件
todoForm
和
todoList
。
import React from 'react' ;
import '../App.css' ;
import { ToDoForm } from './todoform' ;
import { ToDolist } from './todolist' ;
export class Dashboard extends React .Component {
render() {
return (
<div className ="dashboard" >
<ToDoForm />
<ToDolist />
div >
);
}
}
如何在React中应用样式
将样式应用于React组件有三种方法。
外部样式表
在此方法中,你可以将外部样式表导入到组件使用类中。 但是你应该使用
className
而不是
class
来为React元素应用样式, 这里有一个例子。
import React from 'react' ;
import './App.css' ;
import { Header } from './header/header' ;
import { Footer } from './footer/footer' ;
import { Dashboard } from './dashboard/dashboard' ;
import { UserDisplay } from './userdisplay' ;
function App ( ) {
return (
<div className ="App" >
<Header />
<Dashboard />
<UserDisplay />
<Footer />
div >
);
}
export default App;
内联样式
在这个方法中,我们可以直接将
props
传递给HTML元素,属性为
style
。这里有一个例子。这里需要注意的重要一点是,我们将javascript对象传递给style,这就是为什么我们使用
backgroundColor
而不是CSS方法
backbackground -color
。
import React from 'react' ;
export const Header = () => {
const heading = 'TODO App'
return (
<div style ={{backgroundColor: 'orange '}}>
<h1
> {heading}h1 >
div >
)
}
定义样式对象并使用它
因为我们将javascript对象传递给
style
属性,所以我们可以在组件中定义一个
style
对象并使用它。下面是一个示例,你也可以将此对象作为
props
传递到组件树中。
import React from 'react' ;
const footerStyle = {
width : '100%' ,
backgroundColor : 'green' ,
padding : '50px' ,
font : '30px' ,
color : 'white' ,
fontWeight : 'bold'
}
export const Footer = () => {
return (
<div style ={footerStyle} >
All Rights Reserved 2019
div >
)
}
什么是Redux及其工作原理
Redux 是 React的一个状态管理库,它基于flux。 Redux简化了React中的单向数据流。 Redux将状态管理完全从React中抽象出来。
它是如何工作的
在React中,组件连接到 redux ,如果要访问 redux,需要派出一个包含
id
和负载(payload) 的
action
。action 中的
payload
是可选的,action 将其转发给 Reducer。
当
reducer
收到
action
时,通过
swithc...case
语法比较
action
中
type
。 匹配时,更新对应的内容返回新的
state
。
当
Redux
状态更改时,连接到
Redux
的组件将接收新的状态作为
props
。当组件接收到这些
props
时,它将进入更新阶段并重新渲染 UI。
Redux 循环细节
让我们详细看看整个redux 循环细节。
Action
: Action 只是一个简单的json对象,
type
和有
payload
作为键。
type
是必须要有的,
payload
是可选的。下面是一个 action 的例子。
// action
{
type :"SEND_EMAIL" ,
payload: data
};
Action Creators
:这些是创建
Actions
的函数,因此我们在派发
action
时不必在组件中手动编写每个
action
。 以下是 action creator 的示例。
// action creator
export function sendEamil (data ) {
return { type :"SEND_EMAIL" , payload : data};
}
Reducers
:Reducers 是纯函数,它将
action
和当前
state
作为参数,计算必要的逻辑并返回一个新r的
state
。 这些 Reducers 没有任何副作用。 它不会改变
state
而是总是返回
state
。
export default function emailReducer (state = [], action ) {
switch (action.type) {
case "SEND_EMAIL" : return Object .assign({}, state, {
email : action.payload
});
default : return state;
}
}
组件如何与
redux
进行连接
mapStateToProps
:此函数将
state
映射到
props
上,因此只要
state
发生变化,新 state 会重新映射到
props
。 这是订阅
store
的方式。
mapDispatchToProps
:此函数用于将
action creators
绑定到你的
props
。以便我们可以在第
12
行中使用This .
props.actions.sendemail()
来派发一个动作。
connect
和
bindActionCreators
来自 redux。 前者用于连接 store ,如第22行,后者用于将 action creators 绑定到你的
props
,如第20行。
// import connect
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
// import action creators
import * as userActions from '../../../actions/userActions' ;
export class User extends React .Component {
handleSubmit() {
this .props.actions.sendEmail(this .state.email);
}
}
// you are mapping you state props
const mapStateToProps = (state, ownProps ) => ({user : state.user})
// you are binding your action creators to your props
const mapDispatchToProps = (dispatch ) => ({actions : bindActionCreators(userActions, dispatch)})
export default connect(mapStateToProps, mapDispatchToProps)(User);
什么是 React Router Dom 及其工作原理
react-router-dom
是应用程序中路由的库。 React库中没有路由功能,需要单独安装
react-router-dom
。
react-router-dom 提供两个路由器
BrowserRouter
和
HashRoauter
。前者基于rul的pathname段,后者基于hash段。
react-router-dom 组件
BrowserRouter
和
HashRouter
是路由器。
Route
用于路由匹配。
Link
组件用于在应用程序中创建链接。 它将在HTML中渲染为锚标记。
NavLink
是突出显示当前活动链接的特殊链接。
Switch
不是必需的,但在组合路由时很有用。
Redirect
用于强制路由重定向
下面是组件中的
Link
、
NavLink
和
Redirect
的例子
// normal link
"/gotoA" >Home
// link which highlights currentlu active route with the given class name
"/gotoB" activeClassName="active" >
React
// you can redirect to this url
"/gotoC" />
以下是 react router 组件的示例。 如果你查看下面的示例,我们将匹配路径并使用
Switch
和
Route
呈现相应的组件。
import React from 'react'
// import react router DOM elements
import { Switch, Route, Redirect } from 'react-router-dom'
import ComponentA from '../common/compa'
import ComponentB from '../common/compb'
import ComponentC from '../common/compc'
import ComponentD from '../common/compd'
import ComponentE from '../common/compe'
const Layout = ({ match } ) => {
return (
)}
export default Layout
什么是错误边界
在 React 中,我们通常有一个组件树。如果任何一个组件发生错误,它将破坏整个组件树。没有办法捕捉这些错误,我们可以用错误边界优雅地处理这些错误。
错误边界有两个作用
下面是
ErrorBoundary
类的一个例子。如果类实现了
getDerivedStateFromError
或
componentDidCatch
这两个生命周期方法的任何一下,,那么这个类就会成为
ErrorBoundary
。前者返回
{hasError: true}
来呈现回退UI,后者用于记录错误。
import React from 'react'
export class ErrorBoundary extends React .Component {
constructor (props) {
super (props);
this .state = { hasError : false };
}
static getDerivedStateFromError(error) {
return { hasError : true };
}
componentDidCatch(error, info) {
console .log('Error::::' , error);
}
render() {
if (this .state.hasError) {
return <h1 > OOPS!. WE ARE LOOKING INTO IT.h1 > ;
}
return this .props.children;
}
}
以下是我们如何在其中一个组件中使用ErrorBoundary。使用ErrorBoundary类包裹
ToDoForm
和
ToDoList
。 如果这些组件中发生任何错误,我们会记录错误并显示回退UI。
import React from 'react' ;
import '../App.css' ;
import { ToDoForm } from './todoform' ;
import { ToDolist } from './todolist' ;
import { ErrorBoundary } from '../errorboundary' ;
export class Dashboard extends React .Component {
render() {
return (
<div className ="dashboard" >
<ErrorBoundary >
<ToDoForm />
<ToDolist />
ErrorBoundary >
div >
);
}
}
什么是 Fragments
在React中,我们需要有一个父元素,同时从组件返回React元素。有时在DOM中添加额外的节点会很烦人。使用
Fragments
,我们不需要在DOM中添加额外的节点。我们只需要用
React.Fragment
或才简写
<>
来包裹内容就行了。如下 所示:
return (
<div >
<CompoentA />
<CompoentB />
<CompoentC />
div >
)
// With Fragments
return (
<React.Fragment >
<CompoentA />
<CompoentB />
<CompoentC />
React.Fragment >
)
// shorthand notation Fragments
return (
<>
<CompoentA />
<CompoentB />
<CompoentC />
>
)
什么是传送门(Portals)
默认情况下,所有子组件都在UI上呈现,具体取决于组件层次结构。Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案。
这里有一个例子。默认情况下,父组件在DOM层次结构中有子组件。
我们可以将
children
组件移出
parent
组件并将其附加
id
为
someid
的 Dom 节点下。
首先,获取 id 为 someid,我们在constrcutorand中创建一个元素div,将child附加到componentDidMount中的someRoot。 最后,我们在ReactDOM.createPortal(this.props.childen),domnode的帮助下将子节点传递给该特定DOM节点。
首先,先获取 id 为
someid
DOM元素,接着在构造函数中创建一个元素div,在
componentDidMount
方法中将
someRoot
放到 div 中 。 最后,通过
ReactDOM.createPortal(this.props.childen), domnode)
将
children
传递到对应的节点下。
const someRoot = document.getElementById('someid' );
class Modal extends React .Component {
constructor (props) {
super (props);
this .el = document.createElement('div' );
}
componentDidMount() {
someRoot.appendChild(this .el);
}
componentWillUnmount() {
someRoot.removeChild(this .el);
}
render() {
return ReactDOM.createPortal(
this .props.children,
this .el,
);
}
}
什么是上下文
有时我们必须将
props
传递给组件树,即使所有中间组件都不需要这些
props
。上下文是一种传递
props
的方法,而不用在每一层传递组件树。
什么是 Hooks
Hooks 是React版本16.8中的新功能。 请记住,我们不能在函数组件中使用
state
,因为它们不是类组件。
Hooks 让我们在函数组件中可以使用
state
和其他功能。