React中需要注意的地方二

一、在getInitialState里边使用 props 是一种反面模式

提示:这不是React明确规定的,就像经常发生在其它代码中的那样;在这种情况下,React能使这种模式更清晰。

getInitialState中使用props传递的父组件的数据来绑定state,经常会导致所谓的真理的重复来源(就是说可能分不清数据来源了)。只要有可能动态推断值,以确定不会发生不同步以及维护困难的情况。(小僧翻译出来也快吐了,原文如果不引入俚语还好,一旦用了就晕乎了,不过在最下方小僧会大致总结下,客官勿急)。

反面示例:

var MessageBox = React.createClass({
  getInitialState: function() {
    return {nameWithQualifier: 'Mr. ' + this.props.name};
  },render: function() {
    return <div>{this.state.nameWithQualifier}</div>;
  }
});

React.render(<MessageBox name="Rogers"/>,mountNode);
好的示例:
var MessageBox = React.createClass({
  render: function() {
    return <div>{'Mr. ' + this.props.name}</div>;
  }
});

React.render(<MessageBox name="Rogers"/>,mountNode);

然而,如果你明确表示同步不是你的目标,那么也可以写成非反向模式。

var Counter = React.createClass({
  getInitialState: function() {
    // naming it initialX clearly indicates that the only purpose
    // of the passed down prop is to initialize something internally
    return {count: this.props.initialCount};
  },handleClick: function() {
    this.setState({count: this.state.count + 1});
  },render: function() {
    return <div onClick={this.handleClick}>{this.state.count}</div>;
  }
});

React.render(<Counter initialCount={7}/>,mountNode);

个人总结:getInitialState中初始化的数据,原则是保持在该组件及其子组件使用,不要将父组件的数据(props传递过来的数据)使用在这里。如果你想在该组件内使用的数据需要根据props传递过来的数据来初始化,那就是你的数据原型有问题了,为什么不在其它方法中直接使用父组件的数据。与父组件通信,最好是通过回调函数,该回调函数是从父组件传递过来,并且里边封装了state绑定的数据(即更改的数据)。


二、在组件中使用DOM事件

注意:这里说的事件是非React提供的事件。React有关于DOM的操作可以很容易和其它类库合作,如jQuery。

试着改变窗口大小:

