关于react.js:腾讯前端二面常考react面试题总结

31次阅读

共计 15250 个字符,预计需要花费 39 分钟才能阅读完成。

你了解“在 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>
  );
}

在上述的示例中,不会对 HeaderFooter 组件运行严格模式查看。然而,ComponentOneComponentTwo 以及它们的所有后辈元素都将进行查看。

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 的变动能够通过自定义事件触发实现

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

正文完
 0