react子组件怎么react 改变组件 state父组件的state

  React中父组件与子组件之间的数据传递的的实现大家都可以轻易做到,但对比很多人的实现方法,总是会有或多或少的差异。在一个团队中,这种实现的差异体现了每个人各自的理解的不同,但是反过来思考,一个团队用了同样的UI,同样的框架,实现方式确实有差异,这其实就是工程化的问题。
  回到React中父组件与子组件之间的数据传递的问题上来。
  父组件与子组件之间的数据传递的实现方式大致可以分为2种情况:
    1、子组件用自己的flux环传递数据,最后调用父组件的onChange事件将数据传给父组件。
    2、子组件调用父组件的onChange事件,在父组件中的onChange事件中调用flux环传递数据到付组件的View层
  这2种方式各有优点,对比这两种方式,在实时性上,第二种方式是通过调用父组件的onChange事件,数据改变是通过父组件的flux环发生改变的,所以是实时的,而第一种方式的数据是通过子组件自己的flux环改变的,最终传给父组件,所以非实时;而在粒度上,这2种方式是相同的,都是维护了一个局部逻辑。我们一般用子组件来实现一些页面局部的复杂逻辑,如果这个逻辑内部的数据处理也很复杂(要根据各种情况作出不同的判定、改变),那么第一种无疑更为合适,而更为现实的情况是,往往局部的复杂逻辑的实现在子组件内部还有子组件的子组件,这种情况下,优先选择第一种方式;那么相对的如果这个数据处理比较简单,我们完全可以将整个子组件看做页面上的一个输入框(也可以是其他实现某个功能的对话框),那么父组件中的一个输入框调用父付组件的onChange事件来改变数据流,毫无疑问,第二种方式更为合理些。
  按照第二种方式,我们经常可以在父组件中看到如下的局部代码:
