Quick Start the ReactJS with som

2017-06-13  本文已影响0人  LillianSiYin

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')
);
  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>.
  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')
);
  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.
// 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')
);
上一篇下一篇

猜你喜欢

热点阅读