react.js初学者常见问题,老鸟也可能遇到😅

1,851 阅读9分钟
原文链接: www.fragmentwall.com

举个栗子:

class greeting extends React.Component { 
  // ...
}

如果您尝试渲染 ,则React将忽略上述内容,您将收到警告:

Warning: The tag <greeting> is unrecognized in this browser. 
If you meant to render a React component, 
start its name with an uppercase letter.

还有一个更大的问题是当你命名你的组件为buttonimg时,React会忽略你的组件渲染一个原生的html buttonimg

注意上面没有呈现“My Awesome Button”,React只呈现了一个空的HTML按钮元素。 React在这种情况下不会提醒你。

2.使用单引号代替倒引号

用倒引号(`...`)创建的字符串与用单引号('...')创建的字符串不同。

在大多数键盘上,可以使用Tab键上方的键来输入倒引号(`)字符。

当我们需要在该字符串中包含动态表达式时,我们会使用倒引号创建一个字符串(不需要使用字符串连接)。

`这是一个字符串模板文字,可以包含表达式`

'这只是一个字符串,这里不能包含表达式'

假设你想要一个字符串,它显示当前时间: "Time is ..."

// 当前时间
const time = new Date().toLocaleTimeString();

// 当使用常规字符串(单引号或双引号)时,
// 您需要使用字符串连接:
'Time is ' + time

// 使用倒引号时,
// 您可以使用${}在字符串中插入时间
`Time is ${time}`

另外,当使用字符串文本(倒引号)时,您可以创建一个跨越多行的字符串:

const template = `I

CAN

SPAN

Multiple Lines`;

这是不能使用普通字符串做到的

3.使用React.PropTypes

PropTypes对象已从React中删除。它以前可以作为React.PropTypes使用,但是现在你不能再使用它了。

现在需要这样使用:

1. 将新的prop-types包添加到您的项目中:npm install prop-types

2. 导入包:`import PropTypes from 'prop-types'`

然后你可以使用它。例如:PropTypes.string

如果你错误地使用了React.PropTypes,你会得到如下错误:TypeError: Cannot read property 'string' of undefined

4.不使用教程正在使用的版本

当你看到一些教程或视频并跟着他们做DEMO时,请务必确保你正在使用的包或工具版本是正确的。通常,使用每种工具的最新版本是安全的选择,但如果教程有点老,则可能会遇到一些版本问题。

为了安全期间,推荐使用和教程一样的主版本,比如教程使用的是React.js 16那么就不推荐你使用React.js 15

对于Node.js这点很重要,如果使用老版本的Node.js你可能会面临重大问题。例如你跟着一些教程他们使用了Object.values你使用的Node.js 6.x,这个方法就并不存在那么就需要更新到Node.js 7.x

5.疑惑的functionclass

你能告诉我以下代码有什么问题吗?

class Numbers extends React.Component { 
  const arrayOfNumbers = _.range(1, 10);
  // ...
}

上面的代码是无效的,因为在JavaScript类的主体内部,你不能自由地做任何事情。您只能使用有限的语法定义方法和属性。

这有点让人迷惑,因为类语法中使用的{}看起来像普通的块作用域,但事实并非如此。

在基于function组件中,您可以自由地做任何事情:

// 完全可以做任何事情

const Number = (props) => { 
  const arrayOfNumbers = _.range(1, 10);
  // ...
};

6.将数字作为字符串传递

您可以使用字符串传递一个prop值:

<Greeting name="World" />

如果需要传递数值,请不要使用字符串:

// 不要这样做
<Greeting counter="7" />
``

相反,你需要使用大括号将你要传递的数值括起来

```javascript
// 这样做
<Greeting counter={7} />

使用{7}Greeting组件中,this.props.counter将会获得一个数值型的7对于数学运算是安全的。如果你把它当作"7",然后把它当作一个数字运算,你可能会遇到意想不到的结果你懂的。

7.忘记创建环境变量

一些项目依赖于shell环境变量的存在来启动。如果您在不需要环境变量的情况下运行这些项目,它们将尝试为它们使用未定义的值,并可能会给您一些神秘的错误。

例如如果一个项目连接了MongoDB数据库,它可能会使用像process.env.MONGO_URI这样的环境变量来连接它。这使得项目可以在不同的环境中使用不同的MongoDB实例。

在本地运行连接到MongoDB的项目,你必须先导出一个MONGO_URI环境变量。例如,如果您有一个本地MongoDB在27017端口上运行,那么在运行该项目之前您需要执行此操作:

export MONGO_URI = "mongodb://localhost:27017/mydb"

你可以使用grep查看项目源代码找出它需要什么环境变量才能正常工作。

8.混淆花括号{}和圆括号()

不能这样

return { 
  something();
};

应该这样

return ( 
  something();
);

第一个将尝试返回一个对象,而第二个将正确调用something()并且返回该函数返回的内容

因为在JSX中任何 都将转换为函数调用,所以在返回任何JSX时,这个问题都是适用的

这个问题在箭头函数的短语法中也很常见

不能这样

const Greeting = () => { 
  <div> 
    Hello World 
  </div>
};

应该这样

const Greeting = () => ( 
  <div> 
    Hello World 
  </div>
);

9.不用圆括号包装对象

当您想要创建一个返回一个普通对象的短箭头函数时,上面的花括号和括号问题也会令人困惑

不要这样

const myAction = () => { type: 'DO_THIS' };

需要这样

const myAction = () => ({ type: 'DO_THIS'});

不将对象用括号括起来,myAction函数不会得到一个正确的普通对象。

这在setState方法的updater函数中很常见,因为它需要返回一个对象。如果要使用短箭头函数语法,则需要用圆括号包装该对象。

不要这样

this.setState(prevState => { answer: 42 });

需要这样

this.setState(prevState => ({ answer: 42 }));

10.APIprops不使用正确的大小写

它是React.Component不是React.component。它是componentDidMount不是ComponentDidMount。还有ReactDOM不是ReactDom

请注意您需要的API大小写。如果您使用不正确的大写字母,那么您将得到的错误可能无法清楚地说明问题所在。

当从reactreact-dom导入时,确保导入正确的名称,使用的名称与导入的内容完全相同。ESLint可以帮助你指出不正确的地方。

访问组件props时,这个问题也很常见:

<Greeting userName="Max" />

// 在组件内部,你需要这样
props.userName

如果不是props.userName,您错误地使用props.usernameprops.UserName,你会得到undefined值。需要注意这一点,或者更好的方法是,配置您的ESLint让他帮你处理这些问题。

11.混淆state对象和实例属性

在类组件中,您可以定义一个组件state对象,然后使用以下方法访问它:

class Greeting extends React.Component { 
  state = { 
    name: "World", 
  };

  render() { 
    return `Hello ${this.state.name}`;
  }
}

以上将输出“Hello World”

你也可以在定义state附近定义一个实例属性

class Greeting extends React.Component { 
  user = { 
    name: "World", 
  };

  render() { 
    return `Hello ${this.user.name}`;
  }
}

以上也会输出“Hello World”。

state属性是一个特殊的属性,因为React将管理它,你只能通过setState来改变它,而React会在你做这件事时做出对应的反应。但是,您定义的所有其他实例属性都不会影响渲染算法。您可以根据需要在上面的示例中更改this.user,React不会触发渲染周期

12.混淆<tag/></tag>

不要在结束标记中放错/字符。无可否认,有时您可以使用<tag />和其他需要</ tag>

在HTML中,有一种叫做“自闭合标签”,这些是代表没有任何子节点的元素的标签。例如,img标签是一个自闭合标签:

<img src="..." />

// 你不需要使用 <img></img>

一个div标签可以有子元素,所以你会使用开始和结束标签:

<div> 
  Children here...
</div>

这同样适用于React组件。如果组件具有子内容,则可能如下所示:

<Greeting>Hello!</Greeting>

如果组件没有子元素,可以使用自闭合组件

// 下面两种方法都是有效的

<Greeting></Greeting>

<Greeting />

下面使用是无效的

// 错误

<Greeting><Greeting />

如果你放错了/字符,你会得到如下错误:

Syntax error: Unterminated JSX contents

13.不绑定函数作用域

我最后保存了这个,因为这是一个很大的问题,也是一个很常见的问题。

您可以在React组件中定义类方法,然后在组件的render方法中使用它们。例如:

class Greeting extends React.Component { 
  whoIsThis() { 
    console.dir(this); // "this"是whoIsThis的调用者
    return "World"; 
  }

  render() { 
    return `Hello ${this.whoIsThis()}`; 
  }
}

ReactDOM.render(<Greeting />, mountNode);

render方法内部,我使用了this.whoIsThis方法调用了whoIsThis()方法,这个this关键字是指与表示组件的DOM元素相关联的组件实例,也就是Greeting组件

React内部会确保其类方法中的this引用到组件实例,但是当你使用whoIsThis方法的引用时,JavaScript不会自动绑定到组件实例。

console.dir这行中打印出的this会指向组件实例,因为我们是从render方法内部调用的。执行上面的代码时,您应该在控制台中看到Greeting对象:

但是,当您在延迟执行通道中使用相同的方法时,如事件处理程序,调用者将不再明确,并且console.dir行不指向组件实例。

请参阅下面的代码和输出(单击后)

在上面的代码中,当你点击字符串时,React调用whoIsThis方法,但它不会让你访问里面的组件实例。这就是为什么当我们点击字符串时你会得到undefined的原因。如果你的类方法需要访问像this.propsthis.state这样的东西,这是一个问题。它根本无法工作。

对于这个问题,有许多解决方案。您可以将方法封装在内联函数中,或者使用.bind调用来强制方法记住它的调用者。对于不经常更新的组件,两者都可以。您还可以通过在类的构造函数中而不是在render方法中对绑定方法进行优化。但是,此方法的最佳解决方案是通过Babel启用ECMAScript class-fields段功能(仍然是第3阶段),并仅为处理程序使用箭头函数:

class Greeting extends React.Component { 
  whoIsThis = () => { 
    console.dir(this); 
  }

  render() { 
    return ( 
      <div onClick={this.whoIsThis}> 
        Hello World 
      </div> 
    ); 
  }
}

将按预期工作:

目前就是这些了,感谢阅读。