React 面试必知必会 Day7

2,271 阅读4分钟

这是我参与更文挑战的第13天,活动详情查看:更文挑战

大家好,我是 @洛竹,一个坚持写作的博主,感恩你的每一个点赞和评论。

本文首发于 洛竹的官方网站

本文翻译自 sudheerj/reactjs-interview-questions

本文同步于公众号洛竹早茶馆,转载请联系作者。

1. 如何在 React 使用样式?

style 属性接受一个小驼峰命名法属性的 JavaScript 对象,而不是一个 CSS 字符串。这与 DOM 风格的 JavaScript 属性一致,更有效率,并能防止 XSS 安全漏洞。

const divStyle = {
  color: 'blue',
  backgroundImage: `url(${imgUrl})`,
};

function HelloWorldComponent() {
  return <div style={divStyle}>Hello World!</div>;
}

样式键名是符合驼峰命名法的,以便与在 JavaScript 中访问 DOM 节点的属性相一致(例如 node.style.backgroundImage)。

2. 事件在 React 中有何不同?

Handling events in React elements has some syntactic differences:

在 React 元素上处理事件有一些语法上的不同:

  1. React 事件处理程序使用小驼峰命名,而不是小写。
  2. 使用 JSX,你传递一个函数作为事件处理程序,而不是一个字符串。

3. 如果你在构造函数中使用 setState(),会发生什么?

当你使用 setState() 时,除了分配给对象的状态外,React 还重新渲染组件和它的所有子组件。你会得到这样的错误:只能更新一个已挂载或正在挂载的组件。所以我们需要使用 this.state 来初始化构造函数中的变量。

4. 索引作为键的影响是什么?

键应该是稳定的、可预测的和唯一的,这样 React 就可以跟踪元素。

在下面的代码片段中,每个元素的键都是基于索引的,而不是与被表示的数据相联系。这限制了 React 可以做的优化。

{
  todos.map((todo, index) => <Todo {...todo} key={index} />);
}

如果你使用元素数据作为唯一键,假设 todo.id 在这个列表中是唯一的,并且是稳定的,React 将能够对元素进行重新排序,而不需要像以前那样重新计算它们。

{
  todos.map(todo => <Todo {...todo} key={todo.id} />);
}

5. 在 componentWillMount() 方法中使用 setState 真的好吗?

是的,在 componentWillMount() 方法中使用 setState() 是安全的。但同时,建议避免在componentWillMount() 生命周期方法中进行异步初始化。componentWillMount() 在挂载发生前立即被调用。它在 render() 之前被调用,因此在这个方法中设置状态不会触发重新渲染。避免在这个方法中引入任何副作用或订阅。我们需要确保组件初始化的异步调用发生在 componentDidMount() 而不是 componentWillMount()

componentDidMount() {
  axios.get(`api/todos`).then((result) => {
    this.setState({
      messages: [...result.data]
    })
  })
}

6. 如果你在初始状态下使用 props,会发生什么?

如果组件上的 props 被改变而组件没有被刷新,新的 props 值将永远不会被显示,因为构造函数永远不会更新组件的当前状态。来自 props 的状态初始化只在组件第一次被创建时运行。

下面这个组件就不会显示更新的输入值。

class MyComponent extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      records: [],
      inputValue: this.props.inputValue,
    };
  }

  render() {
    return <div>{this.state.inputValue}</div>;
  }
}

在 render 方法中使用 props 将更新数值。

class MyComponent extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      record: [],
    };
  }

  render() {
    return <div>{this.props.inputValue}</div>;
  }
}

7. 你如何有条件地渲染组件?

在某些情况下,你想根据一些状态来渲染不同的组件。JSX 不渲染 falseundefined,所以你可以使用条件性短路来渲染你的组件的某一部分,只有当某个条件为真时。

const MyComponent = ({ name, address }) => (
  <div>
    <h2>{name}</h2>
    {address && <p>{address}</p>}
  </div>
);

如果你需要一个 if-else 条件,则使用三元运算符。

const MyComponent = ({ name, address }) => (
  <div>
    <h2>{name}</h2>
    {address ? <p>{address}</p> : <p>{'Address is not available'}</p>}
  </div>
);

8. 为什么我们在 DOM 元素上传递 props 时需要谨慎?

当我们传递 props 时,我们会遇到添加未知的 HTML 属性的风险,这是一个不好的做法。相反,我们可以使用带有 ...rest 操作符的 prop 解构,所以它将只添加需要的 prop。

比如说。

const ComponentA = () => (
  <ComponentB isDisplay={true} className={'componentStyle'} />
);

const ComponentB = ({ isDisplay, ...domProps }) => (
  <div {...domProps}>{'ComponentB'}</div>
);

9. 如何在 React 中使用装饰器?

你可以对你的类组件进行装饰,这与将组件传入一个函数是一样的。装饰器是修改组件功能的灵活和可读的方式。

@setTitle('Profile')
class Profile extends React.Component {
  //....
}

/*
title 是一个字符串,将被设置为文档标题。WrappedComponent 是我们的装饰器在以下情况下会收到的东西直接放在一个组件类上面时,我们的装饰器会收到这样的信息,如上面的例子所示
*/
const setTitle = title => WrappedComponent => {
  return class extends React.Component {
    componentDidMount() {
      document.title = title;
    }

    render() {
      return <WrappedComponent {...this.props} />;
    }
  };
};

注意: 装饰器是一个没有进入 ES7 的功能,但目前是一个第二阶段的建议。

10. 如何 memo 化一个组件?

有一些可用的缓存库,可以用于函数组件。

例如,moize 库可以在另一个组件中对组件进行 memo 化。

import moize from 'moize';
import Component from './components/Component'; // 本模块导出一个非 memo 组件

const MemoizedFoo = moize.react(Component);

const Consumer = () => {
  <div>
    {'I will memoize the following entry:'}
    <MemoizedFoo />
  </div>;
};

更新: 从 React v16.6.0 开始,我们有一个 React.memo。它提供了一个更高阶的组件,除非 props 发生变化,否则会将组件缓存。要使用它,只需在使用前用 React.memo 包住组件。

const MemoComponent = React.memo(function MemoComponent(props) {
  /* render using props */
});
// 或者
export default React.memo(MyFunctionComponent);