怎么用 React.createElement 重写上面的代码
Question:
const element = (
<h1 className="greeting">
Hello, rdhub.cn!
</h1>
);
Answer:
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, rdhub.cn!'
);
对 React-Intl 的了解,它的工作原理?
React-intl 是雅虎的语言国际化开源我的项目 FormatJS 的一部分,通过其提供的组件和 API 能够与 ReactJS 绑定。
React-intl 提供了两种应用办法,一种是援用 React 组件,另一种是间接调取 API,官网更加举荐在 React 我的项目中应用前者,只有在无奈应用 React 组件的中央,才应该调用框架提供的 API。它提供了一系列的 React 组件,包含数字格式化、字符串格式化、日期格式化等。
在 React-intl 中,能够配置不同的语言包,他的工作原理就是依据须要,在语言包之间进行切换。
react 有什么特点
- react 应用过的虚构 DOM,而不是实在 DOM
- react 能够用服务器渲染
- react 遵循单向数据流 或者数据绑定
React 中的 key 是什么?为什么它们很重要?
key 能够帮忙 React 跟踪循环创立列表中的虚构 DOM 元素,理解哪些元素已更改、增加或删除。
每个绑定 key 的虚构 DOM 元素,在兄弟元素之间都是举世无双的。在 React 的和解过程中,比拟新的虛拟 DOM 树与上一个虛拟 DOM 树之间的差别,并映射到页面中。key 使 React 解决列表中虛拟 DOM 时更加高效,因为 React 能够应用虛拟 DOM 上的 key 属性,疾速理解元素是新的、须要删除的,还是批改过的。如果没有 key,Rεat 就不晓得列表中虚构 DOM 元素与页面中的哪个元素绝对应。所以在创立列表的时候,不要疏忽 key。
为什么 React 要用 JSX?
JSX 是一个 JavaScript 的语法扩大,或者说是一个相似于 XML 的 ECMAScript 语法扩大。它自身没有太多的语法定义,也不冀望引入更多的规范。
其实 React 自身并不强制应用 JSX。在没有 JSX 的时候,React 实现一个组件依赖于应用 React.createElement 函数。代码如下:
class Hello extends React.Component {render() {
return React.createElement(
'div',
null,
`Hello ${this.props.toWhat}`
);
}
}
ReactDOM.render(React.createElement(Hello, {toWhat: 'World'}, null),
document.getElementById('root')
);
而 JSX 更像是一种语法糖,通过相似 XML 的形容形式,刻画函数对象。在采纳 JSX 之后,这段代码会这样写:
class Hello extends React.Component {render() {return <div>Hello {this.props.toWhat}</div>;
}
}
ReactDOM.render(
<Hello toWhat="World" />,
document.getElementById('root')
);
通过比照,能够清晰地发现,代码变得更为简洁,而且代码构造档次更为清晰。
因为 React 须要将组件转化为虚构 DOM 树,所以在编写代码时,实际上是在手写一棵构造树。而XML 在树结构的形容上天生具备可读性强的劣势。
但这样可读性强的代码仅仅是给写程序的同学看的,实际上在运行的时候,会应用 Babel 插件将 JSX 语法的代码还原为 React.createElement 的代码。
总结: JSX 是一个 JavaScript 的语法扩大,构造相似 XML。JSX 次要用于申明 React 元素,但 React 中并不强制应用 JSX。即便应用了 JSX,也会在构建过程中,通过 Babel 插件编译为 React.createElement。所以 JSX 更像是 React.createElement 的一种语法糖。
React 团队并不想引入 JavaScript 自身以外的开发体系。而是心愿通过正当的关注点拆散放弃组件开发的纯正性。
React-Router 如何获取 URL 的参数和历史对象?
(1)获取 URL 的参数
- get 传值
路由配置还是一般的配置,如:'admin'
,传参形式如:'admin?id='1111''
。通过 this.props.location.search
获取 url 获取到一个字符串'?id='1111'
能够用 url,qs,querystring,浏览器提供的 api URLSearchParams 对象或者本人封装的办法去解析出 id 的值。
- 动静路由传值
路由须要配置成动静路由:如 path='/admin/:id'
,传参形式,如'admin/111'
。通过this.props.match.params.id
获得 url 中的动静路由 id 局部的值,除此之外还能够通过useParams(Hooks)
来获取
- 通过 query 或 state 传值
传参形式如:在 Link 组件的 to 属性中能够传递对象 {pathname:'/admin',query:'111',state:'111'};
。通过this.props.location.state
或this.props.location.query
来获取即可,传递的参数能够是对象、数组等,然而存在毛病就是只有刷新页面,参数就会失落。
(2)获取历史对象
- 如果 React >= 16.8 时能够应用 React Router 中提供的 Hooks
import {useHistory} from "react-router-dom";
let history = useHistory();
2. 应用 this.props.history 获取历史对象
let history = this.props.history;
ref 是一个函数又有什么益处?
- 不便 react 销毁组件、从新渲染的时候去清空 refs 的货色,避免内存泄露
如何配置 React-Router 实现路由切换
(1)应用<Route>
组件
路由匹配是通过比拟 <Route>
的 path 属性和以后地址的 pathname 来实现的。当一个 <Route>
匹配胜利时,它将渲染其内容,当它不匹配时就会渲染 null。没有门路的 <Route>
将始终被匹配。
// when location = {pathname: '/about'}
<Route path='/about' component={About}/> // renders <About/>
<Route path='/contact' component={Contact}/> // renders null
<Route component={Always}/> // renders <Always/>
(2)联合应用 <Switch>
组件和 <Route>
组件
<Switch>
用于将 <Route>
分组。
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/contact" component={Contact} />
</Switch>
<Switch>
不是分组 <Route>
所必须的,但他通常很有用。一个 <Switch>
会遍历其所有的子 <Route>
元素,并仅渲染与以后地址匹配的第一个元素。
(3)应用 <Link>、<NavLink>、<Redirect>
组件
<Link>
组件来在你的应用程序中创立链接。无论你在何处渲染一个<Link>
,都会在应用程序的 HTML 中渲染锚(<a>
)。
<Link to="/">Home</Link>
// <a href='/'>Home</a>
是一种非凡类型的 当它的 to 属性与以后地址匹配时,能够将其定义为 ” 沉闷的 ”。
// location = {pathname: '/react'}
<NavLink to="/react" activeClassName="hurray">
React
</NavLink>
// <a href='/react' className='hurray'>React</a>
当咱们想强制导航时,能够渲染一个 <Redirect>
,当一个<Redirect>
渲染时,它将应用它的 to 属性进行定向。
在哪个生命周期中你会收回 Ajax 申请?为什么?
Ajax 申请应该写在组件创立期的第五个阶段,即 componentDidMount 生命周期办法中。起因如下。
在创立期的其余阶段,组件尚未渲染实现。而在存在期的 5 个阶段,又不能确保生命周期办法肯定会执行(如通过 shouldComponentUpdate 办法优化更新等)。在销毀期,组件行将被销毁,申请数据变得无意义。因而在这些阶段发岀 Ajax 申请显然不是最好的抉择。
在组件尚未挂载之前,Ajax 申请将无奈执行结束,如果此时发出请求,将意味着在组件挂载之前更新状态(如执行 setState),这通常是不起作用的。
在 componentDidMount 办法中,执行 Ajax 即可保障组件曾经挂载,并且可能失常更新组件。
参考:前端 react 面试题具体解答
react 和 vue 的区别
相同点:
- 数据驱动页面,提供响应式的试图组件
- 都有 virtual DOM, 组件化的开发,通过 props 参数进行父子之间组件传递数据,都实现了 webComponents 标准
- 数据流动单向,都反对服务器的渲染 SSR
- 都有反对 native 的办法,react 有 React native,vue 有 wexx
不同点:
- 数据绑定:Vue 实现了双向的数据绑定,react 数据流动是单向的
- 数据渲染:大规模的数据渲染,react 更快
- 应用场景:React 配合 Redux 架构适宜大规模多人合作简单我的项目,Vue 适宜小快的我的项目
- 开发格调:react 举荐做法 jsx + inline style 把 html 和 css 都写在 js 了
vue 是采纳 webpack +vue-loader 单文件组件格局,html, js, css 同一个文件
如何通知 React 它应该编译生产环境版
通常状况下咱们会应用
Webpack
的DefinePlugin
办法来将NODE_ENV
变量值设置为production
。编译版本中React
会疏忽propType
验证以及其余的告警信息,同时还会升高代码库的大小,React
应用了Uglify
插件来移除生产环境下不必要的正文等信息
在 Reducer 文件里,对于返回的后果,要留神哪些问题?
在 Reducer 文件里,对于返回的后果,必须要应用 Object.assign ()来复制一份新的 state,否则页面不会跟着数据刷新。
return Object.assign({}, state, {
type: action.type,
shouldNotPaint: true,
});
React-Router 4 的 Switch 有什么用?
Switch 通常被用来包裹 Route,用于渲染与门路匹配的第一个子 <Route>
或 <Redirect>
,它外面不能放其余元素。
如果不加 <Switch>
:
import {Route} from 'react-router-dom'
<Route path="/" component={Home}></Route>
<Route path="/login" component={Login}></Route>
Route 组件的 path 属性用于匹配门路,因为须要匹配 /
到 Home
,匹配 /login
到 Login
,所以须要两个 Route,然而不能这么写。这样写的话,当 URL 的 path 为“/login”时,<Route path="/" />
和<Route path="/login" />
都会被匹配,因而页面会展现 Home 和 Login 两个组件。这时就须要借助 <Switch>
来做到只显示一个匹配组件:
import {Switch, Route} from 'react-router-dom'
<Switch>
<Route path="/" component={Home}></Route>
<Route path="/login" component={Login}></Route>
</Switch>
此时,再拜访“/login”门路时,却只显示了 Home 组件。这是就用到了 exact 属性,它的作用就是准确匹配门路,常常与<Switch>
联结应用。只有当 URL 和该 <Route>
的 path 属性完全一致的状况下能力匹配上:
import {Switch, Route} from 'react-router-dom'
<Switch>
<Route exact path="/" component={Home}></Route>
<Route exact path="/login" component={Login}></Route>
</Switch>
在生命周期中的哪一步你应该发动 AJAX 申请
咱们该当将 AJAX 申请放到
componentDidMount
函数中执行,次要起因有下
React
下一代和谐算法Fiber
会通过开始或进行渲染的形式优化利用性能,其会影响到componentWillMount
的触发次数。对于componentWillMount
这个生命周期函数的调用次数会变得不确定,React
可能会屡次频繁调用componentWillMount
。如果咱们将AJAX
申请放到componentWillMount
函数中,那么不言而喻其会被触发屡次,天然也就不是好的抉择。- 如果咱们将
AJAX
申请搁置在生命周期的其余函数中,咱们并不能保障申请仅在组件挂载结束后才会要求响应。如果咱们的数据申请在组件挂载之前就实现,并且调用了setState
函数将数据增加到组件状态中,对于未挂载的组件则会报错。而在componentDidMount
函数中进行AJAX
申请则能无效防止这个问题
何为 JSX
JSX 是 JavaScript 语法的一种语法扩大,并领有 JavaScript 的全副性能。JSX 生产 React “ 元素 ”,你能够将任何的 JavaScript 表达式封装在花括号里,而后将其嵌入到 JSX 中。在编译实现之后,JSX 表达式就变成了惯例的 JavaScript 对象,这意味着你能够在 if
语句和 for
循环外部应用 JSX,将它赋值给变量,承受它作为参数,并从函数中返回它。
为什么应用 jsx 的组件中没有看到应用 react 却须要引入 react?
实质上来说 JSX 是 React.createElement(component, props, ...children)
办法的语法糖。在 React 17 之前,如果应用了 JSX,其实就是在应用 React,babel
会把组件转换为 CreateElement
模式。在 React 17 之后,就不再须要引入,因为 babel
曾经能够帮咱们主动引入 react。
在 React 中元素(element)和组件(component)有什么区别?
简略地说,在 React 中元素(虛拟 DOM)形容了你在屏幕上看到的 DOM 元素。
换个说法就是,在 React 中元素是页面中 DOM 元素的对象示意形式。在 React 中组件是一个函数或一个类,它能够承受输出并返回一个元素。
留神:工作中,为了进步开发效率,通常应用 JSX 语法示意 React 元素(虚构 DOM)。在编译的时候,把它转化成一个 React. createElement 调用办法。
非嵌套关系组件的通信形式?
即没有任何蕴含关系的组件,包含兄弟组件以及不在同一个父级中的非兄弟组件。
- 能够应用自定义事件通信(公布订阅模式)
- 能够通过 redux 等进行全局状态治理
- 如果是兄弟组件通信,能够找到这两个兄弟节点独特的父节点, 联合父子间通信形式进行通信。
形容事件在 React 中的解决形式。
为了解决跨浏览器兼容性问题,React 中的事件处理程序将传递 SyntheticEvent 的实例,它是跨浏览器事件的包装器。这些 SyntheticEvent 与你习惯的原生事件具备雷同的接口,它们在所有浏览器中都兼容。
React 实际上并没有将事件附加到子节点自身。而是通过事件委托模式,应用单个事件监听器监听顶层的所有事件。这对于性能是有益处的。这也意味着在更新 DOM 时,React 不须要放心跟踪事件监听器。
Redux 实现原理解析
为什么要用 redux
在
React
中,数据在组件中是单向流动的,数据从一个方向父组件流向子组件(通过props
), 所以,两个非父子组件之间通信就绝对麻烦,redux
的呈现就是为了解决state
外面的数据问题
Redux 设计理念
Redux
是将整个利用状态存储到一个中央上称为store
, 外面保留着一个状态树store tree
, 组件能够派发(dispatch
) 行为 (action
) 给store
, 而不是间接告诉其余组件,组件外部通过订阅store
中的状态state
来刷新本人的视图
Redux 三大准则
- 惟一数据源
整个利用的 state 都被存储到一个状态树外面,并且这个状态树,只存在于惟一的 store 中
- 放弃只读状态
state
是只读的,惟一扭转state
的办法就是触发action
,action
是一个用于形容以产生工夫的一般对象
- 数据扭转只能通过纯函数来执行
应用纯函数来执行批改,为了形容
action
如何扭转state
的,你须要编写reducers
Redux 源码
let createStore = (reducer) => {
let state;
// 获取状态对象
// 寄存所有的监听函数
let listeners = [];
let getState = () => state;
// 提供一个办法供内部调用派发 action
let dispath = (action) => {
// 调用管理员 reducer 失去新的 state
state = reducer(state, action);
// 执行所有的监听函数
listeners.forEach((l) => l())
}
// 订阅状态变动事件,当状态扭转产生之后执行监听函数
let subscribe = (listener) => {listeners.push(listener);
}
dispath();
return {
getState,
dispath,
subscribe
}
}
let combineReducers=(renducers)=>{
// 传入一个 renducers 治理组,返回的是一个 renducer
return function(state={},action={}){let newState={};
for(var attr in renducers){newState[attr]=renducers[attr](state[attr],action)
}
return newState;
}
}
export {createStore,combineReducers};