第一个React Web应用程序

2022-07-17 10:09:40 浏览数 (1)

learn from 《React全家桶:前端开发与实例详解》 https://zh-hans.reactjs.org/tutorial/tutorial.html https://zh-hans.reactjs.org/docs/create-a-new-react-app.html#create-react-app

  • 安装 Node.js
  • 安装 npm install -g live-server,配置环境变量 path C:UsersuserAppDataRoamingnpm
代码语言:javascript复制
npx create-react-app react_learning
cd react_learning
npm start

1. JSX

对 javascript 的扩展,代码显示更优雅,与 react 配合很好

Babel

目前(2022-07), 并不是所有的 浏览器 都支持 ES6,Babel 可以转译 ES6 -> ES5

head 里包含了 <script src="vendor/babel-standalone.js"></script>

index.html

代码语言:javascript复制
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Project One</title>
    <link rel="stylesheet" href="./semantic-dist/semantic.css" />
    <link rel="stylesheet" href="./style.css" />
    <script src="vendor/babel-standalone.js"></script>
    <script src="vendor/react.js"></script>
    <script src="vendor/react-dom.js"></script>
  </head>

  <body>
    <div class="main ui text container">
      <h1 class="ui dividing centered header">Popular Products</h1>
      <div id="content"></div>
    </div>
    <script src="./js/seed.js"></script>
    <script
            type = "text/babel"
            data-plugins="transform-class-properties"
            src="./js/app.js"></script>

  </body>

</html>

app.js

代码语言:javascript复制
class ProductList extends React.Component {
    render() {
        return (
            <div className='ui unstackable items'>
                <Product/>  {/*子组件*/}
            </div>
        );
    }
}

class Product extends React.Component {
    render() {
        return (
            <div className='item'>
                <div className='image'>
                    <img src='images/products/image-aqua.png'/>
                </div>
                <div className='middle aligned content'>
                    <div className='description'>
                        <a>Fort Knight</a>
                        <p>Authentic renaissance actors, delivered in just two weeks.</p>
                    </div>
                    <div className='extra'>
                        <span>Submitted by:</span>
                        <img
                            className='ui avatar image'
                            src='images/avatars/daniel.jpg'
                        />
                    </div>
                </div>
            </div>
        );
    }
}

ReactDOM.render(
    <ProductList/>,  // 渲染的组件
    document.getElementById('content')
    // 渲染的组件位置 index.html 里的 id=content 的组件
)

2. 动态组件

  • 数据驱动的组件,数据从父组件 流向 子组件,是通过 props 实现的

JSX属性值必须由 {} or "" 分隔

代码语言:javascript复制
class ProductList extends React.Component {
    render() {
        const product = Seed.products[0];
        return (
            <div className="ui unstackable items">
                <Product
                    id={product.id}
                    title={product.title}
                    description={product.description}
                    url={product.url}
                    votes={product.votes}
                    submitterAvatarUrl={product.submitterAvatarUrl}
                    productImageUrl={product.productImageUrl}
                />
            </div>
        );
    }
}

class Product extends React.Component {
    render() {
        return (
            <div className='item'>
                <div className='image'>
                    <img src={this.props.productImageUrl}/>
                </div>
                <div className='middle aligned content'>
                    <div className='header'>
                        <a>
                            <i className='large caret up icon'/>
                        </a>
                        {this.props.votes}
                    </div>
                    <div className='description'>
                        <a href={this.props.url}>
                            {this.props.title}
                        </a>
                        <p>
                            {this.props.description}
                        </p>
                    </div>
                    <div className='extra'>
                        <span>Submitted by:</span>
                        <img
                            className='ui avatar image'
                            src={this.props.submitterAvatarUrl}
                        />
                    </div>
                </div>
            </div>
        );
    }
}

3. 渲染多个组件

  • 使用 map 函数,对多个组件进行处理
代码语言:javascript复制
class ProductList extends React.Component {
    render() {
        const productComponents = Seed.products.map(
            (product) => (
                <Product
                    key={'product-'   product.id}
                    id={product.id}
                    title={product.title}
                    description={product.description}
                    url={product.url}
                    votes={product.votes}
                    submitterAvatarUrl={product.submitterAvatarUrl}
                    productImageUrl={product.productImageUrl}
                />
            )
        );
        return (
            <div className="ui unstackable items">
                {productComponents}
            </div>
        )
    }
}
  • 排序 sort
代码语言:javascript复制
		const products = Seed.products.sort(
            (a, b) => (b.votes - a.votes)
        );
        const productComponents = products.map......

按照投票数从上到下降序排列

sort 方法改变了原始数组,是一种危险的行为,需要小心bug

4. 事件响应

  • 子组件可以读取其 props ,但是无法修改,props 是属于父组件的
  • 父组件拥有子组件的 props

