前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >React: JSX 、虚拟 DOM、组件配置(props、state、PropTypes、createContext、props.children)

React: JSX 、虚拟 DOM、组件配置(props、state、PropTypes、createContext、props.children)

作者头像
Michael阿明
发布2022-07-28 08:36:52
1.7K0
发布2022-07-28 08:36:52
举报
文章被收录于专栏:Michael阿明学习之路

文章目录

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

1. 虚拟 DOM

我们操作虚拟DOM,让 React 负责更改浏览器的 DOM

虚拟 DOM,指的是,表示实际 DOM 的 JavaScript 对象树

开发人员只需要返回需要的 DOM,React 负责转换,且性能有优化,速度很快(高效的差异算法、更新子树、批量更新DOM)

ReactElement 是 虚拟 DOM 中对 DOM 元素的表示

先创建 RE,再 render (RE, 到实际的DOM挂载位置, 回调函数)

2. JSX

JSX 是 JavaScript Syntax Extension

JSX可以很方便的编写 ReactElement(无状态,不可变) 层次结构

babel 插件 可以 将 JSX 转译成 JS

JSX 通常用 () 包含起来,JSX属性 用 {} 包含, JSX 内部注释 {/* 注释 */}

JSX 使用 className 标识类

JSX 不能使用 for 属性,而是 htmlFor

3. ReactComponent

ReactComponent 是一个 JS 对象,至少有一个 render() 函数,返回一个 ReactElement

4. props 是参数

props 是组件的输入

props 可以传递任何 JS 对象

  • 基本类型、简单 JS 对象
  • 原子操作、函数、React元素、虚拟DOM节点

5. PropTypes

是验证 props 传递的值 的一种方法,属性名 : PropsTypes (string, number, boolean, function, object, array, arrayOf, node, element)

代码语言:javascript
复制
import PropTypes from 'prop-types';
import React from 'react';

class DocumentedContainer extends React.Component {
  static propTypes = {
    children: PropTypes.oneOf([PropTypes.element, PropTypes.array])
  };

  render() {
    return <div className="container">{this.props.children}</div>;
  }
}

export default DocumentedContainer;

6. getDefaultProps() 获取默认 props

代码语言:javascript
复制
class Counter extends React.Component {
  static defaultProps = {
  		initialValue: 1
  	}
  	...
}

使用 <Counter /> ,<Counter initialValue={1}/> 两种用法效果一致

7. 上下文

从 React 16.3.0 开始,可以指定通过组件树向下传递的变量,无需手动将变量从父组件传递到子组件

  • React.createContext 只接受一个参数,上下文提供的默认值

相当于 全局公开 的属性

例如网站主题: theme.js

代码语言:javascript
复制
import React from 'react';

export const themes = {
  light: {
    foreground: '#222222',
    background: '#e9e9e9'
  },
  dark: {
    foreground: '#fff',
    background: '#222222'
  }
};

export const ThemeContext = React.createContext(themes.dark);

在 app 中: ThemeContext.Provider 用于把数据传递给子组件

代码语言:javascript
复制
import React, {Component} from 'react';

import {ThemeContext, themes} from './theme';
import './App.css';
import Header from './Header';

class App extends Component {
  state = {theme: themes.dark};

  changeTheme = evt => {
    this.setState(state => ({
      theme: state.theme === themes.dark ? themes.light : themes.dark
    }));
  };

  render() {
    return (
      <div className="App">
        <ThemeContext.Provider value={this.state.theme}>
          <Header />
          <p className="App-intro">
            To get started, edit <code>src/App.js</code> and save to reload.
          </p>

          <button onClick={this.changeTheme}>Change theme</button>
        </ThemeContext.Provider>
      </div>
    );
  }
}

export default App;

Header.js ThemeContext.Consumer 从 Provider 父组件中获取主题

代码语言:javascript
复制
import React from 'react';
import logo from './logo.svg';

import {ThemeContext} from './theme';

export const Header = props => (
  <ThemeContext.Consumer>
    {theme => (
      <header
        className="App-header"
        style={{backgroundColor: theme.background}}
      >
        <img src={logo} className="App-logo" alt="logo" />
        <h1 className="App-title" style={{color: theme.foreground}}>
          Welcome to React
        </h1>
      </header>
    )}
  </ThemeContext.Consumer>
);

export default Header;

8. 多个上下文

user.js

代码语言:javascript
复制
import React from 'react';
export const UserContext = React.createContext(null);

Body.js

代码语言:javascript
复制
import React from 'react';

import {ThemeContext} from './theme';
import {UserContext} from './user';

export const Body = props => (
    <ThemeContext.Consumer>
        {theme => (
            <header
                className="App-header"
                style={{backgroundColor: theme.background}}
            >
                <UserContext.Consumer>
                    <h1>{user => (user ? 'Welcome back' : 'Welcome')}</h1>
                </UserContext.Consumer>
            </header>
        )}
    </ThemeContext.Consumer>
);

