请勿执行的操做以及如何解决的方法,这部份内容是针对React的新手开发人员提供的。javascript
考虑一下这段代码,它建立一个简单的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
解决方法很简单,大写您的组件。浏览器
要访问由父组件传入的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被传递到您的组件中,并相应地访问它们。这将在调试期间为您节省一些没必要要的麻烦。
若是所接收的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的 ChildComponent
:showIntro
和 showBody
。它显示“你好!和“发现错误!”只有当showIntro
和 showBody
分别设置为 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'}
会致使无心中为 showIntro
和 showBody
分配了一个值为 false
的字符串,而不是布尔值 false
。
对于前两个 ChildComponent
,将 showIntro
和 showBody
都计算为 true
。
这是因为 &&
运算符的隐式强制类型转换。当 &&
运算符检查 showIntro
或 showBody
(均为字符串)时,两个字符串都将强制为 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表达式嵌入属性中时,请勿在大括号周围加上引号。您应该使用引号(用于字符串值)或大括号(用于表达式),但不要在同一属性中都使用引号。
下图无限循环错误消息
尽管您的组件中没有 componentWillUpdate()
或 componentWillUpdate()
,您仍可能遇到此错误。当您在 render()
函数中调用 setState()
时也会发生此错误。
为何会这样?每次调用 setState()
时,React将经过调用 render()
从新渲染。您的 render()
函数内部是什么? setState()
。你看到结果了吗?一个无限循环。
只需将 setState()
调用移到 render()
函数以外便可。
若是在组件挂载后必须初始化状态(也许是从API端点提取数据),请在 componentDidMoun()
中进行。
若是能够在组件挂载以前初始化状态,也可使用构造函数来完成。
在调试时,一般使用 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()
提供同步行为。
文章首发《前端外文精选》微信公众号
继续阅读其余高赞文章