var Box = React.createClass({
  getInitialState: function() {
    return {windowWidth: window.innerWidth};
  },handleResize: function(e) {
    this.setState({windowWidth: window.innerWidth});
  },componentDidMount: function() {
    window.addEventListener('resize',this.handleResize);
  },componentWillUnmount: function() {
    window.removeEventListener('resize',render: function() {
    return <div>Current window width: {this.state.windowWidth}</div>;
  }
});

React.render(<Box />,mountNode);
componentDidMount 会在组件被渲染之后被调用。在这个方法中通常被用来给DOM添加事件,因为只有DOM(渲染成功)存在,才能给其添加事件。

注意这里的事件是绑定到了React中的组件,而不是最原始的DOM。React会通过一个叫 autobinding 的过程将这个事件方法绑定到组件中。


三、用ajax加载初始数据

在componentDidMount中获取数据:当响应到达时,会将数据存储的state中,然后触发更新UI。

当处理异步请求的响应时,要确定当前组件是否仍然在更新中,通过 this.isMounted() 来判断。

下边的例子是获取所需的Github用户最新动态:

var UserGist = React.createClass({
  getInitialState: function() {
    return {
      username: '',lastGistUrl: ''
    };
  },componentDidMount: function() {
    $.get(this.props.source,function(result) {
      var lastGist = result[0];
      if (this.isMounted()) {
        this.setState({
          username: lastGist.owner.login,lastGistUrl: lastGist.html_url
        });
      }
    }.bind(this));
  },<pre name="code" class="javascript">React.render(<div id={false} />,mountNode);

render: function() { return ( <div> {this.state.username}'s last gist is <a href={this.state.lastGistUrl}>here</a>. </div> ); }});React.render( <UserGist source="https://api.github.com/users/octocat/gists" />,mountNode);
 注意:例子中的bind(this),只能用在函数 
 
 

四、在JSX中使用false

下边是不同情况系 false 渲染的过程:

1. 渲染成id=“false”:

React.render(<div id={false} />, mountNode);
2. 渲染成输入框中的字符串值
React.render(<input value={false} />,mountNode);
3. 没有子元素的情况
React.render(<div>{false}</div>,mountNode);
在这种情况中,false被渲染成<div></div>之间的文本,而是作为一个div的子元素,是为了可以有更多灵活的用法:如
<div>{x > 1 && 'You have more than one item'}</div>

五、组件间的通信

在父子组件之间的通信,可以简单的通过props。

而在同级子组件之间的通信:假如你的 GroceryList 组件有很多通过数组生成的条目。当其中一个条目被点击时,你想要展示该条目的名称。

var GroceryList = React.createClass({
  handleClick: function(i) {
    console.log('You clicked: ' + this.props.items[i]);
  },render: function() {
    return (
      <div>
        {this.props.items.map(function(item,i) {
          return (
            <div onClick={this.handleClick.bind(this,i)} key={i}>{item}</div>
          );
        },this)}
      </div>
    );
  }
});

React.render(
  <GroceryList items={['Apple','Banana','Cranberry']} />,mountNode
);
注意bind( this,arg1,arg2,...)的用法:这里我们只是去传递更多的参数给 handleClick 方法。这并不是React新加的规定,而是JavaScript就有的。

在两个同级子组件之间的通信,你可以设置一个全局的事件componentWillUnmount。在 componentDidMount 中注册监听,在componentWillUnmount 卸载监听,当监听到一个事件时,调用setState()更新视图。


六、暴露组件的功能

组件之间的通信也有一个不常见的方法:可以简单的在子组件中调用父组件的回调函数,此处的子组件拆分更加琐碎。

下边的例子中,每点击一个条目然后自身被删除,当仅剩一个条目时,就为其加上动画效果。

var Todo = React.createClass({
  render: function() {
    return <div onClick={this.props.onClick}>{this.props.title}</div>;
  },//this component will be accessed by the parent through the `ref` attribute
  animate: function() {
    console.log('Pretend %s is animating',this.props.title);
  }
});

var Todos = React.createClass({
  getInitialState: function() {
    return {items: ['Apple','Cranberry']};
  },handleClick: function(index) {
    var items = this.state.items.filter(function(item,i) {
      return index !== i;
    });
    this.setState({items: items},function() {
      if (items.length === 1) {
        this.refs.item0.animate();
      }
    }.bind(this));
  },render: function() {
    return (
      <div>
        {this.state.items.map(function(item,i) {
          var boundClick = this.handleClick.bind(this,i);
          return (
            <Todo onClick={boundClick} key={i} title={item} ref={'item' + i} />
          );
        },this)}
      </div>
    );
  }
});

React.render(<Todos />,mountNode);

或者,你也可以通过在子组件 todo 中定义一个 isLastUnfinishedItem 属性,然后在 componentDidUpdate 进行判断,是否添加动画效果。然而,当有多个属性来控制动画时就显得混乱了。

七、组件引用

当你在一个大的非React应用中想要使用React的组件或者将你的代码过渡到React,你需要想办法引用组件。React.render 方法返回的就是一个完整组件的引用。

var myComponent = React.render(<MyComponent />,myContainer);

要记住,JSX语法并不会返回一个组件实例。它只是一个React元素:一个组件的轻量级表现方式。

var myComponentElement = <MyComponent />; // This is just a ReactElement.

// Some code here...

var myComponentInstance = React.render(myComponentElement,myContainer);
注意:这里只能在顶级作用域(组件外部)中使用。在组件内部应该使用 props 和 state 来保持组件间的通信。

八、this.props.children 未定义

你不能使用this.props.children来访问组件的子节点。this.props.children被设计用来表示自身的节点。

var App = React.createClass({
  componentDidMount: function() {
    // This doesn't refer to the `span`s! It refers to the children between
    // last line's `<App></App>`,which are undefined.
    console.log(this.props.children);
  },render: function() {
    return <div><span/><span/></div>;
  }
});

React.render(<App></App>,mountNode);
想要访问子节点,就要使用在span中ref

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom