React基础概念内容

文章目录

React基础

React项目

  1. 创建项目
npx create-react-app my-app
  1. 运行项目
npm start

元素和组件

React应用程序可以分为两部分:元素 + 组件

function formatName(user) {
  return user.firstName + " " + user.lastName;
}

const user = {
  firstName: "Harper",
  lastName: "Perez",
};

export default function Jsx() {
  return <h1>Hello, {formatName(user)}!</h1>;
}

以最简单的React的例子展开来介绍React。

在上面的代码中有两个function,第一个formatName函数,是一个方法,拼接两个字符串,返回user的全名;第二个Jsx函数,是一个React组件,返回的是一个Html元素,而Html元素中的又使用{}包裹了一个变量,这个变量是formatName函数的返回值,这种将Html元素和JavaScript语法结合起来使用的方式,称为JSX语法,它也是React使用的主要语法。

JSX语法

const elementOne = <img src={user.avatarUrl} alt="" />;

const elementTwo = (
  <div>
    <h1>Hello!</h1>
    <h2>Good to see you here.</h2>
  </div>
);

JSX语法的优点:

  1. JSX防止注入攻击,你可以安全地在JSX中插入用户输入内容。

    ReactDOM在渲染所有输入内容之前,默认会进行转译,所有内容在渲染之前都被转换成了字符串,可以有效的防止XSS攻击。
  2. Babel会将JSX转译为一个名为React.createElement()的函数,这个函数会预先执行一些检查,确保你编写的代码无错。

React元素的渲染

元素是构成React应用的最小砖块。

ReactDOM负责将React元素渲染为DOM。

React元素一旦被创建,就无法更改它的子元素或属性。

React只更新它需要的部分,ReactDOM会将元素及其子元素与它们之前的状态进行比较,然后更新被改变了的部分。

React组件

组件允许你将 UI 拆分为独立可复用的代码片段,并对每个片段进行独立构思。

组件类似与JS中的函数,它可以接受任意的参数(即props),并返回React元素。组件由元素 + 逻辑构成。

在React中组件分为两种:函数式组件和class组件。

函数式组件

function Welcome(props){
    return <h1>Hello, {props.name}</h1>;
}

class组件

class Welcome extends React.Component {
    render() {
        return <h1>Hello, {this.props.name}</h1>; 
    }
}

React组件的渲染

const element = <Welcome name="Sara" />;

当React元素为自定义组件时,它会将JSX所接收的属性以及子组件转换为props传递给组件。

function WarningBanner(props) {
  if (!props.warn) {
    return null;
  }

  return <div className="warning">Warning!</div>;
}

当React组件的返回值为null,默认不渲染组件。

组件的组合与提取

通过在父组件中引入import子组件的方式来实现组件的组合。

当组件的嵌套层级过多时,为了便于组件的维护,可以将其中可复用的组件提取出来,在引入使用。

Props

props:用于获取父组件中的数据。

在函数式组件中的使用:props.data

function UserInfo(props) {
  return (
    <div className="UserInfo">
      <Avatar user={ props.author }/>
      <div className="UserInfo-name">
        {props.author.name}
      </div>
    </div>
  );
}

在函数式组件中使用props,需要先向函数传入props参数,而在class组件中,则通过this.访问,即class组件上默认带有props属性,无需再通过参数传递。

在class组件中的使用:this.props.data

export default function Page1() {
  const { messages1 } = this.props;
  return <Mailbox unreadMessages={messages1} />;
}

通过props获取的数据具有只读性,因此子组件无法直接修改props的数据。

如果一定需要在子组件中修改获取的props数据,该怎么做呢?

可以在父组件中获取子组件中需要修改的props,然后在父组件中进行修改(需要使用到【事件处理】,在后面提到)

State

state:用于监控数据的变化。

constructor(props){    
  super(props);    
  this.state = {state1: false, }; 
}

state的内容是组件私有的,在组件内通过this.state.data来访问里面的数据。

当state中的数据需要被多个组件同时使用时,则应该将state放在最近的父组件中,并通过props向下传递获取数据。

生命周期

挂载

  1. constructor(props):初始化state 和props数据;
  2. getDerivedStateFromProps(nextProps, prevState):组件初始化和更新时调用;
  3. render():渲染组件;
  4. componentDidMount():在组件被挂载到页面后执行,只在挂载时执行一次。

更新

  1. getDerivedStateFromProps(nextProps, prevState):组件初始化和被更新时调用;
  2. shouldComponentUpdate(nextProps, nextState):在组件被更新之前执行 (return true 更新 , return false 不更新);
  3. render(): 渲染页面;
  4. getSnapshotBeforeUpdate(prevProps, prevState);
  5. componentDidUpdate():state或props更新后调用。

