你了解“在React中,一切都是组件”这句话。
组件是 React 利用 UI 的构建块。这些组件将整个 UI 分成小的独立并可重用的局部。每个组件彼此独立,而不会影响 UI 的其余部分。
约束性组件( controlled component)与非约束性组件( uncontrolled component)有什么区别?
在 React中,组件负责管制和治理本人的状态。
如果将HTML中的表单元素( input、 select、 textarea等)增加到组件中,当用户与表单产生交互时,就波及表单数据存储问题。依据表单数据的存储地位,将组件分成约東性组件和非约東性组件。
约束性组件( controlled component)就是由 React管制的组件,也就是说,表单元素的数据存储在组件外部的状态中,表单到底出现什么由组件决定。
如下所示, username没有存储在DOM元素内,而是存储在组件的状态中。每次要更新 username时,就要调用 setState更新状态;每次要获取 username的值,就要获取组件状态值。
class App extends Component {
//初始化状态
constructor(props) {
super(props);
this.state = {
username: "有课前端网",
};
}
//查看后果
showResult() {
//获取数据就是获取状态值
console.log(this.state.username);
}
changeUsername(e) {
//原生办法获取
var value = e.target.value;
//更新前,能够进行脏值检测
//更新状态
this.setState({
username: value,
});
}
//渲染组件
render() {
//返回虚构DOM
return (
<div>
<p>
{/*输入框绑定va1ue*/}
<input type="text" onChange={this.changeUsername.bind(this)} value={this.state.username} />
</p>
<p>
<button onClick={this.showResult.bind(this)}>查看后果</button>
</p>
</div>
);
}
}
非约束性组件( uncontrolled component)就是指表单元素的数据交由元素本身存储并解决,而不是通过 React组件。表单如何出现由表单元素本身决定。
如下所示,表单的值并没有存储在组件的状态中,而是存储在表单元素中,当要批改表单数据时,间接输出表单即可。有时也能够获取元素,再手动批改它的值。当要获取表单数据时,要首先获取表单元素,而后通过表单元素获取元素的值。
留神:为了不便在组件中获取表单元素,通常为元素设置ref属性,在组件外部通过refs属性获取对应的DOM元素。
class App extends Component {
//查看后果
showResult() {
//获取值
console.log(this.refs.username.value);
//批改值,就是批改元素本身的值
this.refs.username.value = "业余前端学习平台";
//渲染组件
//返回虚构DOM
return (
<div>
<p>
{/*非约束性组件中,表单元素通过 defaultvalue定义*/}
<input type="text" ref=" username" defaultvalue="有课前端网" />
</p>
<p>
<button onClick={this.showResult.bind(this)}>查看后果</button>
</p>
</div>
);
}
}
尽管非约東性组件通常更容易实现,能够通过refs间接获取DOM元素,并获取其值,然而 React倡议应用约束性组件。次要起因是,约東性组件反对即时字段验证,容许有条件地禁用/启用按钮,强制输出格局等。
react 生命周期
初始化阶段:
- getDefaultProps:获取实例的默认属性
- getInitialState:获取每个实例的初始化状态
- componentWillMount:组件行将被装载、渲染到页面上
- render:组件在这里生成虚构的 DOM 节点
- componentDidMount:组件真正在被装载之后
运行中状态:
- componentWillReceiveProps:组件将要接管到属性的时候调用
- shouldComponentUpdate:组件承受到新属性或者新状态的时候(能够返回 false,接收数据后不更新,阻止 render 调用,前面的函数不会被继续执行了)
- componentWillUpdate:组件行将更新不能批改属性和状态
- render:组件从新描述
- componentDidUpdate:组件曾经更新
销毁阶段:
- componentWillUnmount:组件行将销毁
shouldComponentUpdate 是做什么的,(react 性能优化是哪个周期函数?)
shouldComponentUpdate 这个办法用来判断是否须要调用 render 办法从新描述 dom。因为 dom 的描述十分耗费性能,如果咱们能在 shouldComponentUpdate 办法中可能写出更优化的 dom diff 算法,能够极大的进步性能。
在react17 会删除以下三个生命周期
componentWillMount,componentWillReceiveProps , componentWillUpdate
**
React 与 Vue 的 diff 算法有何不同?
diff 算法是指生成更新补丁的形式,次要利用于虚构 DOM 树变动后,更新实在 DOM。所以 diff 算法肯定存在这样一个过程:触发更新 → 生成补丁 → 利用补丁。
React 的 diff 算法,触发更新的机会次要在 state 变动与 hooks 调用之后。此时触发虚构 DOM 树变更遍历,采纳了深度优先遍历算法。但传统的遍历形式,效率较低。为了优化效率,应用了分治的形式。将繁多节点比对转化为了 3 种类型节点的比对,别离是树、组件及元素,以此晋升效率。
- 树比对:因为网页视图中较少有跨层级节点挪动,两株虚构 DOM 树只对同一档次的节点进行比拟。
- 组件比对:如果组件是同一类型,则进行树比对,如果不是,则间接放入到补丁中。
- 元素比对:次要产生在同层级中,通过标记节点操作生成补丁,节点操作对应实在的 DOM 剪裁操作。
以上是经典的 React diff 算法内容。自 React 16 起,引入了 Fiber 架构。为了使整个更新过程可随时暂停复原,节点与树别离采纳了 FiberNode 与 FiberTree 进行重构。fiberNode 应用了双链表的构造,能够间接找到兄弟节点与子节点。整个更新过程由 current 与 workInProgress 两株树双缓冲实现。workInProgress 更新实现后,再通过批改 current 相干指针指向新节点。
Vue 的整体 diff 策略与 React 对齐,尽管不足工夫切片能力,但这并不意味着 Vue 的性能更差,因为在 Vue 3 初期引入过,前期因为收益不高移除掉了。除了高帧率动画,在 Vue 中其余的场景简直都能够应用防抖和节流去进步响应性能。
参考:前端react面试题具体解答
React 废除了哪些生命周期?为什么?
被废除的三个函数都是在render之前,因为fber的呈现,很可能因为高优先级工作的呈现而打断现有工作导致它们会被执行屡次。另外的一个起因则是,React想束缚使用者,好的框架可能让人不得已写出容易保护和扩大的代码,这一点又是从何谈起,能够从新减少以及行将废除的生命周期剖析动手
1) componentWillMount
首先这个函数的性能齐全能够应用componentDidMount和 constructor来代替,异步获取的数据的状况下面曾经阐明了,而如果抛去异步获取数据,其余的即是初始化而已,这些性能都能够在constructor中执行,除此之外,如果在 willMount 中订阅事件,但在服务端这并不会执行 willUnMount事件,也就是说服务端会导致内存透露所以componentWilIMount齐全能够不应用,但使用者有时候不免因为各 种各样的状况在 componentWilMount中做一些操作,那么React为了束缚开发者,罗唆就抛掉了这个API
2) componentWillReceiveProps
在老版本的 React 中,如果组件本身的某个 state 跟其 props 密切相关的话,始终都没有一种很优雅的解决形式去更新 state,而是须要在 componentWilReceiveProps 中判断前后两个 props 是否雷同,如果不同再将新的 props更新到相应的 state 下来。这样做一来会毁坏 state 数据的繁多数据源,导致组件状态变得不可预测,另一方面也会减少组件的重绘次数。相似的业务需要也有很多,如一个能够横向滑动的列表,以后高亮的 Tab 显然隶属于列表本身的时,依据传入的某个值,间接定位到某个 Tab。为了解决这些问题,React引入了第一个新的生命周期:getDerivedStateFromProps。它有以下的长处∶
- getDSFP是静态方法,在这里不能应用this,也就是一个纯函数,开发者不能写出副作用的代码
- 开发者只能通过prevState而不是prevProps来做比照,保障了state和props之间的简略关系以及不须要解决第一次渲染时prevProps为空的状况
- 基于第一点,将状态变动(setState)和低廉操作(tabChange)辨别开,更加便于 render 和 commit 阶段操作或者说优化。
3) componentWillUpdate
与 componentWillReceiveProps 相似,许多开发者也会在 componentWillUpdate 中依据 props 的变动去触发一些回调 。 但不论是 componentWilReceiveProps 还 是 componentWilUpdate,都有可能在一次更新中被调用屡次,也就是说写在这里的回调函数也有可能会被调用屡次,这显然是不可取的。与 componentDidMount 类 似, componentDidUpdate 也不存在这样的问题,一次更新中 componentDidUpdate 只会被调用一次,所以将原先写在 componentWillUpdate 中 的 回 调 迁 移 至 componentDidUpdate 就能够解决这个问题。
另外一种状况则是须要获取DOM元素状态,然而因为在fber中,render可打断,可能在wilMount中获取到的元素状态很可能与理论须要的不同,这个通常能够应用第二个新增的生命函数的解决 getSnapshotBeforeUpdate(prevProps, prevState)
4) getSnapshotBeforeUpdate(prevProps, prevState)
返回的值作为componentDidUpdate的第三个参数。与willMount不同的是,getSnapshotBeforeUpdate会在最终确定的render执行之前执行,也就是能保障其获取到的元素状态与didUpdate中获取到的元素状态雷同。官网参考代码:
class ScrollingList extends React.Component {
constructor(props) {
super(props);
this.listRef = React.createRef();
}
getSnapshotBeforeUpdate(prevProps, prevState) {
// 咱们是否在 list 中增加新的 items ?
// 捕捉滚动地位以便咱们稍后调整滚动地位。
if (prevProps.list.length < this.props.list.length) {
const list = this.listRef.current;
return list.scrollHeight - list.scrollTop;
}
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
// 如果咱们 snapshot 有值,阐明咱们刚刚增加了新的 items,
// 调整滚动地位使得这些新 items 不会将旧的 items 推出视图。
//(这里的 snapshot 是 getSnapshotBeforeUpdate 的返回值)
if (snapshot !== null) {
const list = this.listRef.current;
list.scrollTop = list.scrollHeight - snapshot;
}
}
render() {
return (
<div ref={this.listRef}>{/* ...contents... */}</div>
);
}
}
React中setState的第二个参数作用是什么?
setState
的第二个参数是一个可选的回调函数。这个回调函数将在组件从新渲染后执行。等价于在 componentDidUpdate
生命周期内执行。通常倡议应用 componentDidUpdate
来代替此形式。在这个回调函数中你能够拿到更新后 state
的值:
this.setState({
key1: newState1,
key2: newState2,
...
}, callback) // 第二个参数是 state 更新实现后的回调函数
React 高阶组件是什么,和一般组件有什么区别,实用什么场景
官网解释∶
高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 本身不是 React API 的一部分,它是一种基于 React 的组合个性而造成的设计模式。
高阶组件(HOC)就是一个函数,且该函数承受一个组件作为参数,并返回一个新的组件,它只是一种组件的设计模式,这种设计模式是由react本身的组合性质必然产生的。咱们将它们称为纯组件,因为它们能够承受任何动静提供的子组件,但它们不会批改或复制其输出组件中的任何行为。
// hoc的定义
function withSubscription(WrappedComponent, selectData) {
return class extends React.Component {
constructor(props) {
super(props);
this.state = {
data: selectData(DataSource, props)
};
}
// 一些通用的逻辑解决
render() {
// ... 并应用新数据渲染被包装的组件!
return <WrappedComponent data={this.state.data} {...this.props} />;
}
};
// 应用
const BlogPostWithSubscription = withSubscription(BlogPost,
(DataSource, props) => DataSource.getBlogPost(props.id));
1)HOC的优缺点
- 长处∶ 逻辑服用、不影响被包裹组件的外部逻辑。
- 毛病∶hoc传递给被包裹组件的props容易和被包裹后的组件重名,进而被笼罩
2)实用场景
- 代码复用,逻辑形象
- 渲染劫持
- State 形象和更改
- Props 更改
3)具体利用例子
- 权限管制: 利用高阶组件的 条件渲染 个性能够对页面进行权限管制,权限管制个别分为两个维度:页面级别和 页面元素级别
// HOC.js
function withAdminAuth(WrappedComponent) {
return class extends React.Component {
state = {
isAdmin: false,
}
async UNSAFE_componentWillMount() {
const currentRole = await getCurrentUserRole();
this.setState({
isAdmin: currentRole === 'Admin',
});
}
render() {
if (this.state.isAdmin) {
return <WrappedComponent {...this.props} />;
} else {
return (<div>您没有权限查看该页面,请分割管理员!</div>);
}
}
};
}
// pages/page-a.js
class PageA extends React.Component {
constructor(props) {
super(props);
// something here...
}
UNSAFE_componentWillMount() {
// fetching data
}
render() {
// render page with data
}
}
export default withAdminAuth(PageA);
// pages/page-b.js
class PageB extends React.Component {
constructor(props) {
super(props);
// something here...
}
UNSAFE_componentWillMount() {
// fetching data
}
render() {
// render page with data
}
}
export default withAdminAuth(PageB);
- 组件渲染性能追踪: 借助父组件子组件生命周期规定捕捉子组件的生命周期,能够不便的对某个组件的渲染工夫进行记录∶
class Home extends React.Component {
render() {
return (<h1>Hello World.</h1>);
}
}
function withTiming(WrappedComponent) {
return class extends WrappedComponent {
constructor(props) {
super(props);
this.start = 0;
this.end = 0;
}
UNSAFE_componentWillMount() {
super.componentWillMount && super.componentWillMount();
this.start = Date.now();
}
componentDidMount() {
super.componentDidMount && super.componentDidMount();
this.end = Date.now();
console.log(`${WrappedComponent.name} 组件渲染工夫为 ${this.end - this.start} ms`);
}
render() {
return super.render();
}
};
}
export default withTiming(Home);
留神:withTiming 是利用 反向继承 实现的一个高阶组件,性能是计算被包裹组件(这里是 Home 组件)的渲染工夫。
- 页面复用
const withFetching = fetching => WrappedComponent => {
return class extends React.Component {
state = {
data: [],
}
async UNSAFE_componentWillMount() {
const data = await fetching();
this.setState({
data,
});
}
render() {
return <WrappedComponent data={this.state.data} {...this.props} />;
}
}
}
// pages/page-a.js
export default withFetching(fetching('science-fiction'))(MovieList);
// pages/page-b.js
export default withFetching(fetching('action'))(MovieList);
// pages/page-other.js
export default withFetching(fetching('some-other-type'))(MovieList);
class类的key改了,会产生什么,会执行哪些周期函数?
在开发过程中,咱们须要保障某个元素的 key 在其同级元素中具备唯一性。在 React Diff 算法中 React 会借助元素的 Key 值来判断该元素是早先创立的还是被挪动而来的元素,从而缩小不必要的元素重渲染。此外,React 还须要借助 Key 值来判断元素与本地状态的关联关系,因而咱们绝不可漠视转换函数中 Key 的重要性。
答:componentWillMount componentDidMount render
React申明组件有哪几种办法,有什么不同?
React 申明组件的三种形式:
- 函数式定义的
无状态组件
- ES5原生形式
React.createClass
定义的组件 - ES6模式的
extends React.Component
定义的组件
(1)无状态函数式组件 它是为了创立纯展现组件,这种组件只负责依据传入的props来展现,不波及到state状态的操作
组件不会被实例化,整体渲染性能失去晋升,不能拜访this对象,不能拜访生命周期的办法
(2)ES5 原生形式 React.createClass // RFC React.createClass会自绑定函数办法,导致不必要的性能开销,减少代码过期的可能性。
(3)E6继承模式 React.Component // RCC 目前极为举荐的创立有状态组件的形式,最终会取代React.createClass模式;绝对于 React.createClass能够更好实现代码复用。
无状态组件绝对于于后者的区别: 与无状态组件相比,React.createClass和React.Component都是创立有状态的组件,这些组件是要被实例化的,并且能够拜访组件的生命周期办法。
React.createClass与React.Component区别:
① 函数this自绑定
- React.createClass创立的组件,其每一个成员函数的this都有React主动绑定,函数中的this会被正确设置。
- React.Component创立的组件,其成员函数不会主动绑定this,须要开发者手动绑定,否则this不能获取以后组件实例对象。
② 组件属性类型propTypes及其默认props属性defaultProps配置不同
- React.createClass在创立组件时,无关组件props的属性类型及组件默认的属性会作为组件实例的属性来配置,其中defaultProps是应用getDefaultProps的办法来获取默认组件属性的
- React.Component在创立组件时配置这两个对应信息时,他们是作为组件类的属性,不是组件实例的属性,也就是所谓的类的动态属性来配置的。
③ 组件初始状态state的配置不同
- React.createClass创立的组件,其状态state是通过getInitialState办法来配置组件相干的状态;
- React.Component创立的组件,其状态state是在constructor中像初始化组件属性一样申明的。
React 事件机制
<div onClick={this.handleClick.bind(this)}>点我</div>
React并不是将click事件绑定到了div的实在DOM上,而是在document处监听了所有的事件,当事件产生并且冒泡到document处的时候,React将事件内容封装并交由真正的处理函数运行。这样的形式不仅仅缩小了内存的耗费,还能在组件挂在销毁时对立订阅和移除事件。
除此之外,冒泡到document上的事件也不是原生的浏览器事件,而是由react本人实现的合成事件(SyntheticEvent)。因而如果不想要是事件冒泡的话应该调用event.preventDefault()办法,而不是调用event.stopProppagation()办法。 JSX 上写的事件并没有绑定在对应的实在 DOM 上,而是通过事件代理的形式,将所有的事件都对立绑定在了 document
上。这样的形式不仅缩小了内存耗费,还能在组件挂载销毁时对立订阅和移除事件。
另外冒泡到 document
上的事件也不是原生浏览器事件,而是 React 本人实现的合成事件(SyntheticEvent)。因而咱们如果不想要事件冒泡的话,调用 event.stopPropagation
是有效的,而应该调用 event.preventDefault
。
实现合成事件的目标如下:
- 合成事件首先抹平了浏览器之间的兼容问题,另外这是一个跨浏览器原生事件包装器,赋予了跨浏览器开发的能力;
- 对于原生浏览器事件来说,浏览器会给监听器创立一个事件对象。如果你有很多的事件监听,那么就须要调配很多的事件对象,造成高额的内存调配问题。然而对于合成事件来说,有一个事件池专门来治理它们的创立和销毁,当事件须要被应用时,就会从池子中复用对象,事件回调完结后,就会销毁事件对象上的属性,从而便于下次复用事件对象。
react-router 里的 Link 标签和 a 标签的区别
从最终渲染的 DOM 来看,这两者都是链接,都是 标签,区别是∶ <Link>
是react-router 里实现路由跳转的链接,个别配合<Route>
应用,react-router接管了其默认的链接跳转行为,区别于传统的页面跳转,<Link>
的“跳转”行为只会触发相匹配的<Route>
对应的页面内容更新,而不会刷新整个页面。
<Link>
做了3件事件:
- 有onclick那就执行onclick
- click的时候阻止a标签默认事件
- 依据跳转href(即是to),用history (web前端路由两种形式之一,history & hash)跳转,此时只是链接变了,并没有刷新页面而
<a>
标签就是一般的超链接了,用于从以后页面跳转到href指向的另一 个页面(非锚点状况)。
a标签默认事件禁掉之后做了什么才实现了跳转?
let domArr = document.getElementsByTagName('a')
[...domArr].forEach(item=>{
item.addEventListener('click',function () {
location.href = this.href
})
})
React的严格模式如何应用,有什么用途?
StrictMode
是一个用来突出显示应用程序中潜在问题的工具。与 Fragment
一样,StrictMode
不会渲染任何可见的 UI。它为其后辈元素触发额定的检查和正告。
能够为应用程序的任何局部启用严格模式。例如:
import React from 'react';
function ExampleApplication() {
return (
<div>
<Header />
<React.StrictMode>
<div>
<ComponentOne />
<ComponentTwo />
</div>
</React.StrictMode>
<Footer />
</div>
);
}
在上述的示例中,不会对 Header
和 Footer
组件运行严格模式查看。然而,ComponentOne
和 ComponentTwo
以及它们的所有后辈元素都将进行查看。
StrictMode
目前有助于:
- 辨认不平安的生命周期
- 对于应用过期字符串 ref API 的正告
- 对于应用废除的 findDOMNode 办法的正告
- 检测意外的副作用
- 检测过期的 context API
React-Router的实现原理是什么?
客户端路由实现的思维:
-
基于 hash 的路由:通过监听
hashchange
事件,感知 hash 的变动- 扭转 hash 能够间接通过 location.hash=xxx
-
基于 H5 history 路由:
- 扭转 url 能够通过 history.pushState 和 resplaceState 等,会将URL压入堆栈,同时可能利用
history.go()
等 API - 监听 url 的变动能够通过自定义事件触发实现
- 扭转 url 能够通过 history.pushState 和 resplaceState 等,会将URL压入堆栈,同时可能利用
react-router 实现的思维:
- 基于
history
库来实现上述不同的客户端路由实现思维,并且可能保留历史记录等,磨平浏览器差别,下层无感知 - 通过保护的列表,在每次 URL 发生变化的回收,通过配置的 路由门路,匹配到对应的 Component,并且 render
mobox 和 redux 有什么区别?
(1)共同点
- 为了解决状态管理混乱,无奈无效同步的问题对立保护治理利用状态;
- 某一状态只有一个可信数据起源(通常命名为store,指状态容器);
- 操作更新状态形式对立,并且可控(通常以action形式提供更新状态的路径);
- 反对将store与React组件连贯,如react-redux,mobx- react;
(2)区别 Redux更多的是遵循Flux模式的一种实现,是一个 JavaScript库,它关注点次要是以下几方面∶
-
Action∶ 一个JavaScript对象,形容动作相干信息,次要蕴含type属性和payload属性∶
o type∶ action 类型; o payload∶ 负载数据;
- Reducer∶ 定义利用状态如何响应不同动作(action),如何更新状态;
-
Store∶ 治理action和reducer及其关系的对象,次要提供以下性能∶
o 保护利用状态并反对拜访状态(getState()); o 反对监听action的散发,更新状态(dispatch(action)); o 反对订阅store的变更(subscribe(listener));
- 异步流∶ 因为Redux所有对store状态的变更,都应该通过action触发,异步工作(通常都是业务或获取数据工作)也不例外,而为了不将业务或数据相干的工作混入React组件中,就须要应用其余框架配合治理异步工作流程,如redux-thunk,redux-saga等;
Mobx是一个通明函数响应式编程的状态治理库,它使得状态治理简略可伸缩∶
- Action∶定义扭转状态的动作函数,包含如何变更状态;
- Store∶ 集中管理模块状态(State)和动作(action)
- Derivation(衍生)∶ 从利用状态中派生而出,且没有任何其余影响的数据
比照总结:
- redux将数据保留在繁多的store中,mobx将数据保留在扩散的多个store中
- redux应用plain object保留数据,须要手动解决变动后的操作;mobx实用observable保留数据,数据变动后主动解决响应的操作
- redux应用不可变状态,这意味着状态是只读的,不能间接去批改它,而是应该返回一个新的状态,同时应用纯函数;mobx中的状态是可变的,能够间接对其进行批改
- mobx相对来说比较简单,在其中有很多的形象,mobx更多的应用面向对象的编程思维;redux会比较复杂,因为其中的函数式编程思维把握起来不是那么容易,同时须要借助一系列的中间件来解决异步和副作用
- mobx中有更多的形象和封装,调试会比拟艰难,同时后果也难以预测;而redux提供可能进行工夫回溯的开发工具,同时其纯函数以及更少的形象,让调试变得更加的容易
React 性能优化在哪个生命周期?它优化的原理是什么?
react的父级组件的render函数从新渲染会引起子组件的render办法的从新渲染。然而,有的时候子组件的承受父组件的数据没有变动。子组件render的执行会影响性能,这时就能够应用shouldComponentUpdate来解决这个问题。
应用办法如下:
shouldComponentUpdate(nexrProps) {
if (this.props.num === nexrProps.num) {
return false
}
return true;
}
shouldComponentUpdate提供了两个参数nextProps和nextState,示意下一次props和一次state的值,当函数返回false时候,render()办法不执行,组件也就不会渲染,返回true时,组件照常重渲染。此办法就是拿以后props中值和下一次props中的值进行比照,数据相等时,返回false,反之返回true。
须要留神,在进行新旧比照的时候,是浅比照,也就是说如果比拟的数据时援用数据类型,只有数据的援用的地址没变,即便内容变了,也会被断定为true。
面对这个问题,能够应用如下办法进行解决:
(1)应用setState扭转数据之前,先采纳ES6中assgin进行拷贝,然而assgin只深拷贝的数据的第一层,所以说不是最完满的解决办法:
const o2 = Object.assign({},this.state.obj)
o2.student.count = '00000';
this.setState({
obj: o2,
})
(2)应用JSON.parse(JSON.stringfy())进行深拷贝,然而遇到数据为undefined和函数时就会错。
const o2 = JSON.parse(JSON.stringify(this.state.obj))
o2.student.count = '00000';
this.setState({
obj: o2,
})
为什么调用 setState 而不是间接扭转 state?
解答
如果您尝试间接扭转组件的状态,React 将无奈得悉它须要从新渲染组件。通过应用setState()
办法,React 能够更新组件的UI。
另外,您还能够谈谈如何不保障状态更新是同步的。如果须要基于另一个状态(或属性)更新组件的状态,请向setState()
传递一个函数,该函数将 state 和 props 作为其两个参数:
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
对 React-Intl 的了解,它的工作原理?
React-intl是雅虎的语言国际化开源我的项目FormatJS的一部分,通过其提供的组件和API能够与ReactJS绑定。
React-intl提供了两种应用办法,一种是援用React组件,另一种是间接调取API,官网更加举荐在React我的项目中应用前者,只有在无奈应用React组件的中央,才应该调用框架提供的API。它提供了一系列的React组件,包含数字格式化、字符串格式化、日期格式化等。
在React-intl中,能够配置不同的语言包,他的工作原理就是依据须要,在语言包之间进行切换。
React-Router 4怎么在路由变动时从新渲染同一个组件?
当路由变动时,即组件的props产生了变动,会调用componentWillReceiveProps等生命周期钩子。那须要做的只是: 当路由扭转时,依据路由,也去申请数据:
class NewsList extends Component {
componentDidMount () {
this.fetchData(this.props.location);
}
fetchData(location) {
const type = location.pathname.replace('/', '') || 'top'
this.props.dispatch(fetchListData(type))
}
componentWillReceiveProps(nextProps) {
if (nextProps.location.pathname != this.props.location.pathname) {
this.fetchData(nextProps.location);
}
}
render () {
...
}
}
利用生命周期componentWillReceiveProps,进行从新render的预处理操作。
如何有条件地向 React 组件增加属性?
对于某些属性,React 十分聪慧,如果传递给它的值是虚值,能够省略该属性。例如:
var InputComponent = React.createClass({
render: function () {
var required = true;
var disabled = false;
return <input type="text" disabled={disabled} required={required} />;
},
});
渲染后果:
<input type="text" required>
另一种可能的办法是:
var condition = true;
var component = <div value="foo" {...(condition && { disabled: true })} />;
React 如何辨别 Class组件 和 Function组件
个别的形式是借助 typeof 和 Function.prototype.toString 来判断以后是不是 class,如下:
function isClass(func) {
return typeof func === 'function'
&& /^class\s/.test(Function.prototype.toString.call(func));
}
然而这个形式有它的局限性,因为如果用了 babel 等转换工具,将 class 写法全副转为 function 写法,下面的判断就会生效。
React 辨别 Class组件 和 Function组件的形式很奇妙,因为所有的类组件都要继承 React.Component,所以只有判断原型链上是否有 React.Component 就能够了:
AComponent.prototype instanceof React.Component