React 学习笔记(上)

内容概要:

  • React介绍
  • Single Page Application & Multiple page Application
  • JSX 介绍
  • class-based component & functional component
  • props & state
  • styling
  • Handle List
  • Life cycle Hooks

1. What is React?

It is a JavaScript Library for building User Interfaces.

和Angular相似,React 也将整个Project 分为小的 components, 便于管理和重复使用。

React components

2. Single Page Application vs Multi Page Application

SPA MPA
Only get back one HTML file from the server.
We get this back at the first time as user visit the page.
We get back multiple HTML pages, where each page has the content for a given route
Content is rendered on Client Content is rendered on server
Every component is managed by React and the entire page is also managed by a root React component. Only some widgets (like a image gallery) is mamaged by React.



image.png

  • Create React App (简称CRA)

CRA是创建 React 应用的一个脚手架,它与其他脚手架不同的一个地方就是将一些复杂工具(比如 webpack)的配置封装了起来,让使用者不用关心这些工具的具体配置,从而降低了工具的使用难度。

npm install -g create-react-app

create-react-app my-app
cd my-app/
npm start


3. What is JSX?

It is a syntax extension to JavaScript.

const element = 

Hello world!

After compilation, JSX expressions become regular JavaScript function all and evalute to JavaScript objects.

This means that you can use JSX inside of if statement and for loops, assign it to variables, accept it as arguments, and return it from functions.

function getGreeting(user) {
  if (user) {
    return 

Hello, {formatName(user)}!

; } return

Hello, Stranger.

;}
  • JSX Prevents Injection Attacks
const title = response.potentiallyMaliciousInput;
// This is safe:
const element = 

{title}

;

Because by default, React DOM escapes any values embedded in JSX before rendering them. Everything is converted to a String before rendered. This helps prevent XSS (cross-site-scripting) attacks.

  • React.createElement()
    Babel compiles JSX down to React.createElement() calls.

These two examples are identical:

const element = (
  

Hello, world!

); ------------------------------------------------------------------------------- const element = React.createElement( 'h1', {className: 'greeting'}, 'Hello, world!' );


4.Component

Components are the core building block of React apps. Actually, React is just a library for creating components in its core.

A typical React app therefore could be depicted as a component tree - having one root component ("App") and then an potentially infinite amount of nested child components.

Each component needs to return/ render some JSX code - it defines which HTML code React should render to the real DOM in the end.

JSX is NOT HTML but it looks a lot like it. Differences can be seen when looking closely though (for example className in JSX vs class in "normal HTML"). JSX is just syntactic sugar for JavaScript, allowing you to write HTMLish code instead of nested React.createElement(...) calls.

  • Two different ways to create components:

Functional components (also referred to as "presentational", "dumb" or "stateless" components ):

const cmp = () => { return

some JSX
}
(using ES6 arrow functions as shown here is recommended but optional)

class-based components (also referred to as "containers", "smart" or "stateful" components) :

class Cmp extends React.Component { render () { return

some JSX
} }
We'll of course dive into the difference throughout this course, you can already note that you should use 1) as often as possible though. It's the best-practice.

functional vs. class-based

不论用哪种方式创建component, component名称必须首字母大写。

  • 添加动态内容

1). 将简短的可执行JS代码放在大括号 {} 内

I am a person and I am {Math.floor(Math.random()*30)} years old.

2). 使用 props,实现写入动态数据:
Props is an object that includes all attributes you added to your JSX code. It allows you to pass data from a parent (wrapping) component to a child (embedded) component.

const person = (props) => {
  return 

I am {props.name} and I am {Math.floor(Math.random()*30)} years old.

}
class Person extends React.Component {
  render() {
    return 

Hello, {this.props.name}

; } }
  • Children props
    It is a revserved word, it refers to any elements between an open and closed tag of our components.

  • 使用PropTypes

npm install --save prop-types ----- 使用 npm 安装

可以在component中导入并引用,避免外部传入错误类型的props。当外部传入props类型与定义类型不一致时报错。

import React, {Component} from 'react'
import classes from'./Person.module.css';
import Aux from '../../../hoc/Auxiliary';
import withClass from '../../../hoc/WithClasses';
import PropTypes from 'prop-types';