export default Body;

9. state

Switch.css

代码语言:javascript
复制
.active {
  background-color: #d5fffb;
  font-weight: bold;
}

支付选项:

代码语言:javascript
复制
import React from "react";
import "../Switch.css";  // 导入样式

const CREDITCARD = "Creditcard";
const BTC = "Bitcoin";

class Switch extends React.Component {
    state = {
        payMethod: BTC // 默认支付选项
    };

    select = choice => {
        return evt => {
            this.setState({
                payMethod: choice
            }); // 返回一个函数
        };
    };

    renderChoice = choice => {
        // create a set of cssClasses to apply
        const cssClasses = ["choice"];  // 样式选项

        if (this.state.payMethod === choice) {
            cssClasses.push("active"); // add .active class
        } // 支付的选项样式,增加一个 active 样式

        return (
            <div className={cssClasses.join(" ")} onClick={this.select(choice)}>
                {choice}  
            </div>
        ); // 把样式渲染给 choice 
    };

    render() {
        return (
            <div className="switch">
                {this.renderChoice(CREDITCARD)}
                {this.renderChoice(BTC)}
                Pay with: {this.state.payMethod}
            </div>
        );
    }
}

export default Switch;

在setState中使用函数,而不是对象

为什么?下面是一个点击减少的按钮

使用对象的方式赋值给 state,如果用户点击过快,计算机非常慢,而 setState 是异步的,如果碰到更高优先级的响应过载,这个减少按钮的点击响应还在队列中等待,那么用户可能点了3次,但是最后数值只减少了1

  • 状态转换依赖于当前状态时,最好使用函数来设置状态,避免这种Bug
代码语言:javascript
复制
  decrement = () => {
    // Appears correct, but there is a better way
    const nextValue = this.state.value - 1;
    this.setState({
      value: nextValue
    });
  };

更好的写法如下:

代码语言:javascript
复制
  decrement = () => {
    this.setState(prevState => {
      return {
        value: prevState.value - 1
      };
    });
  };
  • 通常在组件里存的状态越少越好,最好是从外部获取,状态多了,会使得系统的状态是什么样子的变得难以推理
  • 可以使用多个无状态组件构成 一个有状态组件

10. 无状态组件

  • React 中 只需要 render() 方法的组件

无状态组件,它不是一个类,我们不会引用 this 这种函数式组件,性能更好

代码语言:javascript
复制
const Header = function(props) {
  return (<h1>{props.headerText}</h1>)
}

有状态

代码语言:javascript
复制
export class Header extends React.Component {
  render() {
    return (
      <h1>{this.props.headerText}</h1>
    );
  }
}

11. 使用 props.children 与子组件对话

可以使用 this.props.children 引用树中的子组件

代码语言:javascript
复制
import PropTypes from 'prop-types';
import React from 'react';

class DocumentedContainer extends React.Component {
  static propTypes = {
    children: PropTypes.oneOf([PropTypes.element, PropTypes.array])
  };

  render() {
    return <div className="container">{this.props.children}</div>;
  }
}

export default DocumentedContainer;

处理子组件 :

  • map(),返回调用函数的结果的数组
  • forEach() 不收集结果
代码语言:javascript
复制
import PropTypes from 'prop-types';
import React from 'react';

class MultiChildContainer extends React.Component {
  static propTypes = {
    component: PropTypes.element.isRequired,
    children: PropTypes.element.isRequired
  };

  renderChild = (childData, index) => {
    return React.createElement(
      this.props.component,
      {}, // <~ child props
      childData // <~ child's children
    );
  };

  render() {
    return (
      <div className="container">
        {React.Children.map(this.props.children, this.renderChild)}
      </div>
    );
  }
}

export default MultiChildContainer;
  • React.Children.toArray() 函数 转成子元素的数组
代码语言:javascript
复制
import PropTypes from 'prop-types';
import React from 'react';

class ArrayContainer extends React.Component {
  static propTypes = {
    component: PropTypes.element.isRequired,
    children: PropTypes.element.isRequired
  };

  render() {
    const arr = React.Children.toArray(this.props.children);

    return <div className="container">{arr.sort((a, b) => a.id < b.id)}</div>;
  }
}

export default ArrayContainer;
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-07-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 1. 虚拟 DOM
  • 2. JSX
  • 3. ReactComponent
  • 4. props 是参数
  • 5. PropTypes
  • 6. getDefaultProps() 获取默认 props
  • 7. 上下文
  • 8. 多个上下文
  • 9. state
    • 在setState中使用函数,而不是对象
    • 10. 无状态组件
    • 11. 使用 props.children 与子组件对话
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档