【React】精选5题

1. React 组件间怎么进行通信?

  • Props:组件的数据流向一般是单向的,父组件通过 Props 将数据传递给子组件。子组件可以通过 this.props 来访问这些数据。父组件也可以通过 Props 向子组件传递函数,使得子组件可以向父组件发送消息。

  • Context:React 的 Context API 可以用于在组件树中共享数据,从而避免 Props drilling(即将 Props 层层传递给深层组件)。父组件可以通过 React.createContext 创建一个 context,并通过 Provider 组件将数据传递给子组件,子组件可以通过 Consumer 组件或 useContext 钩子来访问这些数据。

  • Refs:Refs 可以用来获取组件实例或 DOM 节点的引用。父组件可以通过 Refs 获取子组件的实例,从而调用子组件暴露的方法或访问子组件的属性。

  • 自定义事件:父组件可以通过 EventEmitter 或其他第三方库创建自定义事件,子组件可以监听这些事件并触发相应的回调函数。

  • 全局状态管理器:使用全局状态管理器(例如 Redux 或 MobX)可以将应用程序的状态集中管理,任何组件都可以访问和修改这些状态,从而实现跨组件通信。

2. 说说你在React项目是如何捕获错误的?

  • 使用 Error Boundaries:Error Boundaries (错误边界)是 React 提供的一种机制,用于在组件树中捕获 JavaScript 异常并显示备用 UI,以便让应用程序在出现错误时仍能正常运行。可以在组件中实现 componentDidCatch 生命周期方法捕获错误。

  • 使用 try-catch:在 JavaScript 中,可以使用 try-catch 语句捕获可能出现的异常,并在 catch 语句块中处理这些异常。在 React 中,可以在组件的 render 方法中使用 try-catch 语句捕获异常。

  • 使用 Sentry 等错误跟踪工具:Sentry 是一款常用的错误跟踪工具,可以通过集成 Sentry SDK 来捕获 JavaScript 异常、HTTP 请求异常等。在 React 项目中,可以通过集成 Sentry SDK 来捕获错误,并收集错误信息、堆栈信息等。Sentry 还提供了一系列的工具和服务,帮助开发人员更好地分析和处理错误。

  • 使用代码检查工具:使用一些代码检查工具如 ESLint 和 TypeScript 等,可以在编码阶段检查代码中的潜在错误,从而减少运行时错误的出现。

错误边界

为了解决出现的错误导致整个应用崩溃的问题,react16引用了错误边界新的概念。

错误边界是一种 React 组件,这种组件可以捕获发生在其子组件树任何位置的 JavaScript 错误,并打印这些错误,同时展示降级 UI,而并不会渲染那些发生崩溃的子组件树。

错误边界在渲染期间、生命周期方法和整个组件树的构造函数中捕获错误。

形成错误边界组件的两个条件:

  • 使用了 static getDerivedStateFromError()
  • 使用了 componentDidCatch()
    抛出错误后,请使用 static getDerivedStateFromError() 渲染备用 UI ,使用 componentDidCatch() 打印错误信息,如下:
js 复制代码
class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // 更新 state 使下一次渲染能够显示降级后的 UI
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    // 你同样可以将错误日志上报给服务器
    logErrorToMyService(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      // 你可以自定义降级后的 UI 并渲染
      return <h1>Something went wrong.</h1>;
    }

    return this.props.children; 
  }
}

然后就可以把自身组件的作为错误边界的子组件,如下:

js 复制代码
<ErrorBoundary>
  <MyWidget />
</ErrorBoundary>

下面这些情况无法捕获到异常:

  • 事件处理
  • 异步代码
  • 服务端渲染
  • 自身抛出来的错误
    在react 16版本之后,会把渲染期间发生的所有错误打印到控制台
    除了错误信息和 JavaScript 栈外,React 16 还提供了组件栈追踪。现在你可以准确地查看发生在组件树内的错误信息:

3. 说说你对immutable的理解?如何应用在react项目中?

Immutable 是一种函数式编程的概念,指的是数据不可变性。在 Immutable 数据结构中,一旦创建了一个对象,就无法修改该对象的值,而只能创建一个新的对象。

在 React 项目中,Immutable 数据结构可以用于管理组件的状态,以避免直接修改状态而引起的副作用问题。使用 Immutable 数据结构可以保证状态的不可变性,从而避免在更新状态时不小心修改了原有状态的值。

在 React 项目中,可以使用一些第三方库来实现 Immutable 数据结构,例如 Immutable.js 和 immer 等。这些库提供了许多函数和方法,用于创建和操作不可变的数据结构,如 List、Map、Set 等。在使用这些库时,需要注意避免直接修改状态,而是通过创建新的不可变对象来更新状态。

