我正在观看关于 React 的 Pluralsight 课程,讲师说不应更改道具。我现在正在阅读关于道具与状态的an article (uberVU/react-guide),它说
道具和状态更改都会触发渲染更新。
文章后面说:
Props(properties 的缩写)是一个组件的配置,如果可以的话,它是它的选项。它们是从上面接收的并且是不可变的。
所以道具可以改变,但它们应该是不可变的?
什么时候应该使用道具,什么时候应该使用状态?
如果你有 React 组件需要的数据,是应该通过 props 传递还是通过 getInitialState 在 React 组件中设置?
道具和状态是相关的。一个组件的状态往往会成为子组件的 props。道具在父级的渲染方法中作为 React.createElement()
的第二个参数传递给子级,或者,如果您使用 JSX,则更熟悉的标记属性。
<MyChild name={this.state.childsName} />
父级的状态值 childsName
变为子级的 this.props.name
。从孩子的角度来看,名称道具是不可变的。如果需要更改,父级应该只更改其内部状态:
this.setState({ childsName: 'New name' });
React 会为你将它传播给孩子。一个自然的后续问题是:如果孩子需要更改其名称道具怎么办?这通常通过子事件和父回调来完成。孩子可能会公开一个名为 onNameChanged
的事件。然后,父级将通过传递回调处理程序来订阅事件。
<MyChild name={this.state.childsName} onNameChanged={this.handleName} />
子进程将通过调用(例如,this.props.onNameChanged('New name')
)将其请求的新名称作为参数传递给事件回调,而父进程将使用事件处理程序中的名称来更新其状态。
handleName: function(newName) {
this.setState({ childsName: newName });
}
亲子交流,简单的传递props。
使用状态将当前页面需要的数据存储在控制器视图中。
使用道具将数据和事件处理程序向下传递给您的子组件。
在处理组件中的数据时,这些列表应有助于指导您。
道具
是不可变的,这让 React 可以进行快速的引用检查
这让 React 可以进行快速的参考检查
用于从您的视图控制器向您的顶级组件传递数据
你的顶级组件
具有更好的性能使用它来将数据传递给子组件
使用它来将数据传递给子组件
状态
应该在您的视图控制器中管理您的顶级组件
你的顶级组件
是可变的
表现更差
不应从子组件访问,而是使用 props 传递它
用道具传下去
对于没有父子关系的两个组件之间的通信,可以设置自己的全局事件系统。在 componentDidMount() 中订阅事件,在 componentWillUnmount() 中取消订阅,并在收到事件时调用 setState()。通量模式是安排这一点的可能方式之一。 - https://facebook.github.io/react/tips/communicate-between-components.html 哪些组件应该有状态?大多数组件应该简单地从道具中获取一些数据并渲染它。但是,有时您需要响应用户输入、服务器请求或时间的流逝。为此,您使用状态。尽量保持尽可能多的组件无状态。通过这样做,您可以将状态隔离到其最合乎逻辑的位置并最大限度地减少冗余,从而更容易推理您的应用程序。一种常见的模式是创建几个仅渲染数据的无状态组件,并在层次结构中在它们之上有一个有状态组件,通过 props 将其状态传递给其子级。有状态组件封装了所有的交互逻辑,而无状态组件则以声明的方式处理数据。 - https://facebook.github.io/react/docs/interactivity-and-dynamic-uis.html#what-components-should-have-state 状态应该怎样?状态应包含组件的事件处理程序可能更改以触发 UI 更新的数据。在实际应用程序中,这些数据往往非常小并且可以进行 JSON 序列化。在构建有状态组件时,请考虑其状态的最小可能表示形式,并且仅将这些属性存储在 this.state 中。在 render() 内部,只需根据此状态计算您需要的任何其他信息。你会发现以这种方式思考和编写应用程序往往会导致最正确的应用程序,因为向状态添加冗余或计算值意味着你需要显式地保持它们同步,而不是依赖 React 为你计算它们。 - https://facebook.github.io/react/docs/interactivity-and-dynamic-uis.html#what-should-go-in-state
您可以通过将其与普通 JS 函数相关联来更好地理解它。
简单的说,
状态是组件的本地状态,不能在组件外部访问和修改。它相当于函数中的局部变量。
纯 JS 函数
const DummyFunction = () => {
let name = 'Manoj';
console.log(`Hey ${name}`)
}
反应组件
class DummyComponent extends React.Component {
state = {
name: 'Manoj'
}
render() {
return <div>Hello {this.state.name}</div>;
}
另一方面,Props 通过使组件能够以 props 的形式从其父组件接收数据,从而使组件可重用。它们等价于函数参数。
纯 JS 函数
const DummyFunction = (name) => {
console.log(`Hey ${name}`)
}
// when using the function
DummyFunction('Manoj');
DummyFunction('Ajay');
反应组件
class DummyComponent extends React.Component {
render() {
return <div>Hello {this.props.name}</div>;
}
}
// when using the component
<DummyComponent name="Manoj" />
<DummyComponent name="Ajay" />
文章链接:React State vs Props explained
我最喜欢的道具与状态摘要在这里:react-guide给那些家伙的大帽子。以下是该页面的编辑版本:
道具与状态
tl;dr 如果组件需要在某个时间点更改其属性之一,则该属性应该是其状态的一部分,否则它应该只是该组件的道具。
道具
道具(属性的缩写)是组件的配置。它们是从上面接收的,并且就接收它们的组件而言是不可变的。一个组件不能改变它的 props,但是它负责把它的子组件的 props 放在一起。道具不必只是数据——回调函数可以作为道具传入。
状态
状态是一个数据结构,当一个组件挂载时,它以一个默认值开始。它可能会随着时间而发生变化,主要是由于用户事件。
组件在内部管理自己的状态。除了设置初始状态外,它没有任何事情摆弄其子节点的状态。您可以将状态概念化为该组件的私有状态。
改变道具和状态
props state Can get initial value from parent Component? Yes Yes Can be changed by parent Component? Yes No Can set default values inside Component?* Yes Yes Can change inside Component? No Yes Can set initial value for child Components? Yes Yes Can change in child Components? Yes No
请注意,从父级接收的 props 和 state 初始值都会覆盖组件内定义的默认值。
这个组件应该有状态吗?
状态是可选的。由于状态增加了复杂性并降低了可预测性,因此最好使用没有状态的组件。即使您显然不能在交互式应用程序中没有状态,您也应该避免使用过多的有状态组件。
组件类型
无状态组件只有道具,没有状态。除了 render() 函数之外,没有太多事情发生。他们的逻辑围绕着他们收到的道具。这使得它们很容易遵循和测试。
有状态的组件 props 和 state。当您的组件必须保留某些状态时使用这些。这是客户端-服务器通信(XHR、Web 套接字等)、处理数据和响应用户事件的好地方。这些物流应该封装在适量的有状态组件中,而所有可视化和格式化逻辑都应该向下移动到许多无状态组件中。
来源
关于“道具”和“状态”的问题 - Google 网上论坛
在 React 中思考:确定你的状态应该在哪里
props(“properties”的缩写)和 state 都是纯 JavaScript 对象。虽然两者都保存影响渲染输出的信息,但它们在一个重要方面有所不同:props 被传递给组件(类似于函数参数),而状态是在组件内管理的(类似于在函数中声明的变量)。
因此,状态仅限于您当前的组件,但道具可以传递给您希望的任何组件...您可以将当前组件的状态作为道具传递给其他组件...
同样在 React 中,我们有无状态组件,它们只有 props 而没有内部状态......
下面的示例展示了它们在您的应用中的工作方式:
父级(状态完整组件):
class SuperClock extends React.Component {
constructor(props) {
super(props);
this.state = {name: "Alireza", date: new Date().toLocaleTimeString()};
}
render() {
return (
<div>
<Clock name={this.state.name} date={this.state.date} />
</div>
);
}
}
孩子(无状态组件):
const Clock = ({name}, {date}) => (
<div>
<h1>{`Hi ${name}`}.</h1>
<h2>{`It is ${date}`}.</h2>
</div>
);
props 和 state 之间的主要区别在于 state 是内部的,由组件本身控制,而 props 是外部的,由渲染组件的任何东西控制。
function A(props) {
return <h1>{props.message}</h1>
}
render(<A message=”hello” />,document.getElementById(“root”));
class A extends React.Component{
constructor(props) {
super(props)
this.state={data:"Sample Data"}
}
render() {
return(<h2>Class State data: {this.state.data}</h2>)
}
}
render(<A />, document.getElementById("root"));
https://i.stack.imgur.com/wqvF2.png
状态可以改变(可变)
而道具不能(不可变)
基本上,区别在于 state 类似于 OOP 中的属性 :它是类(组件)的 local ),用来更好地描述它。 Props 类似于参数 - 它们从组件的调用者(父组件)传递到组件) : 就好像你用某些参数调用了一个函数。
React 中的 state 和 props 都是用来控制数据进入组件的,一般 props 由父组件设置并传递给子组件,并且它们在整个组件中是固定的。对于将要发生变化的数据,我们必须使用状态。并且 props 是不可变的,而 state 是可变的,如果你想改变 props,你可以从父组件做,然后将它传递给子组件。
Props :Props 只不过是组件的属性,而 React 组件只不过是一个 javascript 函数。
class Welcome extends React.Component {
render() {
return <h1>Hello {this.props.name}</h1>;
}
}
常量元素 = ;
这里 <Welcome name="Sara" />
传递一个对象 {name : 'Sara'} 作为 Welcome 组件的 props。要将数据从一个父组件传递到子组件,我们使用道具。道具是不可变的。在组件的生命周期中,道具不应更改(认为它们是不可变的)。
状态:状态只能在组件内访问。为了跟踪组件内的数据,我们使用状态。我们可以通过 setState 改变状态。如果我们需要将状态传递给孩子,我们必须将其作为道具传递。
class Button extends React.Component {
constructor() {
super();
this.state = {
count: 0,
};
}
updateCount() {
this.setState((prevState, props) => {
return { count: prevState.count + 1 }
});
}
render() {
return (<button
onClick={() => this.updateCount()}
>
Clicked {this.state.count} times
</button>);
}
}
正如我在使用 react 时了解到的那样。
组件使用 props 从外部环境获取数据,即另一个组件(纯、函数或类)或通用类或 javascript/typescript 代码
状态用于管理组件的内部环境,意味着组件内部的数据变化
状态:
状态是可变的。状态与单个组件相关联,不能被其他组件使用。状态在组件安装时初始化。状态用于渲染组件内的动态变化。
道具:
道具是不可变的。您可以在组件之间传递道具。 props 主要用于组件之间的通信。您可以直接从父级传递给子级。为了从孩子传递给父母,您需要使用提升状态的概念。
类父扩展 React.Component{ render() { return(
state - 它是一个特殊的可变属性,用于保存组件数据。 Componet 挂载时具有默认值。
props - 它是一种特殊属性,本质上是不可变的,用于从父级到子级的值传递。 props 只是组件之间的沟通渠道,总是从顶部(父)移动到底部(子)。
以下是结合状态和道具的完整示例:-
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>state&props example</title>
<script src="https://unpkg.com/react@0.14.8/dist/react.min.js"></script>
<script src="https://unpkg.com/react-dom@0.14.8/dist/react-dom.min.js"></script>
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
var TodoList = React.createClass({
render(){
return <div className='tacos-list'>
{
this.props.list.map( ( todo, index ) => {
return <p key={ `taco-${ index }` }>{ todo }</p>;
})}
</div>;
}
});
var Todo = React.createClass({
getInitialState(){
return {
list : [ 'Banana', 'Apple', 'Beans' ]
}
},
handleReverse(){
this.setState({list : this.state.list.reverse()});
},
render(){
return <div className='parent-component'>
<h3 onClick={this.handleReverse}>List of todo:</h3>
<TodoList list={ this.state.list } />
</div>;
}
});
ReactDOM.render(
<Todo/>,
document.getElementById('root')
);
</script>
</body>
</html>
Props:表示“只读”数据,它们是不可变的,并且引用父组件的属性。
状态:表示可变数据,最终影响页面上呈现的内容并由组件本身在内部管理,并且通常由于用户输入而超时更改。
基本上,props 和 state 是组件可以知道渲染什么以及如何渲染的两种方式。应用程序状态的哪一部分属于状态,哪一部分属于某个顶级商店,与您的应用程序设计更相关,而不是与 React 的工作方式有关。 IMO,最简单的决定方法是考虑这个特定的数据是否对整个应用程序有用,或者它是一些本地信息。此外,重要的是不要重复状态,因此如果可以从 props 计算某些数据 - 它应该从 props 计算。
例如,假设您有一些下拉控件(它包含用于自定义样式的标准 HTML 选择),它可以 a)从列表中选择一些值,并且 b)打开或关闭(即显示或隐藏选项列表)。现在,假设您的应用程序显示某种项目的列表,并且您的下拉控件过滤列表条目。然后,最好将活动过滤器值作为道具传递,并保持本地打开/关闭状态。此外,为了使其正常工作,您将从父组件传递一个 onChange 处理程序,该处理程序将在下拉元素内部调用并立即将更新信息(新选择的过滤器)发送到商店。另一方面,打开/关闭状态可以保留在下拉组件中,因为应用程序的其余部分并不真正关心控件是否打开,直到用户实际更改它的值。
以下代码不完全工作,它需要 css 和处理下拉单击/模糊/更改事件,但我想保持示例最小化。希望它有助于理解差异。
const _store = {
items: [
{ id: 1, label: 'One' },
{ id: 2, label: 'Two' },
{ id: 3, label: 'Three', new: true },
{ id: 4, label: 'Four', new: true },
{ id: 5, label: 'Five', important: true },
{ id: 6, label: 'Six' },
{ id: 7, label: 'Seven', important: true },
],
activeFilter: 'important',
possibleFilters: [
{ key: 'all', label: 'All' },
{ key: 'new', label: 'New' },
{ key: 'important', label: 'Important' }
]
}
function getFilteredItems(items, filter) {
switch (filter) {
case 'all':
return items;
case 'new':
return items.filter(function(item) { return Boolean(item.new); });
case 'important':
return items.filter(function(item) { return Boolean(item.important); });
default:
return items;
}
}
const App = React.createClass({
render: function() {
return (
<div>
My list:
<ItemList items={this.props.listItems} />
<div>
<Dropdown
onFilterChange={function(e) {
_store.activeFilter = e.currentTarget.value;
console.log(_store); // in real life, some action would be dispatched here
}}
filterOptions={this.props.filterOptions}
value={this.props.activeFilter}
/>
</div>
</div>
);
}
});
const ItemList = React.createClass({
render: function() {
return (
<div>
{this.props.items.map(function(item) {
return <div key={item.id}>{item.id}: {item.label}</div>;
})}
</div>
);
}
});
const Dropdown = React.createClass({
getInitialState: function() {
return {
isOpen: false
};
},
render: function() {
return (
<div>
<select
className="hidden-select"
onChange={this.props.onFilterChange}
value={this.props.value}>
{this.props.filterOptions.map(function(option) {
return <option value={option.key} key={option.key}>{option.label}</option>
})}
</select>
<div className={'custom-select' + (this.state.isOpen ? ' open' : '')} onClick={this.onClick}>
<div className="selected-value">{this.props.activeFilter}</div>
{this.props.filterOptions.map(function(option) {
return <div data-value={option.key} key={option.key}>{option.label}</div>
})}
</div>
</div>
);
},
onClick: function(e) {
this.setState({
isOpen: !this.state.isOpen
});
}
});
ReactDOM.render(
<App
listItems={getFilteredItems(_store.items, _store.activeFilter)}
filterOptions={_store.possibleFilters}
activeFilter={_store.activeFilter}
/>,
document.getElementById('root')
);
状态是 react 处理组件持有的信息的方式。
假设您有一个组件需要从服务器获取一些数据。您通常希望通知用户请求是否正在处理、是否失败等。这是一条仅与该特定组件相关的信息。这是状态进入游戏的地方。
通常定义状态的最佳方式如下:
class MyComponent extends React.Component {
constructor() {
super();
this.state = { key1: value1, key2: value2 }
}
}
但是在 react native 的最新实现中,您可以这样做:
class MyComponent extends React.Component {
state = { key1: value1, key2: value2 }
}
这两个示例以完全相同的方式执行,只是语法改进。
那么,与我们在 OO 编程中一直使用的对象属性有什么不同呢?通常,您的状态中保存的信息并不意味着是静态的,它会随着时间而变化,您的视图需要更新以反映这种变化。 State 以一种简单的方式提供了这个功能。
状态是不可变的!我不能对此做出足够的强调。这是什么意思?这意味着你永远不应该做这样的事情。
state.key2 = newValue;
正确的做法是:
this.setState({ key2: newValue });
使用 this.setState 您的组件会在更新周期中运行,如果状态的任何部分发生更改,您的组件渲染方法将再次调用以反映此更改。
查看反应文档以获得更详细的解释:https://facebook.github.io/react/docs/state-and-lifecycle.html
道具只是属性的简写。 Props 是组件之间的通信方式。如果您完全熟悉 React,那么您应该知道 props 从父组件向下流动。
还有一种情况是你可以有默认的 props,这样即使父组件没有传递 props 也可以设置 props。
这就是为什么人们将 React 称为具有单向数据流的原因。这需要一些时间,我稍后可能会在博客上讨论这个问题,但现在请记住:数据从父级流向子级。道具是不可变的(花哨的词不会改变)
所以我们很高兴。组件从父级接收数据。都整理好了,对吧?
嗯,不完全是。当组件从父级以外的其他人那里接收数据时会发生什么?如果用户直接向组件输入数据怎么办?
好吧,这就是我们有状态的原因。
状态
道具不应该改变,所以状态会增加。通常组件没有状态,因此被称为无状态。使用状态的组件称为有状态的。随意在聚会上丢掉那个小花絮,看着人们远离你。
因此使用状态,以便组件可以跟踪它所做的任何渲染之间的信息。当您 setState 时,它会更新状态对象,然后重新渲染组件。这非常酷,因为这意味着 React 可以处理繁重的工作并且速度非常快。
作为状态的一个小例子,这里是一个搜索栏的片段(如果你想了解更多关于 React 的信息,值得看看这门课程)
Class SearchBar extends Component {
constructor(props) {
super(props);
this.state = { term: '' };
}
render() {
return (
<div className="search-bar">
<input
value={this.state.term}
onChange={event => this.onInputChange(event.target.value)} />
</div>
);
}
onInputChange(term) {
this.setState({term});
this.props.onSearchTermChange(term);
}
}
概括
Props 和 State 做类似的事情,但以不同的方式使用。您的大部分组件可能是无状态的。
Props 用于将数据从父级传递给子级或由组件本身传递。它们是不可变的,因此不会改变。
状态用于可变数据或将更改的数据。这对于用户输入特别有用。以搜索栏为例。用户将输入数据,这将更新他们看到的内容。
简而言之。
props 值不能改变 [immutable] 状态值可以改变,使用 setState 方法 [mutable]
道具
props 用于在子组件中传递数据
props 更改组件外部的值(子组件)
状态
在类组件中使用状态
state 改变组件内的值
如果渲染页面,则调用 setState 来更新 DOM(更新页面值)
状态在反应中具有重要作用
在回答关于 props 是不可变的最初问题时,就子组件而言,它们被称为是不可变的,但在父组件中是可变的。
通常,一个组件(父组件)的状态是子组件的道具。
状态驻留在组件中,其中道具从父级传递到子级。道具通常是不可变的。类 Parent 扩展 React.Component { constructor() { super(); this.state = { name : "John", } } render() { return (
在上面的代码中,我们有一个父类(Parent),它的状态为 name,它作为 prop 传递给子组件(Child class),子组件使用 {this.props.name} 渲染它
在 React 中,状态存储数据以及道具。它与后者的区别在于存储的数据可以通过不同的变化进行修改。这些只不过是用平面 JavaScript 编写的对象,因此它们可以包含数据或代码,代表您想要建模的信息。如果您需要更多详细信息,建议您查看这些出版物 Use of the State in React 和 Use of Props in React
这是我目前关于 state 和 props 之间解释的观点
状态就像组件中的局部变量。您可以使用 set state 来操作 state 的值。然后,您可以将 state 的值传递给您的子组件。 Props 是恰好位于您的 redux 存储中的值,这实际上来自于源自 reducer 的状态。你的组件应该连接到 redux 以从 props 中获取值。您还可以将 props 值传递给您的子组件
您有一些用户正在应用程序中某处输入的数据。
正在输入数据的组件应该在其状态下拥有该数据,因为它需要在数据输入期间在应用程序的任何其他位置进行操作和更改数据应该作为道具传递给所有其他组件
所以是的,道具正在改变,但它们在“源头”发生了变化,然后会简单地从那里流下来。所以 props 在接收它们的组件的上下文中是不可变的。
例如,用户编辑供应商列表的参考数据屏幕将在状态下进行管理,然后会有一个操作导致更新的数据保存在 ReferenceDataState 中,它可能比 AppState 低一级,然后这个供应商列表将作为道具传递到需要使用它的所有组件。
反应中“状态”和“道具”之间的一些差异。
React 根据状态控制和渲染 DOM。组件状态有两种:props 是组件之间传递的状态,state 是组件内部的状态。 Props 用于从父组件到子组件的数据传输。组件内部也有自己的状态:只能在组件内部修改的状态。
通常某个组件的状态可以是子组件的 props,props 会传递给子组件,子组件在父组件的渲染方法中声明
来自:Andrea Chiarelli 的书《Beginning React:使用 React 简化前端开发工作流程并增强应用程序的用户体验》:
每个 React 组件都有一个 props 属性。此属性的目的是收集传递给组件本身的数据输入。 JSX 属性附加到 React 元素,具有相同名称的属性附加到 props 对象。因此,我们可以使用附加属性访问传递的数据。此外,props 的不变性让我们可以将组件视为纯函数,它们是没有副作用的函数(因为它们不会改变输入数据)。我们可以将数据从一个组件传递到另一个组件视为单向数据流,从父组件流向子组件。这给了我们一个更可控的系统。
React 提供了一种机制来支持在数据更改时自动渲染组件。这种机制是基于状态的概念。 React 状态是一个表示随时间变化的数据的属性。每个组件都支持 state 属性,但应谨慎使用。存储可以随时间变化的数据的组件被称为有状态组件。有状态组件将状态存储在 this.state 属性中。要通知组件状态已更改,您必须使用 setState() 方法。状态初始化是唯一可以在不使用 setState() 的情况下为 this.state 属性赋值的情况。
setState() 将新数据与状态中已包含的旧数据合并,并覆盖之前的状态 setState() 会触发 render() 方法的执行,因此永远不要显式调用 render()
props 和 state 之间的主要区别在于 state 是内部的,由组件本身控制,而 props 是外部的,由渲染组件的任何东西控制。
React 组件使用状态来读取/写入可以更改/变异的内部变量,例如:
this.setState({name: 'Lila'})
React props 是一个特殊的对象,它允许程序员将变量和方法从父组件获取到子组件中。
这有点像房子的门窗。道具也是不可变的子组件不能更改/更新它们。
有几种方法可以帮助在父组件更改道具时进行侦听。
简单的解释是:STATE 是组件的本地状态,例如 color = "blue" 或 animation=true 等。使用 this.setState 来改变组件的状态。 PROPS 是组件如何相互通信(将数据从父级发送到子级)并使组件可重用。
State 是你的数据,是可变的,你可以用它做任何你需要的事情,props 是只读数据,通常当你传递 props 时,你已经使用了你的数据,你需要子组件来渲染它,或者你的 props 是函数你调用它来执行任务
状态是真相的起源,您的数据所在的地方。你可以说状态通过道具表现出来。
为组件提供道具是使您的 UI 与数据保持同步的原因。组件实际上只是一个返回标记的函数。
给定相同的道具(要显示的数据),它总是会产生相同的标记。
所以 props 就像将数据从源头传送到功能组件的管道。