目录
归档
100
2017 年 04 月 03 日
React的模式,技术,技巧–02

github地址:https://github.com/vasanthk/react-bits

我们接着上面的文章说下去。

Async Nature Of setState()

组件内的setState方法异步的,意味着调用该方法后马上获取setState值的话,往往拿到的是原始值。


//我们往往需要在值改变之后执行一些操作,可以通过setState的回调函数操作
_onClickHandler: function _onClickHandler() {
   console.log(this.state.count);
   this.setState({
     count: this.state.count + 1
   }, () => {
   console.log(this.state.count);
   });
}

//网上也有另外一个方法是通过Async/Await实现异步转同步
setStateAsync(state) {
  return new Promise((resolve) => {
    this.setState(state, resolve)
  });
}
async componentDidMount() {
  await this.setStateAsync({count: this.state.count + 1});
  console.log(this.state.count);
}


Dependency Injection

依赖注入听似一个抽象的概念,实际在React中,依赖注入很容易看到。


// Title.jsx
export default function Title(props) {
  return <h1>{ props.title }</h1>;
}

// Header.jsx
import Title from './Title.jsx';
export default function Header() {
  return (
    <header>
      <Title />
    </header>
  );
}

// App.jsx
import Header from './Header.jsx';
class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { title: 'React Dependency Injection' };
  }
  render() {
    return <Header />;
  }
}

Context Wrapper

原来Context并非只是一个普通对象那么简单,然而实际中并不常用Context


// dependencies.js
export default {
  data: {},
  get(key) {
    return this.data[key];
  },
  register(key, value) {
    this.data[key] = value;
  }
}

// App.js
import dependencies from './dependencies';
dependencies.register('title', 'React in patterns');

class App extends React.Component {
  getChildContext() {
    return dependencies;
  }
  render() {
    return <Header />;
  }
}

App.childContextTypes = {
  data: React.PropTypes.object,
  get: React.PropTypes.func,
  register: React.PropTypes.func
};

// Title.jsx
export default class Title extends React.Component {
  render() {
    return <h1>{ this.context.get('title') }</h1>
  }
}
Title.contextTypes = {
  data: React.PropTypes.object,
  get: React.PropTypes.func,
  register: React.PropTypes.func
};


Event Handlers

React里的事件处理有一个this指向问题,完成一个事件绑定推荐写法如下


class Switcher extends React.Component {
  constructor(props) {
    super(props);
    this.state = { name: 'React in patterns' };
    this._buttonClick = this._handleButtonClick.bind(this);
  }
  render() {
    return (
      <button onClick={ this._buttonClick }>
        click me
      </button>
    );
  }
  _handleButtonClick() {
    console.log(`Button is clicked inside ${ this.state.name }`);
  }
}

//但上面这种写法无法传递额外参数,下面的写法可以
<button onClick={ this._handleButtonClick.bind(this) }>
  click me
</button>


Flux pattern

Flux模式,待续…

One way data flow

单向数据流,待续…

Presentational and Container components


//数据和逻辑一起
class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {time: this.props.time};
    this._update = this._updateTime.bind(this);
  }

  render() {
    var time = this._formatTime(this.state.time);
    return (
      <h1>{ time.hours } : { time.minutes } : { time.seconds }</h1>
    );
  }

  componentDidMount() {
    this._interval = setInterval(this._update, 1000);
  }

  componentWillUnmount() {
    clearInterval(this._interval);
  }

  _formatTime(time) {
    var [ hours, minutes, seconds ] = [
      time.getHours(),
      time.getMinutes(),
      time.getSeconds()
    ].map(num => num < 10 ? '0' + num : num);

    return {hours, minutes, seconds};
  }

  _updateTime() {
    this.setState({time: new Date(this.state.time.getTime() + 1000)});
  }
}

ReactDOM.render(<Clock time={ new Date() }/>, ...);



//数据和逻辑分离

// Clock/index.js
import Clock from './Clock.jsx'; 

export default class ClockContainer extends React.Component {
  constructor(props) {
    super(props);
    this.state = {time: props.time};
    this._update = this._updateTime.bind(this);
  }

  render() {
    return <Clock { ...this._extract(this.state.time) }/>;
  }