下面是一个使用 Immutable.js 的示例:

js 复制代码
import { Map } from 'immutable';

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

    this.state = {
      data: Map({
        name: 'Tom',
        age: 20,
        hobbies: ['reading', 'running'],
      }),
    };
  }

  handleDataChange = () => {
    // 使用 set 方法创建新的 Map 对象更新数据
    const newData = this.state.data.set('age', 21);
    this.setState({
      data: newData,
    });
  }

  render() {
    const { name, age, hobbies } = this.state.data.toObject();
    return (
      <div>
        <p>{name}</p>
        <p>{age}</p>
        <ul>
          {hobbies.map(hobby => <li key={hobby}>{hobby}</li>)}
        </ul>
        <button onClick={this.handleDataChange}>Change Age</button>
      </div>
    );
  }
}

在上述示例中,我们使用 Immutable.js 的 Map 数据结构来管理组件的状态。在构造函数中,我们使用 Map 创建了一个包含名字、年龄和爱好的 Map 对象,并将其存储在组件的状态中。在 handleDataChange 方法中,我们使用 set 方法创建了一个新的 Map 对象,更新了年龄的值。最后,我们使用 setState 方法将新的数据存储到组件的状态中,并在 render 方法中显示出来。

使用方法扩展

  • fromJS():将一个js数据转换为Immutable类型的数据
js 复制代码
const obj = Immutable.fromJS({a:'123',b:'234'})
  • toJS():将一个Immutable数据转换为JS类型的数据
  • is():对两个对象进行比较
js 复制代码
import { Map, is } from 'immutable'
const map1 = Map({ a: 1, b: 1, c: 1 })
const map2 = Map({ a: 1, b: 1, c: 1 })
map1 === map2   //false
Object.is(map1, map2) // false
is(map1, map2) // true
  • get(key):对数据或对象取值

  • getIn([]) :对嵌套对象或数组取值,传参为数组,表示位置

js 复制代码
let abs = Immutable.fromJS({a: {b:2}});
abs.getIn(['a', 'b']) // 2
abs.getIn(['a', 'c']) // 子级没有值

let arr = Immutable.fromJS([1 ,2, 3, {a: 5}]);
arr.getIn([3, 'a']); // 5
arr.getIn([3, 'c']); // 子级没有值

在React中应用

使用 Immutable 可以给 React 应用带来性能的优化,主要体现在减少渲染的次数

在做react性能优化的时候,为了避免重复渲染,我们会在shouldComponentUpdate()中做对比,当返回true执行render方法

Immutable通过is方法则可以完成对比,而无需像一样通过深度比较的方式比较

在使用redux过程中也可以结合Immutable,不使用Immutable前修改一个数据需要做一个深拷贝

js 复制代码
import '_' from 'lodash';

