前端关于Recat面试题(九)

161.React 支持所有的 HTML 属性么?

从 React 16 开始,完全支持标准或自定义 DOM 属性。由于 React 组件通常同时使用自定义和与 DOM 相关的属性,因此 React 与 DOM API 一样都使用 camelCase 约定。让我们对标准 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

除了特殊情况外,这些属性的工作方式与相应的 HTML 属性类似。它还支持所有 SVG 属性。

162.如何将事件处理程序传递给组件?

可以将事件处理程序和其他函数作为属性传递给子组件。它可以在子组件中使用,如下所示:

//父组件
<Child func={this.handleClick}></Child>

//子组件Child
<button  onClick={()=>this.props.func()}>点我</button>

163.在渲染方法中使用箭头函数好么?

是的,你可以用。它通常是向回调函数传递参数的最简单方法。但在使用时需要优化性能。

class Foo extends Component {
  handleClick() {
    console.log('Click happened');
  }
  render() {
    return <button onClick={() => this.handleClick()}>Click Me</button>;
  }
}

注意: 组件每次渲染时,在 render 方法中的箭头函数都会创建一个新的函数,这可能会影响性能。

164.如何防止函数被多次调用?

如果你使用一个事件处理程序,如 onClick or onScroll 并希望防止回调被过快地触发,那么你可以限制回调的执行速度。

这可以通过以下可能的方式实现:

  1. Throttling: 基于时间的频率进行更改。例如,它可以使用 lodash 的 _.throttle 函数。
  2. Debouncing: 在一段时间不活动后发布更改。例如,可以使用 lodash 的 _.debounce 函数。
  3. RequestAnimationFrame throttling: 基于 requestAnimationFrame 的更改。例如,可以使用 raf-schd。

注意:_.debounce, _.throttle 和 raf-schd 都提供了一个 cancel 方法来取消延迟回调。所以需要调用 componentWillUnmount,或者对代码进行检查来保证在延迟函数有效期间内组件始终挂载。

165.JSX 如何防止注入攻击?

React DOM 会在渲染 JSX 中嵌入的任何值之前对其进行转义。因此,它确保你永远不能注入任何未在应用程序中显式写入的内容。

const name = response.potentiallyMaliciousInput;
const element = <h1>{name}</h1>;

这样可以防止应用程序中的XSS(跨站点脚本)攻击。

166.如何更新已渲染的元素?

通过将新创建的元素传递给 ReactDOM 的 render 方法,可以实现 UI 更新。例如,让我们举一个滴答时钟的例子,它通过多次调用 render 方法来更新时间:

扫描二维码关注公众号,回复: 10798685 查看本文章
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);

167.如何防止组件渲染?

你可以基于特定的条件通过返回 null 值来阻止组件的渲染。这样它就可以有条件地渲染组件。

function Greeting(props) {
  if (!props.loggedIn) {
    return null;
  }

  return (
    <div className="greeting">
      welcome, {props.name}
    </div>
  );
}

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>
   );
  }

在上面的示例中,greeting 组件通过应用条件并返回空值跳过其渲染部分。

168.keys 是否需要全局唯一?

数组中使用的键在其同级中应该是唯一的,但它们不需要是全局唯一的。也就是说,你可以在两个不同的数组中使用相同的键。例如,下面的 book 组件在不同的组件中使用相同的数组:

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>
  );
}

169.用于表单处理的流行选择是什么?

Formik 是一个用于 React 的表单库,它提供验证、跟踪访问字段和处理表单提交等解决方案。具体来说,你可以按以下方式对它们进行分类:

  1. 获取表单状态输入和输出的值。
  2. 表单验证和错误消息。
  3. 处理表单提交。

它用于创建一个具有最小 API 的可伸缩、性能良好的表单助手,以解决令人讨厌的问题。

170.什么是基于路由的代码拆分?

进行代码拆分的最佳位置之一是路由。整个页面将立即重新渲染,因此用户不太可能同时与页面中的其他元素进行交互。因此,用户体验不会受到干扰。让我们以基于路由的网站为例,使用像 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>
);

在上面的代码中,代码拆分将发生在每个路由层级。

171.什么是高阶组件(HOC)?

高阶组件既不会修改原组件,也不会使用继承复制原组件的行为。相反,高阶组件是通过将原组件包裹(wrapping)在容器组件(container component)里面的方式来组合(composes) 使用原组件。高阶组件就是一个没有副作用的纯函数。

高阶组件的创建方式有两种:

  1. 属性代理(props proxy)。属性组件通过被包裹的 React 组件来操作 props。
const MyContainer = (WrappedComponent) => {
    return class extends Component {
        render() {
            return (
                <WrappedComponent
                    {...props}
                />
            )
        }
    }
}

export default MyContainer;


  1. 反向继承(inheritance inversion)。高阶组件继承于被包裹的 React 组件。
 function iiHOC(WrappedComponent) {
        return class Enhancer extends WrappedComponent {
            render() {
                return super.render()
            }
       }
    }