  componentDidMount() {
    this._interval = setInterval(this._update, 1000);
  }

  componentWillUnmount() {
    clearInterval(this._interval);
  }

  _extract(time) {
    return {
      hours: time.getHours(),
      minutes: time.getMinutes(),
      seconds: time.getSeconds()
    };
  }

  _updateTime() {
    this.setState({time: new Date(this.state.time.getTime() + 1000)});
  }
};

// Clock/Clock.jsx
export default function Clock(props) {
  var [ hours, minutes, seconds ] = [
    props.hours,
    props.minutes,
    props.seconds
  ].map(num => num < 10 ? '0' + num : num);

  return <h1>{ hours } : { minutes } : { seconds }</h1>;
};


Third Party Integration

讲述React和jQuery的结合


//节选其中一部分代码
class Tags extends React.Component {
  //在这里获取到DOM,并且初始化jQuery插件
  componentDidMount() {
    this.list = $(this.refs.list);
    this.list.tagit();
  }

  //因为是单渲染,数据展示依赖于jQuery,无需React动态更新,这里可以返回false
  shouldComponentUpdate() {
    return false;
  }
  
  //当Props数据发生变化时,再初始化jQuery插件
  componentWillReceiveProps(newProps) {
    this.list.tagit('createTag', newProps.newTag);
  }

  render() {
    return (
      <ul ref='list'>
        { this.props.tags.map((tag, i) => <li key={ i }>{ tag } </li>) }
      </ul>
    );
  }
}

Passing a function to setState

setState使用函数返回


  //以下同时执行时,实际返回值并非期待值
  // assuming this.state.count === 0
  this.setState({count: this.state.count + 1});
  this.setState({count: this.state.count + 1});
  this.setState({count: this.state.count + 1});
  // this.state.count === 1, not 3

  //为解决这个问题,使用以下方法
  this.setState((prevState, props) => ({
    count: prevState.count + props.increment
  }));

  //变异的方式
  //传递对象
  this.setState({ expanded: !this.state.expanded });

  //传递函数
  this.setState(prevState => ({ expanded: !prevState.expanded }));


Decorators

使用ES6的装饰器,待续…

Feature Flags

结合Redux使用,待续…

The switching component

切换组件,这是一种临时做法,实际中都是通过路由控制的


import HomePage from './HomePage.jsx';
import AboutPage from './AboutPage.jsx';
import UserPage from './UserPage.jsx';
import FourOhFourPage from './FourOhFourPage.jsx';

const PAGES = {
  home: HomePage,
  about: AboutPage,
  user: UserPage
};

const Page = (props) => {
  const Handler = PAGES[props.page] || FourOhFourPage;

  return <Handler {...props} />
};

//验证
Page.propTypes = {
  page: PropTypes.oneOf(Object.keys(PAGES)).isRequired
};


Reaching into a Component

从父元素访问组件


  //子组件
class Input extends Component {
  focus() {
    this.el.focus();
  }

  render() {
    return (
      <input
        ref={el=> { this.el = el; }}
      />
    );
  }
}  

  //父组件
class SignInModal extends Component {
  componentDidMount() {
    //请注意,当您对组件使用ref时,它是对组件的ref(而不是底层元素)
    //因此您可以访问其方法。
    this.InputComponent.focus();
  }

  render() {
    return (
      <div>
        <label>User name:</label>
        <Input
          ref={comp => { this.InputComponent = comp; }}
        />
      </div>
    )
  }
}


Lists Components

列表组件


//可以把数组展示的函数单独出来,而不是写组件中去,这个函数可以达到共用。
const SearchSuggestions = (props) => {
  const renderSearchSuggestion = listItem => (
    <li key={listItem.id}>{listItem.name} {listItem.id}</li>
  );

  return (
    <ul>
      {props.listItems.map(renderSearchSuggestion)}
    </ul>
  );
};


Components for formatting text

格式化文本的组件,待续…

Share Tracking Logic

使用高阶组件分享跟踪逻辑,待续…

转载原创文章请注明,转载自: 老赵茶馆 » React的模式,技术,技巧–02
留言
Loading...

发表评论

电子邮件地址不会被公开。 必填项已用*标注

  1. 喜帖街 谢安琪
  2. 猫の恩返 室内管弦楽団