让我们来比较一下道具和状态。这里有一个各自的定义:
- "props"("属性 "的简称)是React函数组件接受的第一个参数的任意输入对象。
- "state "是指在React组件的特定实例的生命周期内发生变化的数据。
让我们深入了解每一个。
Props
把props看作是一个函数的参数。React组件是返回JSX的函数(或更普遍的可渲染的东西,如React元素,null ,一个字符串,等等)。通常情况下,当你有一段你想重用的代码时,你可以将该代码放入一个函数中,并且该代码之前使用的任何动态值都可以作为参数被接受(例如,const five = 2 + 3 可以被提取到一个函数中并接受参数,像这样const five = add(2, 3) )。
一段JSX也是如此,只是你没有像普通函数那样调用它(add(2, 3)),而是使用JSX语法(<Add n1={2} n2={3} />)。JSX中提供的 "属性 "就是所谓的props ,它们被放在一个对象中,并作为第一个参数传递给Add 组件函数,就像这样:
function Add(props) {
return (
<div>
{props.n1} + {props.n2} = {props.n1 + props.n2}
</div>
)
}
如果我像这样使用它:
<Add n1={2} n2={3} />
这里是如何呈现的。
注意:道具可以是任何东西。在我们的例子中,它们是数字,但它们也可以是(而且经常是)字符串、数组、对象、函数等。
比方说,我们想把n2 默认为0 ,以防有人不提供它(如<Add n1={2} /> )。**道具的一个限制是,你不允许改变它们。**所以你不能做这样的事情:
function Add(props) {
if (typeof props.n2 === 'undefined') {
props.n2 = 0
}
return (
<div>
{props.n1} + {props.n2} = {props.n1 + props.n2}
</div>
)
}
如果我们试图这样做,我们会得到以下错误:
TypeError: Cannot add property n2, object is not extensible
不过这很简单,可以解决:
function Add(props) {
let n2 = props.n2
if (typeof n2 === 'undefined') {
n2 = 0
}
return (
<div>
{props.n1} + {n2} = {props.n1 + n2}
</div>
)
}
或者,你会发现人们经常使用带有默认值的析构语法(这是我个人的偏好)。
function Add({n1, n2 = 0}) {
return (
<div>
{n1} + {n2} = {n1 + n2}
</div>
)
}
这很好,但如果我想动态地改变道具值呢?比方说,我想建立这样的东西。
在没有状态的情况下,这里是我可能尝试完成的方式。
function AddWithInput(props) {
function handleInputChange(event) {
const input = event.target
const newN2 = Number(input.value)
props.n2 = newN2
}
return (
<div>
{props.n1} +{' '}
<input type="number" value={props.n2} onChange={handleInputChange} /> ={' '}
{props.n1 + props.n2}
</div>
)
}
然而,由于两个原因,这将无法工作:
- React不知道我们已经更新了我们的
props对象的n2值,所以当我们改变props.n2时,它不会更新DOM,所以我们无论如何都不会看到我们的改变。 - 我们会像以前一样收到
TypeError的警告。
这就是状态的作用。
状态
状态是随时间变化的数据,这对我们的情况来说是完美的。
function AddWithInput(props) {
const [n2, setN2] = React.useState(0)
function handleInputChange(event) {
const input = event.target
const newN2 = Number(input.value)
setN2(newN2)
}
return (
<div>
{props.n1} +{' '}
<input type="number" value={n2} onChange={handleInputChange} /> ={' '}
{props.n1 + n2}
</div>
)
}
这将是可行的,这正是React状态的目的所在。它的目的是在组件的生命周期内跟踪数据值(只要该组件存在于页面上)。
然而,AddWithInput 组件的用户不能再设置n2 的初始值了。以该组件目前的实现方式,它根本就没有引用props.n2 。但是,我们可以通过在初始化状态时使用props来使之工作。
function AddWithInput(props) {
const [n2, setN2] = React.useState(props.n2)
// ... etc...
}
现在,如果有人这样做:<AddWithInput n1={2} n2={3} /> ,那么结果会是这样的(注意,初始输入值是3 )。
所以我们的道具是我们可以传递给组件的 "参数 "或 "输入",而状态是组件内部管理的东西,可以随时间变化。
让我把这个组件清理一下,我将解释我的变化。
function AddWithInput({n1, initialN2 = 0}) {
const [n2, setN2] = React.useState(initialN2)
function handleInputChange(event) {
const input = event.target
const newN2 = Number(input.value)
setN2(newN2)
}
return (
<div>
{n1} + <input type="number" value={n2} onChange={handleInputChange} /> ={' '}
{n1 + n2}
</div>
)
}
我把道具改成了带有默认值的析构,我把道具从n2 改成了initialN2 。当我用一个道具值来初始化一个状态值时,我通常喜欢给它加上前缀initial ,以表明这个道具的变化不会被考虑在内。如果这是你想要的,那么你会想把状态抬高。
总结
我希望这能帮助你理清React中道具和状态之间的区别。这是一个基础的概念。来吧,在下面这个小程序上测试一下自己。哪里是状态,哪里是道具?
我希望这对你有帮助!祝你好运