const Component = React.createClass({
  getInitialState() {
    return {
      data: { times: 0 }
    }
  },
  handleAdd() {
    let data = _.cloneDeep(this.state.data);
    data.times = data.times + 1;
    this.setState({ data: data });
  }
}

使用 Immutable 后:

js 复制代码
getInitialState() {
  return {
    data: Map({ times: 0 })
  }
},
  handleAdd() {
    this.setState({ data: this.state.data.update('times', v => v + 1) });
    // 这时的 times 并不会改变
    console.log(this.state.data.get('times'));
  }

同理,在redux中也可以将数据进行fromJS处理

js 复制代码
import * as constants from './constants'
import {fromJS} from 'immutable'
const defaultState = fromJS({ //将数据转化成immutable数据
    home:true,
    focused:false,
    mouseIn:false,
    list:[],
    page:1,
    totalPage:1
})
export default(state=defaultState,action)=>{
    switch(action.type){
        case constants.SEARCH_FOCUS:
            return state.set('focused',true) //更改immutable数据
        case constants.CHANGE_HOME_ACTIVE:
            return state.set('home',action.value)
        case constants.SEARCH_BLUR:
            return state.set('focused',false)
        case constants.CHANGE_LIST:
            // return state.set('list',action.data).set('totalPage',action.totalPage)
            //merge效率更高,执行一次改变多个数据
            return state.merge({
                list:action.data,
                totalPage:action.totalPage
            })
        case constants.MOUSE_ENTER:
            return state.set('mouseIn',true)
        case constants.MOUSE_LEAVE:
            return state.set('mouseIn',false)
        case constants.CHANGE_PAGE:
            return state.set('page',action.page)
        default:
            return state
    }
}

4. 说说react中引入css的方式有哪几种?区别?

在 React 中,引入 CSS 样式的方式有以下几种:

  1. 在 JSX 中直接使用样式对象:可以在 JSX 中直接使用样式对象,将样式属性作为对象的属性,例如:
js 复制代码
const styles = {
  container: {
    background: '#eee',
    padding: '10px',
  },
  title: {
    fontWeight: 'bold',
    fontSize: '18px',
  },
};

function MyComponent() {
  return (
    <div style={styles.container}>
      <h1 style={styles.title}>Hello, world!</h1>
    </div>
  );
}

这种方式的优点是方便快捷,不需要额外的工具和库,适用于简单的样式需求。缺点是样式和组件混杂在一起,不够模块化和可维护。

  1. 使用 CSS 模块:CSS 模块是一种使用 CSS 的方式,可以将 CSS 样式模块化,使得样式和组件可以分离。在 React 中,可以使用 css-loader 和 style-loader 这两个 Loader,将 CSS 样式文件转换成模块,例如:
  1. 创建一个 CSS 样式文件 styles.module.css:
css 复制代码
.container {
  background: #eee;
  padding: 10px;
}

.title {
  font-weight: bold;
  font-size: 18px;
}
  1. 在组件中引用 CSS 文件并使用 CSS 模块:
js 复制代码
import styles from './styles.module.css';

function MyComponent() {
  return (
    <div className={styles.container}>
      <h1 className={styles.title}>Hello, world!</h1>
    </div>
  );
}

这种方式的优点是可以将样式和组件分离,使得组件更加模块化和可维护。缺点是需要额外的工具和库,并且需要注意类名的命名,以避免类名重复的问题。

  1. 使用 CSS 预处理器:CSS 预处理器是一种使用类似编程语言的方式来编写 CSS 的工具,例如 Sass、Less 等。在 React 中,可以使用 node-sass 和 less-loader 等工具来预处理 CSS,例如:
js 复制代码
import './styles.scss';

function MyComponent() {
  return (
    <div className="container">
      <h1 className="title">Hello, world!</h1>
    </div>
  );
}

这种方式的优点是可以使用类似编程语言的方式来编写 CSS,使得样式更加灵活和易于维护。缺点是需要额外的工具和库,并且需要学习预处理器的语法和特性。

5. state 和 props有什么区别?

在 React 中,组件的状态可以通过 state 和 props 来管理,它们的区别如下:

  1. 定义:state 是组件内部的状态,需要通过 setState 方法来修改;而 props 是由父组件传递给子组件的属性,是只读的。

  2. 来源:state 是组件自己管理的状态,可以在组件内部初始化和修改;而 props 是由父组件传递给子组件的属性,在组件外部进行初始化和传递。

  3. 生命周期: state 可以在组件的生命周期中被修改,从而触发组件的重新渲染;而 props 在组件渲染之后就不会再被修改了。因为 React 鼓励单向数据流的思想,即数据只能从父组件传递给子组件,子组件不能直接修改传递过来的数据,只能通过调用父组件传递的方法来修改数据。

  4. 作用:state 和 props 都用于管理组件的状态,但是 state 通常用于管理组件的内部状态,而 props 通常用于传递数据和方法,使得组件可以与父组件和其他组件进行交互。

综上所述,state 和 props 是 React 组件中用于管理组件状态的两个重要机制。它们的区别在于定义、来源、生命周期和作用等方面,开发人员需要根据具体的场景和需求来选择合适的方式。

相关推荐
FØund40433 分钟前
antd form.setFieldsValue问题总结
前端·react.js·typescript·html
疯狂的沙粒1 小时前
如何在 React 项目中应用 TypeScript?应该注意那些点?结合实际项目示例及代码进行讲解!
react.js·typescript
鑫宝Code2 小时前
【React】React Router:深入理解前端路由的工作原理
前端·react.js·前端框架
沉默璇年11 小时前
react中useMemo的使用场景
前端·react.js·前端框架
2401_8827275711 小时前
BY组态-低代码web可视化组件
前端·后端·物联网·低代码·数学建模·前端框架
红绿鲤鱼13 小时前
React-自定义Hook与逻辑共享
前端·react.js·前端框架
loey_ln15 小时前
FIber + webWorker
javascript·react.js
zhenryx15 小时前
前端-react(class组件和Hooks)
前端·react.js·前端框架
Thomas游戏开发16 小时前
Unity3D 逻辑服的Entity, ComponentData与System划分详解
前端框架·unity3d·游戏开发
老码沉思录19 小时前
React Native 全栈开发实战班 - 性能与调试之打包与发布
javascript·react native·react.js