Quick Start the ReactJS with some basic concepts (1)

Aims: This article is to introduce some basic concepts by using the "Cliking Clock" case.

1.Elements & DOM node

DOM node (.html file): everything inside it will be managed by React DOM.
Elements (.js file) are the smallest building blocks of React apps. To render a React element into a root DOM node, pass both to ReactDOM.render(). Elements are immutable (Once you create an element, you can't change its children or attributes). An element is like a single frame in a movie: it represents the UI at a certain point in time.
One way to update the UI is to create a new element, and pass it to ReactDOM.render():

Cliking Clock V1.0

// index.js (Babel)
function tick() {
  const element = (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {new Date().toLocaleTimeString()}.</h2>
    </div>
  );
  ReactDOM.render(
    element,
    document.getElementById('root')
  );
}

setInterval(tick, 1000);
// index.html (DOM node)
<div id="root">
    <!-- This element's contents will be replaced with your component. -->
</div>

2.Components & Props

Components let you split the UI into independent, reusable pieces, and think about each piece in isolation.Conceptually, components are like JS functions. They accept arbitrary inputs (called "props") and return React elements describing what should appear on the screen.
Previously, we showed how React elements represent DOM tags. However, elements can also represent user-defined components:

// index.js

// ******functional way to define a component****** 
function Welcome(props) {
  return <h1>Hello, {props.name}</h1>; //return an element
}
// ******use an ES6 class to define a component******
class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>; //return an element
  }
}
//elements represent user-defined components
const element = <Welcome name="Sara" />;   

ReactDOM.render(
  element,
  document.getElementById('root')
);
  • Recap:
  1. We call ReactDOM.render() with the <Welcome name="Sara" /> element.
  2. React calls the Welcome component with {name: 'Sara'} as the props.
  3. The Welcome component returns a <h1>Hello, Sara</h1> element as the result.
  4. React DOM efficiently updates the DOM to match <h1>Hello, Sara</h1>.
  • NOTE:
  1. Always start component names with a capital letter.
    Eg: <div /> represents a DOM tag, but <Welcome /> represents a component and requires Welcome to be in scope.
  2. Props are Read-Only. Whether you declare a component as a function or a class, it must never modify its own props. All React components must act like pure functions (do not attempt to change the inputs, and always return the same result for the same inputs) with respect to their props.
  3. Components can refer to other components in their output. This lets us use the same component abstraction for any level of detail. A button, a form, a dialog, a screen: in React apps, all those are commonly expressed as components.
    Eg: we can create an App component that renders Welcome many times:
function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}
function App() {
  return (
    <div>
      <Welcome name="Sara" />
      <Welcome name="Cahal" />
      <Welcome name="Edite" />
    </div>
  );
}
ReactDOM.render(
  <App />,
  document.getElementById('root')
);

3.State & Lifecycle

In this section, we will learn how to make the Clock component in the "Cliking Clock" case truly reusable and encapsulated. It will set up its own timer and update itself every second. By achieving this, we need to add state (see below) to the Clock component.
State is similar to props, but it is private and fully controlled by the component. Local state is exactly a special feature available only to the class-defined component other than the functional component.

Here are the steps showing how to convert a functional component to a class-defined component with state used:

  1. Converting a Function to a Class
  1. Create an ES6 class with the same name that extends React.Component.
  2. Add a single empty method to it called render().
  3. Move the body of the function into the render() method.
  4. Replace props with this.props in the render() body.
  5. Delete the remaining empty function declaration.
class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.props.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}
  1. Adding Local State to a Class
  1. Replace this.props.date with this.state.date in the render() method.
  2. Add a class constructor that assigns the initial this.state.
    Note: how to pass props to the base constructor.
  3. Remove the date prop from the <Clock /> element:
class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}
ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);
  1. Adding Lifecycle Methods to a class
  1. Set up a timer using the special method componentDidMount() whenever the Clock is rendered to the DOM for the first time, which is called "mounting" in React.
  2. Clear the timer using another special method componentWillUnmount() whenever the DOM produced by the Clock is removed, which is called "unmounting" in React.
    NOTE: These 2 methods are called "lifecycle hooks".
  3. Implement the tick() method that will be called every second. It will use this.setState() to schedule updates to the component local state:

Cliking Clock V2.0