卸载

  1. componentWillUnmount():在组件即将被页面剔除时执行。

事件处理

通过元素的onClick、onsubmit等属性来为元素绑定事件,事件处理程序的参数event(事件对象),在事件发生时自动获取。

函数式组件中的事件处理

在函数式组件中,事件处理程序是一个function函数:

function Form() {
  function handleSubmit(e) {
    e.preventDefault();
  }

  return (
    <form onSubmit={handleSubmit}>
      <button type="submit">Submit</button>
    </form>
  );
}

事件处理程序:handleSubmit函数,其中传入的参数e,是事件对象。

class组件中的事件处理

在class组件中,事件处理程序是一个方法:

class Page2 extends React.Component {
  constructor(props) {
    super(props);
    this.state = { showWarning: true };
    this.handleToggleClick = this.handleToggleClick.bind(this);
  }

  handleToggleClick() {
    this.setState((state) => ({
      showWarning: !state.showWarning,
    }));
  }

  render() {
    return (
      <div>
        <WarningBanner warn={this.state.showWarning} />
        <button onClick={this.handleToggleClick}>
          {this.state.showWarning ? "Hide" : "Show"}
        </button>
      </div>
    );
  }
}

事件处理函数:handleToggleClick方法
,当需要在函数中使用this.xxx时,则需要在constructor()中为事件绑定this。

事件绑定:this.handleClick = this.handleClick.bind(this);

条件语法

  1. if 条件语句
if (isLoggedIn) {
    return <UserGreeting />;
}
return <GuestGreeting />;
  1. 与运算符 &&
{ count && <h1>Messages: {count}</h1>}
  1. 三目运算符
condition ? true : false
  1. 阻止组件渲染

    当组件返回null时,则组件不会被渲染。

循环 & key

使用循环来渲染元素组件时,需要给每个元素设置key值,且需要保证兄弟元素的key值各不相同。

设置key的作用:帮助React识别哪些元素被改变(添加/删除)了。

const listItems = numbers.map((number) =>
    <li>{number}</li>
  );
  return (
    <ul>{listItems}</ul>
  );

key值应该被设置在循环渲染的元素上。

return (
    <ul>
      {numbers.map((number) =>
        <ListItem key={number.toString()}
                  value={number} />
      )}
    </ul>
  );

表单

受控组件:组件内数据的改变不能在通过受控组件来修改,需要在外层组件中修改state,通过使用this.setState方法来修改

this.setState({value: event.target.value});

在React中,input、select、textarea元素的值都可以通过value属性来获取和设置,当input是checkbox类型时,通过checked属性来获取true/false。

handleFruitChange(event) {
    this.setState({
      fruit: event.target.value,
    });
  }
  
  
 <label>
  名字:
  <input
    name="name"
    type="text"
    value={this.state.name}
    onChange={this.handleChange}
  ></input>
</label>

当表单中有多个输入元素,可以通过给元素设置不同的name,通过name来修改不同输入元素的value。

handleChange(event) {
    const target = event.target;
    const name = target.name;
    const value = target.value;

    this.setState({
      [name]: value,
    });
  }

状态提升

当多个组件需要使用相同的可变数据时,可以将这些数据放到他们的最近共同父组件中,通过props来获取父组件中的数据。

组合

在React中,对于组件间的代码重用,不使用继承,使用组合模式

包含关系

无法提前知晓子组件的具体内容,但是需要渲染子组件时,使用一个特殊的props.children来将自组件传递到渲染结果中

<div className={'FancyBorder FancyBorder-' + props.color}>
  {props.children}
</div>

<FancyBorder color="blue">
  <h1 className="Dialog-title">
    Welcome
  </h1>
  <p className="Dialog-message">
    Thank you for visiting our spacecraft!
  </p>
</FancyBorder>

特例关系

<div className={'FancyBorder FancyBorder-' + props.color}>      
    <h1 className="Dialog-title">{props.title}</h1>      
    <p className="Dialog-message">{props.message}</p>    
</div>

<FancyBorder title="Wecome" message="Thank you for visiting our spacecraft!" />

组件可以接受任意props,包括基本数据类型、react元素以及函数。

React应用

如何根据页面设计稿来编写react组件