class Person extends Component{
    render(){
        console.log('[Person.js] rendering...');
        const style = {
            color: 'red',
            textDecoration: 'underline',
            cursor: 'pointer'
        }

        return (
            
                

I am {this.props.name} and I am {this.props.age} years old.

{this.props.children}



delete me

) } }; Person.propTypes = { click: PropTypes.func, name: PropTypes.string, age: PropTypes.number, change: PropTypes.func } export default withClass(Person, classes.Person);



3). 使用State

使用props或者state 从父组件向子组件传递数据。

Pure: Functions that do not try to change their own inputs, and always return the same result for the same inputs.
Impure: Functions that will change their own inputs.

All Reacl components must act like pure functions with respect to their props. State allows React components to changes their output over time in response to user actions, network responses, and anything else, without violationg the rule.

State is used to change the component state from within. Only class-based components can define and use state.
state simply is a property of the component class, you have to call it state though - the name is not optional. You can then access it via this.state in your class JSX code (which you return in the required render() method).

Whenever state changes (taught over the next lectures), the component will re-render and reflect the new state. The difference to props is, that this happens within one and the same component - you don't receive new data (props ) from outside!

  • setState()
    Always use setState() function to change state values.
    如果直接用等号赋值修改,react 不会识别。 在React V16.8 之前,functional components中不能访问state,且不能使用setState()方法。
// Wrong
this.state.comment = 'Hello';

// Correct
this.setState({comment: 'Hello'});


  • When you want to update a state depending on its old value:
 state = {
    changeCounter: 0
  };

// Wrong
this.setState({
        changeCounter: this.state.changeCounter+1
      })

Beacuse setStatedoes not immediately trigger an update of the state of this component in a re-render cycle. Instead it is scheduled by React and React will then perform the state update and re-render cycle when it has the resources to do that.
In other words, the update could be instantly in simple applications, but it is not guaranteed. So, sometimes, the value you are depending on could be an unexpected value.

setState() 方法可以接受一个 Javascript 对象,也可以接受一个arrow function,在此匿名方法中,返回你的JavaScript 对象。

Here is the correct way:

this.setState((prevState, props) => {
        return{
          people:persons,
        changeCounter: prevState.changeCounter+1
        }
      }


  • useState Hook

    Use React Hook useState() to initialize and set states. React V16.8 之后,可以使用 useStatehook 在functional component 中操控state

    The useState hook always return an array with two elements:

    1. The current state object.
    2. A function to set current state values.
const [personState, setpersonState] = useState({
      people: [
        {name: 'Acde', age: 39},
        {name: 'Bob', age: 22},
        {name: 'Carial', age: 29},
      ]
  });


  • 使用props&state 跨组件通讯
    示例:
// In parent component
const switchNameHandler = (newName) => {
    setpersonState({
        people:[
          {name: newName, age: 39},
          {name: 'Bob', age: 44},
          {name: 'Carial', age: 99},
        ]}
  )};

// In return
//Two ways to pass the parament, the first will be more efficient
       
       switchNameHandler('ChangedByPerson')}/>
// In child component
import React from 'react'

const person = (props) => {
return (
    

I am {props.name} and I am {props.age} years old.

{props.children}

) } export default person;


5. Conditionally Rendering

1). Logical && operator

return (
    

Hello!

{unreadMessages.length > 0 &&

You have {unreadMessages.length} unread messages.

}
);

2). 在{}中使用三元表达式(ternary expression) condition ? trueActions : faseActions

return(
      {
        showPerson === true ?
        
switchNameHandler('ChangedByPerson')}/> My hobbies: Racing
: null } )

3). 使用if-else condition 将需要动态展示的JSX代码打包

let persons = null;
  if(showPerson){
    persons = (
      
switchNameHandler('ChangedByPerson')}/> My hobbies: Racing
) } return( {persons} )


  • List
    不同于Angular中的ngFor,React使用Javascript中自带的map() 方法,遍历list
let persons = null;
  if(showPerson){
    persons = (
      
{personState.people.map((person, index) => { return })}
) }


  • map():
    注意,map方法只能遍历数组对象,如果需要遍历String,需要将String先转化成Array Object. 否则报错,str.map() is not a function..

String -> Array: [...myStr], myStr.split("")
Array -> String: myArr.join('')


  • key
    使用此种方法时,需要加上key property. The key here should be something unique, which allows React to compare the difference between list items. So that we don't need to rerender the whole list everytime.


6. Styling React Component & Element

  • Set Styles Dynamically:
    通过JavaScript的方式,在相应的condition中修改相关style属性。