// index.js
class Clock extends React.Component {
    constructor(props) {
      super(props);
      this.state = {date: new Date()};
    }
    // mounting, set up a timer which is to call the tick() method by every 1000ms
    componentDidMount() {
      this.timerID = setInterval(
        () => this.tick(),1000
      );
    }
    // unmounting, clear the timer
    componentWillUnmount() {
      clearInterval(this.timerID);
    }
    tick() {
      this.setState({
        date: new Date()
      });
    }
    render() {
      return (
        <div>
          <h1>Hello, world!</h1>
          <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
        </div>
      );}
}
// we write the Clock once and it can updates the UI every second by itself.
ReactDOM.render(
    <Clock />,
    document.getElementById('root')
);
  • Recap:
    1. When <Clock /> is passed to ReactDOM.render(), React calls the constructor of the Clock component. Since Clock needs to display the current time, it initializes this.state with an object including the current time, which state will be updated later.
  1. React then calls the Clock's render() method to know what should be displayed on the screen. And then updates the DOM to match the Clock's render output.
  2. Then React calls the componentDidMount() lifecycle hook. Inside it, the Clock asks the browser to set up a timer to call tick() once a second.
  3. Every second the browser calls the tick() method. Inside it, the Clock schedules a UI update by calling setState() with an object containing the current time. Thanks to the setState() call, React knows the state has changed, and calls render() again to learn what should be on the screen. This time, this.state.date in the render() method will be different, and so the render output will include the updated time. React updates the DOM accordingly.
  4. If the Clock component is ever removed from the DOM, React calls the componentWillUnmount() lifecycle hook so the timer is stopped.
  • NOTE About Using State Correctly
    1. Do Not Modify State Directly, the only place where you can assign this.state is the constructor(). Eg:
// Wrong
this.state.comment = 'Hello';

Instead, use setState():

// Correct
this.setState({comment: 'Hello'});
  1. Updating the State May Be Asynchronous. Because this.props and this.state may be updated asynchronously, you cannot rely on their values for calculating the next state. Eg:
// Wrong
this.setState({
    counter: this.state.counter + this.props.increment,
});

Instead, use a second form of setState() that accepts a function rather than an object. That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument:

// Correct Using Arrow Function
this.setState((prevState, props) => ({
    counter: prevState.counter + props.increment
}));
//Also Correct Using Regular Function
this.setState(function(prevState, props) {
    return {
      counter: prevState.counter + props.increment
  };
});
  1. State Updates are Merged. Eg, your state may contain several independent variables:
  constructor(props) {
    super(props);
    this.state = {
      posts: [],
      comments: []
    };
  }

Then you can update them independently with separate setState() calls:

 componentDidMount() {
    fetchPosts().then(response => {
      this.setState({posts: response.posts});
    });
    
    fetchComments().then(response => {
      this.setState({comments: response.comments});
    });
 }

The merging is shallow, so this.setState({comments}) leaves this.state.posts intact (unchanged), but completely replaces this.state.comments.

4.Handling Events

Handling events with React elements is very similar to handling events on DOM elements. There are some syntactic differences:

  1. React events are named using camelCase, rather than lowercase.
  2. With JSX you pass a function as the event handler, rather than a string.
  3. Cannot return false to prevent default behavior in React. You must call preventDefault explicitly. Eg:
function ActionLink() {
    function handleClick(e) {
      e.preventDefault();
      console.log('The link was clicked.');
    }

    return (
      <a href="#" onClick={handleClick}> Click me </a>
    );
}

However, in HTML, use false to prevent the default link behavior of opening a new page:

<a href="#" onclick="console.log('The link was clicked.'); return false"> Click me </a>
  1. In React you no need to call addEventListener to add listeners to a DOM element after it is created. Instead, just provide a listener when the element is initially rendered.
    When you define a component using an ES6 class, a common pattern is for an event handler to be a method on the class.
    Eg, this Toggle component renders a button that lets the user toggle between "ON" and "OFF" states:
class ClickTest extends React.Component{
    constructor(props){
      super(props);
      this.state = {test : true};

      // This binding is necessary to make `this` works in the callback
      this.makeClick = this.makeClick.bind(this);
    }

    makeClick(){
      this.setState(preTest => ({test: !preTest.test}));
    }

    render(){
      return (<button onClick = {this.makeClick}>{this.state.test ? "on" : "off"}</button>);
    }
}
ReactDOM.render(
    <ClickTest />,
    document.getElementById('root')
);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容