可以将 函数 作为 props 传递给 子组件

代码语言:javascript复制
class ProductList extends React.Component {
    handleProductUpVote(productId){
        console.log(productId   ' was upvoted.');
    }
    。。。

				<Product
                    key={'product-'   product.id}
                    id={product.id}
                    。。。
                    onVote={this.handleProductUpVote}
                />
                
class Product extends React.Component {
    constructor(props) { // 构造函数
        super(props);
        this.handleUpVote = this.handleUpVote.bind(this);
        // 自定义组件方法,需要手动将 this 绑定到自己的组件
    }
    handleUpVote() {
        this.props.onVote(this.props.id);
    }

    render() {
        return (
            。。。
                        <a onClick={this.handleUpVote}>
                            <i className='large caret up icon'/>
                        </a>
                )
  • 自定义组件方法,需要手动将 this 绑定到自己的组件
  • render 等函数,React 自动帮我们把 this 绑定到当前组件

可以看到控制台 (F12打开),输出了字符

5. 更新数据

  • this.state 是组件私有的,用 this.setState() 更改,组件 state 或 props 更新时,组件会重新渲染
  • 不要在 this.setState() 之外的地方修改 state!!!因为这个函数 是异步的,我们不知道它什么时候更新状态 并 重新渲染

map(),数组的 concat() ,不改变原数组,产生新的数组

如果想要修改,请修改副本,而不是原始对象

代码语言:javascript复制
class ProductList extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            products: []
        };
        this.handleProductUpVote = this.handleProductUpVote.bind(this);
    }

    componentDidMount() { // 组件挂载到页面后,react会调用该方法
        this.setState({products: Seed.products});
    }

    handleProductUpVote(productId){
        const nextProducts = this.state.products.map(
            (product) => {
                if(product.id === productId) {
                    return Object.assign({}, product, {
                        votes: product.votes   1,
                    });
                }
                else{
                    return product;
                }
            }
        );
        this.setState({products: nextProducts});
    }

    render() {
        const products = this.state.products.sort(
            (a, b) => (b.votes - a.votes)
        );
        const productComponents = products.map(
            (product) => (
                <Product
                    key={'product-'   product.id}
                    id={product.id}
                    title={product.title}
                    description={product.description}
                    url={product.url}
                    votes={product.votes}
                    submitterAvatarUrl={product.submitterAvatarUrl}
                    productImageUrl={product.productImageUrl}
                    onVote={this.handleProductUpVote}
                />
            )
        );
        return (
            <div className="ui unstackable items">
                {productComponents}
            </div>
        )
    }
}

class Product extends React.Component {
    constructor(props) {
        super(props);
        this.handleUpVote = this.handleUpVote.bind(this);
    }
    handleUpVote() {
        this.props.onVote(this.props.id);
    }

    render() {
        return (
            <div className='item'>
                <div className='image'>
                    <img src={this.props.productImageUrl}/>
                </div>
                <div className='middle aligned content'>
                    <div className='header'>
                        <a onClick={this.handleUpVote}>
                            <i className='large caret up icon'/>
                        </a>
                        {this.props.votes}
                    </div>
                    <div className='description'>
                        <a href={this.props.url}>
                            {this.props.title}
                        </a>
                        <p>
                            {this.props.description}
                        </p>
                    </div>
                    <div className='extra'>
                        <span>Submitted by:</span>
                        <img
                            className='ui avatar image'
                            src={this.props.submitterAvatarUrl}
                        />
                    </div>
                </div>
            </div>
        );
    }
}

ReactDOM.render(
    <ProductList/>,  // 渲染的组件
    document.getElementById('content')
    // 渲染的组件位置 index.html 里的 id=content 的组件
)

由于我们使用了插件 transform-class-properties(属性初始化器)

  • 可以写箭头函数来自定义组件方法,直接绑定 this 到组件
  • constructor() 函数之外定义初始状态
代码语言:javascript复制
<script
            type = "text/babel"
            data-plugins="transform-class-properties"
            src="./js/app.js"></script>

所以,可以这么写:

代码语言:javascript复制
class Product extends React.Component {
    // constructor(props) {
    //     super(props);
    //     this.handleUpVote = this.handleUpVote.bind(this);
    // }
    // handleUpVote() {
    //     this.props.onVote(this.props.id);
    // }

    handleUpVote = ()=>(
        this.props.onVote(this.props.id)
    )
代码语言:javascript复制
class ProductList extends React.Component {
    // constructor(props) {
    //     super(props);
    //     this.state = {
    //         products: []
    //     };
    //     this.handleProductUpVote = this.handleProductUpVote.bind(this);
    // }
    state = {products: []}; // 在 `constructor()` 函数之外定义初始状态

    handleProductUpVote = (productId) => {。。。}

0 人点赞