https://blog.csdn.net/weixin_34150830/article/details/88019752

172.HOC 有哪些限制?

除了它的好处之外,高阶组件还有一些注意事项。 以下列出的几个注意事项:

  1. 不要在渲染方法中使用HOC: 建议不要将 HOC 应用于组件的 render 方法中的组件。

    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 />;
    }
    
    
    

    上述代码通过重新装载,将导致该组件及其所有子组件状态丢失,会影响到性能。正确的做法应该是在组件定义之外应用 HOC ,以便仅生成一次生成的组件

  2. 静态方法必须复制: 将 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
    
    
    

    您可以通过在返回之前将方法复制到输入组件上来解决此问题

    function enhance(WrappedComponent) {
      class Enhance extends React.Component {/*...*/}
      // Must know exactly which method(s) to copy :(
      Enhance.staticMethod = WrappedComponent.staticMethod;
      return Enhance;
    }
    
    
    
  3. Refs 不会被往下传递 对于HOC,您需要将所有属性传递给包装组件,但这对于 refs 不起作用。这是因为 ref 并不是一个类似于 key 的属性。在这种情况下,您需要使用 React.forwardRef API。

173.在 HOCs 中 forward ref 的目的是什么?

因为 ref 不是一个属性,所以 Refs 不会被传递。就像 key 一样,React 会以不同的方式处理它。如果你将 ref 添加到 HOC,则该 ref 将引用最外层的容器组件,而不是包装的组件。在这种情况下,你可以使用 Forward Ref API。例如,你可以使用 React.forwardRef API 显式地将 refs 转发的内部的 FancyButton 组件。

以下的 HOC 会记录所有的 props 变化:

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} />;
  });
}

让我们使用这个 HOC 来记录所有传递到我们 “fancy button” 组件的属性:

class FancyButton extends React.Component {
  focus() {
    // ...
  }

  // ...
}
export default logProps(FancyButton);

现在让我们创建一个 ref 并将其传递给 FancyButton 组件。在这种情况下,你可以聚焦到 button 元素上。

import FancyButton from './FancyButton';

const ref = React.createRef();
ref.current.focus();
<FancyButton
  label="Click Me"
  handleClick={handleClick}
  ref={ref}
/>;

174.ref 参数对于所有函数或类组件是否可用?

常规函数或类组件不会接收到 ref 参数,并且 ref 在 props 中也不可用。只有在使用 React.forwardRef 定义组件时,才存在第二个 ref 参数。

175.如何在没有 ES6 的情况下创建 React 类组件

如果你不使用 ES6,那么你可能需要使用 create-react-class 模块。对于默认属性,你需要在传递对象上定义 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>;
  }
});

注意: 如果使用 createReactClass,则所有方法都会自动绑定。也就是说,你不需要在事件处理程序的构造函数中使用 .bind(this)。

176.如何设置非受控组件的默认值?

在 React 中,表单元素的属性值将覆盖其 DOM 中的值。对于非受控组件,你可能希望能够指定其初始值,但不会控制后续的更新。要处理这种情形,你可以指定一个 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>
  );
}

这同样适用于 selecttextArea 输入框。但对于 checkboxradio 控件,需要使用 defaultChecked

177.你最喜欢的 React 技术栈是什么?

主要使用 redux 和 redux saga 进行状态管理和具有副作用的异步操作,使用 react-router 进行路由管理,使用 styled-components 库开发 React 组件,使用 axios 调用 REST api,使用react-spring做动画,使用formik+yup做表单,以及其他支持的技术栈,如 webpack、reseselect、esnext、babel 等。

你可以克隆 https://github.com/react-boilerplate/react-boilerplate 并开始开发任何新的 React 项目。

178.如何为 React 应用程序添加 bootstrap?

Bootstrap 可以通过三种可能的方式添加到 React 应用程序中:

  1. 使用 Bootstrap CDN: 这是添加 bootstrap 最简单的方式。在 head 标签中添加 bootstrap 相应的 CSS 和 JS 资源。

  2. 把 Bootstrap 作为依赖项: 如果你使用的是构建工具或模块绑定器(如Webpack),那么这是向 React 应用程序添加 bootstrap 的首选选项。

    npm install bootstrap
    
    
  3. 使用 React Bootstrap 包: 在这种情况下,你可以将 Bootstrap 添加到我们的 React 应用程序中,方法是使用一个以 React 组件形式对 Bootstrap 组件进行包装后包。下面的包在此类别中很流行:

    1. react-bootstrap
    2. reactstrap

179.是否建议在 React 中使用 CSS In JS 技术?

React 对如何定义样式没有任何意见,但如果你是初学者,那么好的起点是像往常一样在单独的 *.css 文件中定义样式,并使用类名引用它们。此功能不是 React 的一部分,而是来自第三方库。但是如果你想尝试不同的方法(JS中的CSS),那么 styled-components 库是一个不错的选择。

发布了29 篇原创文章 · 获赞 0 · 访问量 741

猜你喜欢

转载自blog.csdn.net/Jojorain/article/details/105522190