const style = {
    backgroundColor: 'rgb(188, 245, 218)',
    font: 'inherit',
    border: '1x solid blue',
    padding: '8px',
    cursor: 'pointer',
    marginRight: '10px',
    ':hover': {
      backgroundColor: 'rgb(155, 209, 177)',
      color: 'white'
    }
  }

if(someCondition){
  ...
  style.backgroundColor = 'rgb(247, 171, 171)';
}


  • Dynamic add css classes:
    创建一个空数组,在不同条件下,push css styles
// In CSS file
.red{
  color: brown;
}

.bold{
  font-weight: bold;
}
//In JS file
const classes = [];
  if(condition1){
    classes.push('red');
  }
  if(condition2){
    classes.push('bold');
  }

return(
  

Hello, {props.name}

)


  • Using Radium:
    Radium is a package that helps us with styling React Components.
    引入Radium可以让我们在自定义的inline style中使用 css psudo selector,以及media query.

步骤:

  1. npm install --save radium
  2. import Radium from 'radium'
  3. Wrap function name when export: export default Radium(App);
  4. 使用media query时:
    import {StyleRoot} from 'radium'
    All content in App.js return


  • Using hover:
import Radium, {StyleRoot} from 'radium';
const App = props => {
  const style = {
    backgroundColor: 'rgb(188, 245, 218)',
    font: 'inherit',
    border: '1x solid blue',
    padding: '8px',
    cursor: 'pointer',
    marginRight: '10px',
    ':hover': {
      backgroundColor: 'rgb(155, 209, 177)',
      color: 'white'
    }
  }
  return(
    
  )
}

export default Radium(App);


  • Using media query:
import Radium from 'radium';
const person = (props) => {
    const style = {
        '@media (min-width: 700px)' : {
             width: '450px'
        }
    };

return (
    
... Any content
) } export default Radium(person); --------------------------------------------------In App.js--------------------------------------------------- return ( ...Any content )


  • CSS Modules:

    CSS Modules are a relatively new concept (you can dive super-deep into them here: https://github.com/css-modules/css-modules). With CSS modules, you can write normal CSS code and make sure, that it only applies to a given component.

    It's not using magic for that, instead it'll simply automatically generate unique CSS class names for you. And by importing a JS object and assigning classes from there, you use these dynamically generated, unique names. So the imported JS object simply exposes some properties which hold the generated CSS class names as values.

Example:

In Post.css File

 .Post  {
 color: red;
 }

In Post Component File

 import classes from  './Post.css';
   const post =  ()  =>  (
      
...
);

Here, classes.Post refers to an automatically generated Post property on the imported classes object. That property will in the end simply hold a value like Post__Post__ah5_1 .

So your .Post class was automatically transformed to a different class (Post__Post__ah5_1 ) which is unique across the application. You also can't use it accidentally in other components because you don't know the generated string! You can only access it through the classes object. And if you import the CSS file (in the same way) in another component, the classes object there will hold a Post property which yields a different (!) CSS class name. Hence it's scoped to a given component.

By the way, if you somehow also want to define a global (i.e. un-transformed) CSS class in such a .css file, you can prefix the selector with :global .

Example:

:global .Post { ... }

Now you can use className="Post" anywhere in your app and receive that styling.


7. Component Lifecycle

部分内容来源于:React life cycle in-depth

lifecycle hooks

Thay are Only available in Class-based Components
React will execute them for us automatically and they will run at different points of time and we can do different things with them. For example, fetch data from the web or do some cleanup work before a component is removed from the DOM.

React life cycle 遵循 “创建,更新,死亡” 的发展规律, 可分为3个阶段:

1). 出生/创建

这个阶段是开发人员初始化一个组件(Component)的阶段,包括定义和配置propsstate。这个component和其所有的子组件都会被装载到本地的UI堆栈上(Native UI Stack),例如DOM或UIVIew。
一个组件的出生/创建阶段只会发生一次。

constructor()
getDefaultProps() (React.createClass) or MyComponent.defaultProps (ES6 class)
getInitialState() (React.createClass) or this.state = ... (ES6 constructor)
getDerivedStateFromProps()
componentWillMount()
render()
Children initialization & life cycle kickoff
componentDidMount()

