新手React开发人员容易作错的5件事

1_Y4vpCQT5-SSNPGnLKZLFYg.png
请勿执行的操做以及如何解决的方法,这部份内容是针对React的新手开发人员提供的。javascript

1.忘记大写React组件

考虑一下这段代码,它建立一个简单的div,其中包含父组件的标题。里面有一个子组件,其中包含带有一些文本的div。html

class childComponent extends React.Component {
  render() {
    return (
      <div className='childDiv'>
        <p>Child Component</p>
      </div>
    );
  }
}

class ParentComponent extends React.Component {
  render() {
    return (
      <div className='parentDiv'>
        <h1 className='parentHeader'>Parent Component</h1>
        <childComponent />
      </div>
    );
  }
}

export default ParentComponent;

您认为代码运行时会出现什么?前端

childComponent 未渲染。它去哪儿了?代码编译成功,终端也没有错误。java

再次查看子组件的代码。注意组件的名称,你注意到什么不一样了吗?react

在浏览器中打开控制台,浏览器控制台警告的大小写不正确web

事实证实,React将小写组件视为DOM标记。若是你是React的新手,你可能已经错过了React文档中的这个小细节。面试

若是不了解这一点,初学者经常会陷入这样的困惑:即他们的代码编译没有任何错误,到底哪里出了问题?segmentfault

解决方法很简单,大写您的组件。浏览器

2.错误地调用收到的props

要访问由父组件传入的prop,子组件必须确保它们调用了正确的prop名称。安全

还可使用另外一个变量名将Props传递给子组件。考虑如下代码片断:

class ChildComponent extends React.Component {
  render() {
    const { randomString } = this.props;

    return (
      <div className='childDiv'>
        <p>{randomString}</p>
      </div>
    );
  }
}

class ParentComponent extends React.Component {
  render() {
    const randomString = 'lorem ipsum';
    
    return (
      <div className='parentDiv'>
        <h1 className='parentHeader'>Parent Component</h1>
        <ChildComponent mainText={randomString} />
      </div>
    );
  }
}

尽管此代码能够编译并运行无误,但 ChildComponent 内不会渲染任何文本。

<ChildComponent mainText={randomString} />

仔细看看这一行代码,在 ParentComponent 中声明的变量 randomString 做为名为 mainText 的prop传递给 ChildComponent

然而,ChildComponent 试图从它收到的prop中访问 randomString。因为它仅接收 mainText 做为prop,所以将致使未定义的值分配给在 ChildComponent 中声明的 randomString。结果,其 <p>标记内未呈现任何内容。

注意哪些prop被传递到您的组件中,并相应地访问它们。这将在调试期间为您节省一些没必要要的麻烦。

3.传递不正确的Props类型

若是所接收的prop不是预期的类型,那么依赖于这些接收prop的组件可能会有不一样的行为。

class ChildComponent extends React.Component {
  render() {
    const { showIntro, showBody } = this.props;

    return (
      <div className='childDiv'>
        {showIntro && <p>Hello!</p>}
        {showBody && <p>Spot the mistake!</p>}
      </div>
    );
  }
}

考虑这个有两个prop的 ChildComponentshowIntroshowBody。它显示“你好!和“发现错误!”只有当showIntroshowBody 分别设置为 true 时才会这样。

ChildComponent 但愿将两个布尔值做为prop传递。若是在父组件中执行相似的操做,会发生什么状况?

<ChildComponent showIntro='false' showBody='false' />
<ChildComponent showIntro={'false'} showBody={'false'} />
<ChildComponent showIntro={false} showBody={false} />

在prop中使用了不一样的引号和大括号。可是,它们的行为将不一样。看看这个:

前两个 ChildComponent 都渲染了两个 <p> 标记,而最后一个 ChildComponent 没有渲染。

做为prop传递的 'false'{'false'} 会致使无心中为 showIntroshowBody 分配了一个值为 false 的字符串,而不是布尔值 false

对于前两个 ChildComponent,将 showIntroshowBody 都计算为 true

这是因为 && 运算符的隐式强制类型转换。当 && 运算符检查 showIntroshowBody(均为字符串)时,两个字符串都将强制为 true

最后一个 ChildComponent 接收到布尔值 false,所以它没有正确渲染任何内容。

console.log(`showIntro type: ${typeof showIntro}`);
console.log(`showIntro evaluated to: ${showIntro && true}`);
console.log(`showBody type: ${typeof showBody}`);
console.log(`showBody evaluated to: ${showBody && true}`);

为了确认这一点,咱们运行 console.log() 来检查每一个 ChildComponent 中prop的运行结果。

正如这里所演示的,初学者在将prop传递给其余组件时可以区分使用引号和花括号之间的区别是很是重要的。

您可使用引号来传递字符串文字。

<MyComponent data='Hello World!'/> // passing in a String

花括号用于传递JavaScript表达式。

<MyComponent data={2468} /> // passing in a Number
<MyComponent data={true} /> // passing in a Boolean

如下是Reac文档中的一些注意事项:

将JavaScript表达式嵌入属性中时,请勿在大括号周围加上引号。您应该使用引号(用于字符串值)或大括号(用于表达式),但不要在同一属性中都使用引号。

4.在render()内部调用setState()

下图无限循环错误消息

尽管您的组件中没有 componentWillUpdate()componentWillUpdate(),您仍可能遇到此错误。当您在 render() 函数中调用 setState() 时也会发生此错误。

为何会这样?每次调用 setState() 时,React将经过调用 render() 从新渲染。您的 render() 函数内部是什么? setState()。你看到结果了吗?一个无限循环。

只需将 setState() 调用移到 render() 函数以外便可。

若是在组件挂载后必须初始化状态(也许是从API端点提取数据),请在 componentDidMoun() 中进行。

若是能够在组件挂载以前初始化状态,也可使用构造函数来完成。

5.setState()的异步性

在调试时,一般使用 console.log() 打印值。可是,当代码异步运行时,这不能很好地工做。

handleCounterIncrement = () => {
  const { counter } = this.state;
  console.log(`Before update: ${counter}`);
  this.setState({ counter: counter + 1 });
  console.log(`After update: ${counter}`);
};

你之前试过这样作吗?坏消息——setState() 调用是异步的。不能保证给定的代码将按顺序执行。它可能致使以下输出:

在执行 setState() 以前执行了两个 console.log() 调用。所以,它两次打印前一个状态的值。

若是但愿在调用 setState() 以前和以后检查状态的值,请在 setState() 中将回调做为第二个参数传递。

handleCounterIncrement = () => {
  const { counter } = this.state;
  console.log(`before update: ${counter}`);
  this.setState({ counter: counter + 1 }, () => {
      console.log(`after update: ${this.state.counter}`);
  });
};

回调将在 setState() 完成后执行,从而为 console.log() 提供同步行为。


文章首发《前端外文精选》微信公众号

1.png

继续阅读其余高赞文章


相关文章
相关标签/搜索