思路:

  1. 将 UI 分离为组件(父组件、子组件),并给每个组件命名

     例如:
     1.FilterableProductTable
        2.SearchBar
        3.ProductTable
           4.ProductCategoryRow
           5.ProductRow
    
  2. 先渲染UI完成一个静态版本的页面,再实现交互功能(静态版本中不应该使用到state,可以使用props来实现父组件向子组件传递数据)

    自上(父组件)而下(子组件)构建应用

  3. 确定 state 的最小(且完整)表示

    1. 包含所有产品的原始列表----不可变
    2. 用户搜索的关键词-----------1.state
    3. 复选框是否选中的值---------1.state
    4. 经过搜索筛选的产品列表-----通过计算得出
  4. 添加反向数据流

    低层组件是受控组件,在高层组件中修改数据,操作在低层组件上,但是state在高层组件中,通过在高层组件获取低层的event.target来修改(传递event的方法)。

// 最外层的父组件
export default class FilterableProductTable extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      filterText: "",
      inSrockOnly: false,
    };

    this.handleFilterTextChange = this.handleFilterTextChange.bind(this);
    this.handleInSrockOnlyChange = this.handleInSrockOnlyChange.bind(this);
  }

  // 在父组件中修改数据,但是数据是在子组件中获取的,即反向数据流
  handleFilterTextChange(event) {
    this.setState({
      filterText: event.target.value,
    });
  }

  handleInSrockOnlyChange(event) {
    this.setState({
      inSrockOnly: event.target.checked,
    });
  }

  render() {
    const PRODUCT = [
      {
        category: "Sporting Goods",
        price: "$49.99",
        stocked: true,
        name: "Football",
      },
      {
        category: "Sporting Goods",
        price: "$9.99",
        stocked: true,
        name: "Baseball",
      },
      {
        category: "Sporting Goods",
        price: "$29.99",
        stocked: false,
        name: "Basketball",
      },
      {
        category: "Electronics",
        price: "$99.99",
        stocked: true,
        name: "iPod Touch",
      },
      {
        category: "Electronics",
        price: "$399.99",
        stocked: false,
        name: "iPhone 5",
      },
      {
        category: "Electronics",
        price: "$199.99",
        stocked: true,
        name: "Nexus 7",
      },
    ];
    
    return (
      <div>
        <SearchBar
          filterText={this.state.filterText}
          inSrockOnly={this.state.inSrockOnly}
          onFilterTextChange={this.handleFilterTextChange}
          onInSrockOnlyChange={this.handleInSrockOnlyChange}
        />
        <ProductTable
          filterText={this.state.filterText}
          inSrockOnly={this.state.inSrockOnly}
          products={PRODUCT}
        />
      </div>
    );
  }
}

class SearchBar extends React.Component {
  constructor(props) {
    super(props);

    this.handleFilterTextChange = this.handleFilterTextChange.bind(this);
    this.handleInSrockOnlyChange = this.handleInSrockOnlyChange.bind(this);
  }

  handleFilterTextChange(event) {
    this.props.onFilterTextChange(event);
  }

  handleInSrockOnlyChange(event) {
    this.props.onInSrockOnlyChange(event);
  }

  render() {
    return (
      <form>
        <input
          value={this.props.filterText}
          type="search"
          placeholder="Search..."
          onChange={this.handleFilterTextChange}
        />
        <br />
        <label>
          <input
            checked={this.props.inSrockOnly}
            type="checkbox"
            placeholder="Search..."
            onChange={this.handleInSrockOnlyChange}
          />{" "}
          Only show products in stock
        </label>
      </form>
    );
  }
}

function ProductTable(props) {
  const rows = [];
  let lastCategory = "";
  props.products.forEach((product) => {
    if (product.name.indexOf(props.filterText) === -1) {
      return;
    }
    if (props.inSrockOnly && product.stocked === false) {
      return;
    }

    if (product.category !== lastCategory) {
      rows.push(
        <ProductCategoryRow
          category={product.category}
          key={product.category}
        />
      );
      lastCategory = product.category;
    }

    rows.push(<ProductRow product={product} key={product.name} />);
  });
  return (
    <table>
      <thead>
        <tr>
          <th>Name</th>
          <th>Price</th>
        </tr>
      </thead>
      <tbody>{rows}</tbody>
    </table>
  );
}

function ProductCategoryRow(props) {
  return (
    <tr>
      <td colSpan="2" style={{ fontWeight: "600" }}>
        {props.category}
      </td>
    </tr>
  );
}

function ProductRow(props) {
  const name = props.product.stocked ? (
    props.product.name
  ) : (
    <span style={{ color: "red" }}>{props.product.name}</span>
  );
  return (
    <tr>
      <td>{name}</td>
      <td>{props.product.price}</td>
    </tr>
  );
}
上一篇:♠ redux、react-redux的使用


下一篇:React+antd组件库使用方法