onChange: function(property, value) {
Action.changePromotionDetail(property, value);
render: function() {
&div className="xui-promotion-flashSalePage"&
&ProductInfo onChange={this.onChange} /&
&PromotionInfo onSubmit={this.onSubmit}
onChange={this.onChange}
promotionName={this.state.promotionName}
advert={this.state.advert}
promotionRangeDate={this.state.promotionRangeDate}
memberGrades={this.state.memberGrades}
memberGrade={this.state.memberGrade}
promotionPrice={this.state.promotionPrice}
numPerPurchase={this.state.numPerPurchase}
period={this.state.period}
numPerPeriod={this.state.numPerPeriod} /&
  如果传入子组件的属性和方法越多,那么代码的可读性其实越差,维护起来也更不方便,甚至在父组件的Store中还需要对数据流做许多处理,类似:
changePromotionDetail: function(action) {
if (...) {
this.data[action.data.property] = ...;
this.data[action.data.property] = action.data.
this.__emitChange();
  那么我们又需要思考,如果我们像上面所说的将子组件看做一个输入框,一个输入框应该只需要输入一个值,父组件不应该接受那么多的不同属性的数据,同时父组件需要做的只是将接受到的一个数据通过flux环传递给父组件的View层。那么我们可以采用的一种方法是子组件的数据变更先调用子组件的onChange事件,并在其中做好必要的数据处理,然后将数据添加到一个对象中,以一个数据处理完毕的对象的形式调用父组件的onChange事件:
onChange: function(property, value) {
if (property == '...') {
// do someting here...
// do someting here...
var obj = {
// some key/value here
this.props.onChange(obj);
  这样父组件中的代码就可以简化为如下:
onChange: function(obj) {
Action.changePromotionDetail(obj);
render: function() {
&div className="xui-promotion-flashSalePage"&
&ProductInfo onChange={this.onChange} /&
&PromotionInfo onSubmit={this.onSubmit}
onChange={this.onChange}
infoObj={this.state.infoObj} /&
  再回到标准化的思考上,以React为例,React本身只是一个UI,facebook推荐了flux的架构,这就是一种实现方式,那么一个团队在大方向上采用的技术和实现方式其实就确定了下来。如果我们进一步的细分,对诸如父组件和子组件之间的数据传递的方式,数据传递的格式等等作出限制,看上去好像限制了研发编程的自由,同时将研发的工作变成了机械的重复,但是换个角度,这样的限制必然提高了研发效率,每个人碰到不同的场景都有了统一的应对策略;这样的限制也必然降低维护的成本,每个人都能理解他人的编程思路。这就是工程化的一部分。
  编程就是为了解决问题,要想解决问题又需要考虑2个问题:
    1、工具。
    2、方式。
  工具是学不完的,尤其现在前端的工具井喷式的发展(虽然侧面说明了前端工具的匮乏~),到这个公司用React,以后跳槽去了另一家又用Angular,后来换了部门,这个部门又用Vue。
  那么,作为研发,或许可以思考第二个问题,标准化的方式。每个公司每个部门都会有一套标准,你需要做的是先学会这套标准,同时去思考可以完善的地方,譬如这种场景没有标准化的解决方案,你可以提出一个方案,如果被大家接受了,你的方案就成为了标准的一部分。
  这或许也是一条前端之路,一条提高编程效率与维护性的路,一条解决工程化部分问题的路。
阅读(...) 评论()React 进阶: 容器组件 - 众成翻译
编写的 React 系列三篇教程中的第二篇。本系列讲授的都是基础 React 技能之上的晋级内容,用来创建更大的事情,比如完整的单页应用(SPA)。本文是上篇 React Router 的继续。
第二部分: 容器组件 (即本文!)
在第一篇文章中,我们创建了路由和视图。在本教程中,我们打算探索一个新概念,即组件不创建视图,而是协助创建视图的组件创建视图。代码放在 。
我们还会将数据引入到我们的应用程序中。如果你熟悉 MVC 模式,就应该知道将视图与应用程序的行为混合在一起通常被认为是不佳的实践。换句话说,在视图需要接收数据来渲染它的同时,视图不应该知道数据来自哪里,数据是如何改变的,或者如何创建这些数据。
用 AJAX 获取数据
作为一个不佳实践的示例,我们扩展一下前一篇教程中的 UserList 组件,让它可以处理它自己的数据获取:
// 这是一个不推荐的将视图与数据紧耦合的示例
var UserList = React.createClass({
getInitialState: function() {
componentDidMount: function() {
var _this =
$.get('/path/to/user-api').then(function(response) {
_this.setState({users: response})
render: function() {
&ul className=&user-list&&
{this.state.users.map(function(user) {
&li key={user.id}&
&Link to=&{'/users/' + user.id}&&{user.name}&/Link&
如果需要知道这个组件做什么的更详细/入门者的解释,看看。
为什么是这个不太理想的示例?开始的时候,我们要打破把“行为”与“如何渲染视图&混在一起的规则 - 这两件事情应该分离。
要明白,用 getInitialState 来初始化组件的状态并没有什么错,从 componentDidMount 管理一个 AJAX 请求也没有什么错(虽然我们可能应该将实际调用抽出来放到其他函数中)。问题是,我们是在视图存储的同一个组件中一起做这些事情。这种紧耦合让应用程序变得更死板、更。如果你还需要在其他地方获取用户列表该怎么办?获取用户的行为与这个视图绑在一起,所以它是不可重用的。
第二个问题是,我们是在用 jQuery 发起 AJAX 调用。当然,jQuery 有很多好的功能,但是它的大部分功能都是处理 DOM 渲染,而 React 有自己的方法来处理 DOM 渲染。至于 jQuery 的非 DOM 功能,比如 AJAX,我们可以找到很多只关注一个功能的可选方案。
其中之一就是 ,一个基于 promise 的 AJAX 工具。它与 jQuery 的基于 Promise 的 AJAX 功能在 API 上很相似。如何相似呢?
$.get('/path/to/user-api').then(function(response) { ... });
axios.get('/path/to/user-api').then(function(response) { ... });
余下的示例中,我们会一直用 Axios。其它类似工具有 、 和 。
Props 和 State
在学习容器组件和展示性组件之前,我们需要搞清楚有关 props 和 state 的一些东西。二者都可以从父组件到子组件向下传递。但是,父组件的props 和 state 只会成为子组件的 props。
比如,假如 ComponentA 将它的一些 props 和 state 传递给它的子组件 ComponentB。ComponentA 的 render 方法看起来可能这样的:
// ComponentA
render: function() {
return &ComponentB foo={this.state.foo} bar={this.props.bar} /&
即使 foo 是父组件上的状态,它也会成为子组件 ComponentB 上的一个 prop。bar 属性也会成为子组件上的 prop,因为所有从父组件传递到子组件的数据都会成为子组件中的 props。下面的示例展示 ComponentB 的方法是如何把 foo 和 bar 当作 props 访问的:
// ComponentB
componentDidMount: function() {
console.log(this.props.foo);
console.log(this.props.bar);
在用 AJAX 获取数据示例中,从 AJAX 接收的数据被设置为组件的状态。那个示例没有子组件,但是你可以料想一下,如果它有子组件的话,那么状态会作为 props 从父组件向下 到子组件。
要更好地理解状态,请参考 。从这里开始,本教程会把随着时间改变的数据称为“状态(state)“。
是时候分拆了
在用 AJAX 获取数据示例中,我们制造了一个问题。UserList 组件可以运行,但是它试图做太多事情。要解决这个问题,我们来把 UserList 分拆成两个组件,每个组件充当不同的角色。这两个组件的类型,在概念上将会称为 容器组件 和 展示性组件,又称“智能(smart)”组件和“木偶(dumb)”组件。
简而言之,容器组件获取数据,并处理状态。然后状态会被传递给展示性组件作为 props,然后被渲染到视图。
术语“智能组件”及“木偶组件”在社区中正在消失。我在这里引用它们,只是为了让你在阅读更老的文章时,知道它们与容器组件和展示性组件是同一概念。
展示性组件
你也许不知道展示性组件,但是在本系列教程的前面你已经看到过它。想像一下 UserList 组件在管理自己的状态之前的样子:
var UserList = React.createClass({
render: function() {
&ul className=&user-list&&
{this.props.users.map(function(user) {
&li key={user.id}&
&Link to=&{'/users/' + user.id}&&{user.name}&/Link&
这个组件与之前的不太一样,它是一个展示性组件。它和 最大的区别为,它是遍历用户数据来创建列表条目,并且通过 props 接收用户数据。
展示性组件是“木偶”,就是说它们不知道它们接收的 props 是如何形成的,也不知道 state。
展示性组件永远不会自己修改 prop 数据。实际上,任何接收 props 的组件应该认为该数据是不可变的,是属于父组件的。不过,虽然展示性组件不能修改 prop 中数据的意义,但是它能为视图格式化数据(比如将 Unix timestap 转换为人类可读的东西)。
在 React 中,事件是直接通过像 onClick 这样的属性绑定到视图。但是,有人也许想知道既然展示性组件被认为不能修改 props,那么事件是如何工作的呢?为此,我们有了下面有关事件的整整一个小节。
当在循环中创建 DOM 节点时,key 属性 (相对于相邻兄弟)。注意,这只是对最高级别的 DOM 节点 - 本例中的&li&。
此外,如果嵌套的 return 对你来说看起来有点古怪的话,可以考虑将列表条目的创建分离到它自己的函数中:
var UserList = React.createClass({
render: function() {
&ul className=&user-list&&
{this.props.users.map(this.createListItem)}
createListItem: function(user) {
&li key={user.id}&
&Link to=&{'/users/' + user.id}&&{user.name}&/Link&
容器组件几乎总是展示性组件的父组件。在某种程度上,它充当展示性组件和应用程序其它部分之间的一个中介。它们也称为智能(smart)组件,因为它们知道整体应用程序。
既然容器组件和展示性组件需要有不同的名字,所以为避免混淆,我们称这个为 UserListContainer:
var React = require('react');
var axios = require('axios');
var UserList = require('../views/list-user');
var UserListContainer = React.createClass({
getInitialState: function() {
componentDidMount: function() {
var _this =
axios.get('/path/to/user-api').then(function(response) {
_this.setState({users: response.data})
render: function() {
return (&UserList users={this.state.users} /&);
module.exports = UserListC
为简单起见,前面的例子都省略了 require() 和 module.exports 语句。但是在本例中,展示容器组件将它们各自的展示性组件作为直接依赖是很重要的。为完整性起见,本例展示了所有需要的 requre。
容器组件可以像其它 React 组件一样创建。它们跟其它组件一样,也有一个 render 方法,它们只是不创建任何渲染它们自己的东西,而是返回展示性组件的结果。
ES6 箭头函数快速备注:你可能会注意到上面的例子中用到传统的 var _this = this 技巧。除了语法更短外,还有,可以减轻使用这种技巧的需要。为了让你把注意力放在学习 React 上,本教程没有使用 ES6 语法,而是采用 ES5 语法。但是,本教程的Github指南则是用 ES6 语法,并且在 README 文件中有解释。
迄今为止,我们展示了状态是如何从容器组件传递到展示性组件,但是行为如何传递呢?事件属于行为的范畴,它们通常需要修改数据。React 中的事件是在视图级别绑定的。对于分离关注点来说,如果我们在视图所在的地方创建事件函数,就会在展示性组件中出问题。
为详细阐述,我们首先以直接给展示性组件添加一个事件开始(一个可以点击的 &button&),来识别问题:
// 展示性组件
var UserList = React.createClass({
render: function() {
&ul className=&user-list&&
{this.props.users.map(function(user) {
&li key={user.id}&
&Link to=&{'/users/' + user.id}&\&{user.name}&/Link&
&button onClick={this.toggleActive}&Toggle Active&/button&
toggleActive: function() {
// 我们不能在展示性组件中修改状态 :(
从技术讲,这段代码是可以运行的,但是它不是一个好主意。事件需要修改数据,能修改的数据应该被存为状态 - 展示性组件不应该知道的东西。
在我们的示例中,状态改变将是用户的“积极性”,但是你可以把你想要的任何函数绑定到 onClick。
更好的解决方案是将功能作为 prop,从容器组件传递给展示性组件,像这样子:
// 容器组件
var UserListContainer = React.createClass({
render: function() {
return (&UserList users={this.state.users} toggleActive={this.toggleActive} /&);
toggleActive: function() {
// 我们应该在容器组件中修改状态 :)
// 展示性组件
var UserList = React.createClass({
render: function() {
&ul className=&user-list&&
{this.props.users.map(function(user) {
&li key={user.id}&
&Link to=&{'/users/' + user.id}&&{user.name}&/Link&
&button onClick={this.props.toggleActive}&Toggle Active&/button&
onclick 属性必须放在视图所在的地方 - 展示性组件中。但是,它调用的函数已经移到父容器组件中了。这个更好,因为是由容器组件处理状态。
如果父函数刚好改变了状态,那么状态改变就会导致重新渲染父函数,然后依次更新子组件。这在 React 中是自动发生的。
这里有一个示例,展示容器组件上的事件如何修改状态,从而会自动更新展示性组件:
// Example for https://css-tricks.com/learning-react-container-components/
// 容器组件
const UserListContainer = React.createClass({
getInitialState: function() {
{id:1, name:'Ryan', active:true},
{id:2, name:'Michael', active:true},
{id:3, name:'Dan', active:true}
render: function() {
return (&UserList users={this.state.users} toggleActive={this.toggleActive} /&);
toggleActive: function(userId) {
// 状态永远不应该被直接修改。我们应该总是创建一份状态的副本,然后用副本替换原始状态。
// 在本例中,我们是替换整个状态,如果有很多记录这样做可能性能不是最佳的,但是对于本例来说足够了。
// 我们会将在第三篇文章 Redux 中谈到更多有关可修改和不可修改状态。
var newState = Object.assign({}, this.state)
var user = _.find(newState.users, {id: userId});
user.active = !user.active
this.setState(newState)
// 展示性组件
const UserList = React.createClass({
render: function() {
let _this =
&ul className=&user-list&&
{this.props.users.map(function(user) {
// `.bind()` 方法确保当 `toggleActive()` 被调用时,第一个参数将是用户的 ID
&li key={user.id}&
&a href=&#&&{user.name}&/a&
&span&{user.active ? 'Active' : 'Not Active'}&/span&
&button onClick={_this.props.toggleActive.bind(null, user.id)}&Toggle Active&/button&
ReactDOM.render(&UserListContainer /&, document.getElementById('root'))
请注意这个示例如何处理,以及如何使用方法。
用路由器使用容器组件
路由器应该不在直接使用 UserList,而是直接使用 UserListContainer,而 UserListContainer 又会使用 UserList。最后,UserListContainer 返回 UserList 结果,所以路由器依然会接收到它所需的东西。
数据流和扩展运算符
在 React 中,props被从父组件向下传递到子组件的概念被称为流。迄今为止的示例只展示了简单的父子关系,但是在真实应用程序中可能有很多嵌套的组件。想像一下数据流通过状态和 props,从高层父组件向下流过很多子组件。这是一个 React 中必须记住的一个基础概念。
ES6 有一个新的 很有用。React 已经把 用到 JSX。这对 React 中数据通过 props 流动很有帮助。本教程的 Github 指南也用到了它,所以一定要读读 中这个功能的说明。
无状态的函数式组件
从 React 0.14 开始,就有了一个更容易创建无状态(展示性)组件的新功能。这个新功能称为。
到现在你可能已经注意到,随着你分离容器组件和展示性组件,很多展示性组件只有一个 render 方法。在这些例子中,React 现在允许组件可以被写成一个函数:
// 老的啰嗦的方式
var Component = React.createClass({
render: function() {
&div&{this.props.foo}&/div&
// 较新的无状态函数式组件方式
var Component = function(props) {
&div&{props.foo}&/div&
你可以很清楚地看到,新的方式更简洁。但是记住,这种方式只是只需要一个 render 方法的组件的可选项。
用新的无状态函数式方式,函数的参数为 props。这意味着它不需要用 this 来访问 props。
这里有一个很好的无状态函数式组件的
到现在你可能已经看到,React 跟传统的 MVC 不一样。React 更多时候被称为“只是视图层”。React 初学者很容易相信 React 应该术语他们熟悉的传统的 MVC,好像它命中注定要和来自于第三方的传统控制器和模型一起用一样。
React 确实没有“传统的控制器”,但是它以自己特殊的方式提供了一种分离视图和行为的方法。我相信容器组件充当了在传统 MVC 中控制器充当的相同的基础用途。
至于模型,我已经看到了有人在 React 中用 Backbone 模型,我也相信他们在这样做是否好方面有各种观点。但是传统模型是适合 React 的方式,我并没有被说服。React 流动数据的方式,让它不适合传统模型的工作方式。Facebook 创建的 是一种信奉 React 固有的流动数据的能力的方式。在下一个教程汇总,我们将学习 Redux,一种很流行的 Flux 实现,也是我看作是传统模型的一种可选方案。
容器组件更多是一种概念,而不是一种解决方案。本教程中的示例只是一种实现的方式。但是这种概念是如此好地被接受,甚至 也在他们团队中使用 - 虽然他们看额能用的是不同的术语。
本教程是被 在本主题上强烈影响。更多的信息和容器组件的示例一定要看看本教程的官方
文章内容对你有帮助吗?
不确定有没有帮助
非常有帮助
你觉得译者翻译得如何?
非常感谢!您的评价已成功提交。react如何根据登录前后渲染不同的组件 - CNode技术社区
在前端默默耕耘,但不会止步于前端,而是努力成为大前端
使用webpack打包后的bundle.js作为项目的入口文件,如何根据用户是否已经登录渲染不同的组件。登录状态应该是在后台判断的,react如何接收后台的信号去渲染不同的组件。
props 传进参数
不好意思?能不能说具体一些,这个props是父组件上的参数?这个参数如何感知是否已经登录了呢
登录前后-------这是个State
React根据State去渲染组件
修改State的方式:
Props 回调
其他: 事件
可以加flux ,改善流程
组件 有个登录状态的State字段, 在ComponentDidMoount的时候监听
登录状态的事件(用来修改登录State)
登录组件 产生Action
Store emit登录事件
监听的view
在事件回调里改变state
如果是根据登录状态,异步加载组件…webpack本来就有分割chunk的能力,加载组件的方法里用AMD的require,应该很方便实现异步插入js吧
没用过react
react 你是怎么做用户登录信息保存的呀
React 是视图部分。用户登录信息是后台处理和保存的。
他问的可能是,登录前一对view,登陆后又一堆view,此时也应该用react的路由的
是的是的 用户登录信息该怎么保存呢,路由咋分登录还是未登录呢
CNode 社区为国内最专业的 Node.js 开源技术社区,致力于 Node.js 的技术研究。
服务器赞助商为
,存储赞助商为
,由提供应用性能服务。
新手搭建 Node.js 服务器,推荐使用无需备案的react子组件怎么改变父组件的state_百度知道
react子组件怎么改变父组件的state
我有更好的答案
&&&/p&&&&&p&年龄.&&&&&&&render(){&&&&&&&&&p&render(){&&&&&&&&&Button&onClicked={()=&this.setState(stateName)&&&&}&&/p&'John'&&&nbsp.age}&&&&onChangeState(stateName){&&&&&&&&&}&&&&}&&&&&age,&&&&&Child&extends&&&&&super(props);&&&&&&&&&&nbsp:class&&&&&Component&{&&Child&onClicked={this.onChangeState.bind(this)}/&&&&&}}子组件:&nbsp可以通过向子组件传入一个修改state的函数,比如如下代码;&&Component&{&'Peter';&nbsp:&nbsp.姓名:{this.state.name}&&construtor(props){&&nbsp:&nbsp.state={&&&&&&&&&&&&&&&&&nbsp:父组件:class&Father&extends&&&&&nbsp:{&&})}/&&'26'&&nbsp.onClicked({name
采纳率:77%
为您推荐:
其他类似问题
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。

我要回帖

更多关于 react 父子组件通信 的文章

 

随机推荐