creation lifecycle


  • render()
    在render() 方法中,我们通过JSX创建元素,并将他们返回。不能在render()中修改任何state。

    The render() method being called does not immediately also render this to the real DOM. Instead, it compares the virtual DOM. It has an old virtual DOM and a Re-render virtual DOM. The virtual DOM is faster than the real DOM.

    React compares the old virtual DOM with the new one and checks if there is any differences. If there are some differences, it reaches out to the real DOM and only updates the places where differences are detected.

    How React render the DOM


  • componentDidMount()

    This method is called once all our children Elements and our Component instances are mounted onto the native UI. When this method is called we now have access to the Native UI (DOM, UIView, etc.), access to our children refs and the ability to potentially trigger a new render pass.

执行render 方法时,遍历顺序为从上到下。

A -> A.0 -> A.0.0 -> A.0.1 -> A.1 -> A.2.

componentDidMount 则相反,其顺序为从下至上。

A.2 -> A.1 -> A.0.1 -> A.0.0 -> A.0 -> A

通过倒序遍历,可以确保每个子组件都以安置,且执行了自己的componentDidMount() 方法。这使得父组件可以访问其自己的UI element和其所有子组件。

Useful Task:
1).componentDidMount() 最通常的用途为处理UI交互和初始化第三方 UI 库。

For example, we may need to make changes to our current state based on how the Native UI laid out our content. We may need to figure out the current width/height of our children or our own instance. This is especially helpful in the browser where CSS layout drives a lot of our DOM calculations.

Another useful task is setting up 3rd party UIs. For example, if we wanted to use a library like C3.js or the Date Range Picker, this is where we would initialize our UI libraries.

2). Making HTTP requests.



2). 成长/更新

在此阶段中,开发人员会更新props,state,处理用户交互,进行跨组件通讯。这个阶段也是我们在一个组件的生命周期中花费时间最多的阶段。
与一三两阶段不同的是,我们往往会不断重复 “生长/更新” 阶段。

getDerivedStateFromProps()
componentWillReceiveProps()
shouldComponentUpdate()
componentWillUpdate()
render()
Children Life cycle methods
getSnapshotBeforeUpdate()
componentDidUpdate()

update lifecycle


  • shouldComponentUpdate(): A hook to optmize performance
    This method allows your Component to exit the Update life cycle if there is no reason to apply a new render. Out of the box, the shouldComponentUpdate() is a no-op that returns true. This means every time we start an Update in a Component, we will re-render.
    The Goal is to Prevent unnecessary renders.

    在此方法中,我们可以判断现有的props & statenext prop & next state是否继续一致。如果一致则返回false,如果不同则返回true.

 shouldComponentUpdate(nextProps, nextState) {
    return nextProps.show !== this.props.show
}

如果需要比较组件中所有props是否发生了任意变化,则可以不是用此方法一一比较,采用extends PureComponent

  • PureComponent
    It is a normal component that already implements shouldComponentUpdate with a complete props check. It checks any changes in any props of that component.
    You can use it by class App extends PureComponent.

  • React.memo()
    When React.memo() wraps a component, React memoizes the rendered output then skips unnecessary rendering.

  • useEffect
    useEffect is a React Hook, which allows you to combines the functionality or the use cases you cover of all these class-base lifecycle hooks in one React hook.

    -- It takes a default function for every render cycle. It runs for every update.
    -- You can also return a function, which runs BEFORE the main useEffect function runs, but AFTER the first render cycle.
    -- To control the behavior of useEffect, there is a second parameter. It is an array, where you simply point at all the data that actually are used in your effect.

    For the example code below:
    It only executes when people change props.
    If the array is empty, it will only run for the first time when the app gets rendered.
    If you don't pass an array as a second parameter, it will run on every ender cycle.

 useEffect(() => {
        console.log('[Cockpit.js] useEffect');
        
        setTimeout(()=>{
            alert("This is from useEffect");
        }, 1000);
    }, [props.people]);



3). 死亡/卸载
此阶段往往发生于当一个组件从DOM上被移除(unmounted)的时候。通常是用户导航离开,UI页面改变,组件暂时被隐藏等情况发生时。
此阶段只发生一次,并为组件被垃圾回收做出准备。

This method is used to handle memory leaks.

componentWillUnmount()
Children Life cycle methods
Instance destroyed for Garbage Collection

PS: 被划去的方法已被React取消或由其他方法取代,将于React17 停用。

8. Virtual DOM

A virtual DOM object is a representation of a DOM object, like a lightweight copy.
React updates the view by comparing different versions of virtual DOMs.
































你可能感兴趣的:(React 学习笔记(上))