(hello-react)React: Section 3: Understanding the Base Features & Syntax

第 3 節練習:認識基本語法(JSX,Component,Props,State,useState() Hook,Binding,Styles)。

1. JSX Restrictions

JSX 是 Javascript 的語法擴充,在寫 React 時透過這個語法來描述使用者介面的外觀。

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

ReactDOM.render(
  <App/>,
  document.getElementById('root')
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

App.js

// import logo from './logo.svg';
import './App.css';
// import { render } from 'react-dom';
import { Component } from 'react';

//function App() {
class App extends Component{
  render() {
    return (
      <div className="App">
        <h1>Hi, I'm a React App, Wendy</h1>
        <p>This is really working!</p>
      </div>
    );
    //return React.createElement('div', {classname: 'App'}, React.createElement('h1', null, 'Does this work now?'));
  }
}

export default App;

呈現結果:

2. Create a Funcional Component

建立 Person 目錄和 Person.js 檔案

Person.js

import React from 'react';

const person =() => {
    return <p>I'm a Person</p>
}

export default person;

App.js

// import logo from './logo.svg';
import './App.css';
// import { render } from 'react-dom';
import { Component } from 'react';
import Person from './Person/Person';

//function App() {
class App extends Component{
  render() {
    return (
      <div className="App">
        <h1>Hi, I'm a React App, Wendy</h1>
        <p>This is really working!</p>
        <Person />
      </div>
    );
    //return React.createElement('div', {classname: 'App'}, React.createElement('h1', null, 'Does this work now?'));
  }
}

export default App;

呈現結果:

3. Outputting Dynamic Content

Person.js

import React from 'react';

const person =() => {
    return <p>I'm a Person and I am {Math.floor(Math.random() * 30)} years old.</p>
}

export default person;

App.js

// import logo from './logo.svg';
import './App.css';
// import { render } from 'react-dom';
import { Component } from 'react';
import Person from './Person/Person';

//function App() {
class App extends Component{
  render() {
    return (
      <div className="App">
        <h1>Hi, I'm a React App, Wendy</h1>
        <p>This is really working!</p>
        <Person />
        <Person />
        <Person />
      </div>
    );
    //return React.createElement('div', {classname: 'App'}, React.createElement('h1', null, 'Does this work now?'));
  }
}

export default App;

呈現結果:

4. Working with Props

Person.js

import React from 'react';

const person =(props) => {
    return <p>I'm {props.name} and I am {props.age} years old.</p>
}

export default person;

App.js

// import logo from './logo.svg';
import './App.css';
// import { render } from 'react-dom';
import { Component } from 'react';
import Person from './Person/Person';

//function App() {
class App extends Component{
  render() {
    return (
      <div className="App">
        <h1>Hi, I'm a React App, Wendy</h1>
        <p>This is really working!</p>
        <Person name="Max" age="28"/>
        <Person name="Manu" age="29">My Hobbies:Racing</Person>
        <Person name="Stephanie" age="26"/>
      </div>
    );
    //return React.createElement('div', {classname: 'App'}, React.createElement('h1', null, 'Does this work now?'));
  }
}

export default App;

呈現結果:

5. Understanding & Using State

state 是讓元件控制自己的狀態,主要作用是用元件保存,控制以及修改自己可變的狀態。

props 是讓外部對元件自己進行配置,是 React 父元件與子元件間溝通的橋樑,是靜態(唯獨)的,且是不可改變的。

Person.js

import React from 'react';

const person = (props) => {
    return (
        <div>
            <p>I'm {props.name} and I am {props.age} years old.</p>
            <p>{props.children}</p>
        </div>
    )
}

export default person;

App.js

// import logo from './logo.svg';
import './App.css';
// import { render } from 'react-dom';
import { Component } from 'react';
import Person from './Person/Person';

//function App() {
class App extends Component{
  state = {
    persons: [
      { name:'Max', age: 28 },
      { name:'Manu', age: 29 },
      { name:'Stephanie', age: 26 }
    ]
  } 

  render() {
    return (
      <div className="App">
        <h1>Hi, I'm a React App, Wendy</h1>
        <p>This is really working!</p>
        <button>Switch name</button>
        <Person name={this.state.persons[0].name} age={this.state.persons[0].age}/>
        <Person name={this.state.persons[1].name} age={this.state.persons[1].age}>My Hobbies:Racing</Person>
        <Person name={this.state.persons[2].name} age={this.state.persons[2].age}/>
      </div>
    );
    //return React.createElement('div', {classname: 'App'}, React.createElement('h1', null, 'Does this work now?'));
  }
}

export default App;

呈現結果:

6. Handing Events with Methods & Manipulating the State

App.js

// import logo from './logo.svg';
import './App.css';
// import { render } from 'react-dom';
import { Component } from 'react';
import Person from './Person/Person';

//function App() {
class App extends Component{
  state = {
    persons: [
      { name:'Max', age: 28 },
      { name:'Manu', age: 29 },
      { name:'Stephanie', age: 26 }
    ],
    otherState: 'Some other value'
  } 
  
  switchNameHandler = () => {
    //console.log('Was clicked!');
    //DON'T DO THIS: this.state.persons[0],name = 'Maximilion';
    this.setState({
      persons: [
        { name:'Maximilion', age: 28 },
        { name:'Manu', age: 29 },
        { name:'Stephanie', age: 27 }
      ]
    })
  }

  render() {
    return (
      <div className="App">
        <h1>Hi, I'm a React App, Wendy</h1>
        <p>This is really working!</p>
        <button onClick={this.switchNameHandler}>Switch name</button>
        <Person name={this.state.persons[0].name} age={this.state.persons[0].age}/>
        <Person name={this.state.persons[1].name} age={this.state.persons[1].age}>My Hobbies:Racing</Person>
        <Person name={this.state.persons[2].name} age={this.state.persons[2].age}/>
      </div>
    );
    //return React.createElement('div', {classname: 'App'}, React.createElement('h1', null, 'Does this work now?'));
  }
}

export default App;

呈現結果:點按鈕時

7. Using the useState() Hook for State Manipulation

conset [ state, setState ] = useState(initialState);

回傳一個 state 的值,以及更新 state 的 function。

在首次 rander 時,回傳的 state 的值會跟第一個參數(initialState)一樣。

setState function 是用來更新 state。它接收一個新的 state 並將 component 的重新 render 排進隊列。

App.js

// import logo from './logo.svg';
import './App.css';
// import { render } from 'react-dom';
import { useState } from 'react';
import Person from './Person/Person';

//function App() {
//class App extends Component{
const app = props => {
  const [ personsState, setPersonsState ] = useState({
    persons: [
      { name:'Max', age: 28 },
      { name:'Manu', age: 29 },
      { name:'Stephanie', age: 26 }
    ]
  });

  const [otherState, setOtherState] = useState('Some other value');

  console.log(personsState, otherState);

  const switchNameHandler = () => {
    //console.log('Was clicked!');
    //DON'T DO THIS: this.state.persons[0],name = 'Maximilion';
    setPersonsState({
      persons: [
        { name:'Maximilion', age: 28 },
        { name:'Manu', age: 29 },
        { name:'Stephanie', age: 27 }
      ]
    });
  };

    return (
      <div className="App">
        <h1>Hi, I'm a React App, Wendy</h1>
        <p>This is really working!</p>
        <button onClick={switchNameHandler}>Switch name</button>
        <Person name={personsState.persons[0].name} age={personsState.persons[0].age}/>
        <Person name={personsState.persons[1].name} age={personsState.persons[1].age}>My Hobbies:Racing</Person>
        <Person name={personsState.persons[2].name} age={personsState.persons[2].age}/>
      </div>
    );
  }

export default app;

呈現結果:點按鈕時

8. Passing Method References Between Components

Person.js

import React from 'react';

const person = (props) => {
    return (
        <div>
            <p onClick={props.click}>I'm {props.name} and I am {props.age} years old.</p>
            <p>{props.children}</p>
        </div>
    )
}

export default person;

App.js

// import logo from './logo.svg';
import './App.css';
// import { render } from 'react-dom';
import { Component } from 'react';
import Person from './Person/Person';

//function App() {
class App extends Component{
  state = {
    persons: [
      { name:'Max', age: 28 },
      { name:'Manu', age: 29 },
      { name:'Stephanie', age: 26 }
    ],
    otherState: 'Some other value'
  } 
  
  switchNameHandler = (newName) => {
    //console.log('Was clicked!');
    //DON'T DO THIS: this.state.persons[0],name = 'Maximilion';
    this.setState({
      persons: [
        { name:newName, age: 28 },
        { name:'Manu', age: 29 },
        { name:'Stephanie', age: 27 }
      ]
    })
  }

  render() {
    return (
      <div className="App">
        <h1>Hi, I'm a React App, Wendy</h1>
        <p>This is really working!</p>
        <button onClick={this.switchNameHandler.bind(this, 'Maximilion')}>Switch name</button>
        <Person name={this.state.persons[0].name} age={this.state.persons[0].age}/>
        <Person name={this.state.persons[1].name} age={this.state.persons[1].age} click={this.switchNameHandler.bind(this, 'Max!')}>My Hobbies:Racing</Person>
        <Person name={this.state.persons[2].name} age={this.state.persons[2].age}/>
      </div>
    );
    //return React.createElement('div', {classname: 'App'}, React.createElement('h1', null, 'Does this work now?'));
  }
}

export default App;

呈現結果:點 Menu 時

or App.js

// import logo from './logo.svg';
import './App.css';
// import { render } from 'react-dom';
import { Component } from 'react';
import Person from './Person/Person';

//function App() {
class App extends Component{
  state = {
    persons: [
      { name:'Max', age: 28 },
      { name:'Manu', age: 29 },
      { name:'Stephanie', age: 26 }
    ],
    otherState: 'Some other value'
  } 
  
  switchNameHandler = (newName) => {
    //console.log('Was clicked!');
    //DON'T DO THIS: this.state.persons[0],name = 'Maximilion';
    this.setState({
      persons: [
        { name:newName, age: 28 },
        { name:'Manu', age: 29 },
        { name:'Stephanie', age: 27 }
      ]
    })
  }

  render() {
    return (
      <div className="App">
        <h1>Hi, I'm a React App, Wendy</h1>
        <p>This is really working!</p>
        <button onClick={() => this.switchNameHandler('Maximilion!!')}>Switch name</button>
        <Person name={this.state.persons[0].name} age={this.state.persons[0].age}/>
        <Person name={this.state.persons[1].name} age={this.state.persons[1].age} click={this.switchNameHandler.bind(this, 'Max!')}>My Hobbies:Racing</Person>
        <Person name={this.state.persons[2].name} age={this.state.persons[2].age}/>
      </div>
    );
    //return React.createElement('div', {classname: 'App'}, React.createElement('h1', null, 'Does this work now?'));
  }
}

export default App;

呈現結果:點按鈕時

9. Adding Two Way Binding

Person.js

import React from 'react';

const person = (props) => {
    return (
        <div>
            <p onClick={props.click}>I'm {props.name} and I am {props.age} years old.</p>
            <p>{props.children}</p>
            <input type="text" onChange={props.changed} value={props.name}/>
        </div>
    )
}

export default person;

App.js

// import logo from './logo.svg';
import './App.css';
// import { render } from 'react-dom';
import { Component } from 'react';
import Person from './Person/Person';

//function App() {
class App extends Component{
  state = {
    persons: [
      { name:'Max', age: 28 },
      { name:'Manu', age: 29 },
      { name:'Stephanie', age: 26 }
    ],
    otherState: 'Some other value'
  } 
  
  switchNameHandler = (newName) => {
    //console.log('Was clicked!');
    //DON'T DO THIS: this.state.persons[0],name = 'Maximilion';
    this.setState({
      persons: [
        { name:newName, age: 28 },
        { name:'Manu', age: 29 },
        { name:'Stephanie', age: 27 }
      ]
    })
  }

  nameChangedHandler = (event) => {
    this.setState({
      persons: [
        { name:'Max', age: 28 },
        { name:event.target.value, age: 29 },
        { name:'Stephanie', age: 26 }
      ]
    })
  }

  render() {
    return (
      <div className="App">
        <h1>Hi, I'm a React App, Wendy</h1>
        <p>This is really working!</p>
        <button onClick={() => this.switchNameHandler('Maximilion!!')}>Switch name</button>
        <Person name={this.state.persons[0].name} age={this.state.persons[0].age}/>
        <Person name={this.state.persons[1].name} age={this.state.persons[1].age} click={this.switchNameHandler.bind(this, 'Max!')} changed={this.nameChangedHandler}>My Hobbies:Racing</Person>
        <Person name={this.state.persons[2].name} age={this.state.persons[2].age}/>
      </div>
    );
    //return React.createElement('div', {classname: 'App'}, React.createElement('h1', null, 'Does this work now?'));
  }
}

export default App;

呈現結果:於第二個輸入框輸入時

10. Adding Styling with Stylesheets

在 Person 目錄建立 Person.css 檔案

Person.css

.Person{
    width: 60%;
    margin: 16px auto;
    border: 1px solid #eee;
    box-shadow: 0 2px 3px #ccc;
    padding: 16px;
    text-align: center;
}

Person.js

import React from 'react';
import './Person.css';

const person = (props) => {
    return (
        <div className="Person">
            <p onClick={props.click}>I'm {props.name} and I am {props.age} years old.</p>
            <p>{props.children}</p>
            <input type="text" onChange={props.changed} value={props.name}/>
        </div>
    )
}

export default person;

呈現結果:

11. Working with Inline Styles

 App.js

// import logo from './logo.svg';
import './App.css';
// import { render } from 'react-dom';
import { Component } from 'react';
import Person from './Person/Person';

//function App() {
class App extends Component{
  state = {
    persons: [
      { name:'Max', age: 28 },
      { name:'Manu', age: 29 },
      { name:'Stephanie', age: 26 }
    ],
    otherState: 'Some other value'
  } 
  
  switchNameHandler = (newName) => {
    //console.log('Was clicked!');
    //DON'T DO THIS: this.state.persons[0],name = 'Maximilion';
    this.setState({
      persons: [
        { name:newName, age: 28 },
        { name:'Manu', age: 29 },
        { name:'Stephanie', age: 27 }
      ]
    })
  }

  nameChangedHandler = (event) => {
    this.setState({
      persons: [
        { name:'Max', age: 28 },
        { name:event.target.value, age: 29 },
        { name:'Stephanie', age: 26 }
      ]
    })
  }

  render() {
    const style = {
      backgroindColor: 'white',
      font: 'inherit',
      border: '1px solid blue',
      padding: '8px',
      cursor: 'pointer'
    };

    return (
      <div className="App">
        <h1>Hi, I'm a React App, Wendy</h1>
        <p>This is really working!</p>
        <button style={style} onClick={() => this.switchNameHandler('Maximilion!!')}>Switch name</button>
        <Person name={this.state.persons[0].name} age={this.state.persons[0].age}/>
        <Person name={this.state.persons[1].name} age={this.state.persons[1].age} click={this.switchNameHandler.bind(this, 'Max!')} changed={this.nameChangedHandler}>My Hobbies:Racing</Person>
        <Person name={this.state.persons[2].name} age={this.state.persons[2].age}/>
      </div>
    );
    //return React.createElement('div', {classname: 'App'}, React.createElement('h1', null, 'Does this work now?'));
  }
}

export default App;

呈現結果: