React文档笔记1-核心概念

目录

  1. react使用方式
  2. JSX
  3. 元素渲染
  4. 组件 & Props
  5. State & 生命周期
  6. 事件处理
  7. 条件渲染
  8. 列表 & Key
  9. 表单
  10. 状态提升
  11. 组合 vs 继承
  12. React 哲学

1. react使用方式

不使用构建工具,直接在现有页面上使用react组件

  <!-- ... 其它 HTML ... -->

  <!-- 加载 React。-->
  <!-- 注意: 部署时,将 "development.js" 替换为 "production.min.js"-->
  <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
  <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
  //加入下条代码可使用JSX,该方法会使网站速度变慢,不适用于生产环境。可以使用JSX 预处理器
  <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

  <!-- 加载我们的 React 组件。-->
  <script src="like_button.js"></script>

</body>

安装 JSX 预处理器

  • 执行 npm init -y (如果失败,这是修复办法)
  • 执行 npm install babel-cli@6 babel-preset-react-app@3

运行 JSX 预处理器

  • 创建一个名为 src 的文件夹并执行这个终端命令:
    npx babel --watch src --out-dir . --presets react-app/prod
    当你编辑带有 JSX 的源文件时,转换过程将自动重新执行。

使用构建工具

  • 学习 React 或创建一个新的单页应用,请使用 Create React App

这里是引用

```javascript
npx create-react-app my-app
cd my-app
npm start
```
  • 用 Node.js 构建服务端渲染的网站,试试 Next.js
  • 构建面向内容的静态网站,试试 Gatsby
  • 打造组件库或将 React 集成到现有代码仓库:
    • Neutrino 把 webpack 的强大功能和简单预设结合在一起。并且包括了 React 应用和 React 组件的预设。
    • Parcel 是一个快速的、零配置的网页应用打包器,并且可以搭配 React 一起工作。
    • Razzle 是一个无需配置的服务端渲染框架,但它提供了比 Next.js 更多的灵活性。

2. JSX

  • JavaScript的语法扩展
  • React.createElement()的语法糖,简化写法
  • JSX也是一个表达式,可以在 if语句和 for循环的代码块中使用 JSX,将 JSX 赋值给变量,把 JSX 当作参数传入,以及从函数中返回 JSX:
  • 使用引号"",来将属性值指定为字符串字面量;使用大括号{},来在属性值中插入一个 JavaScript 表达式;(对于同一属性不能同时使用这两种符号)
  • 使用 camelCase(小驼峰命名)来定义属性的名称
  • class 替换为 className; for 替换为 htmlFor
  • JSX 能防止注入攻击;
    React DOM 在渲染所有输入内容之前,默认会进行转义。所有的内容在渲染之前都被转换成了字符串。这样可以有效地防止 XSS(cross-site-scripting, 跨站脚本)攻击。

3. 元素渲染

  • 元素是构成 React 应用的最小砖块。
  • 与浏览器的 DOM 元素不同,React 元素是创建开销极小的普通对象。React DOM 会负责更新 DOM 来与 React 元素保持一致。
  • 想要将一个 React 元素渲染到根 DOM 节点中,只需把它们一起传入 ReactDOM.render()
    const element = <h1>Hello, world</h1>;
    ReactDOM.render(element, document.getElementById('root'));
    
  • React DOM 会将元素和它的子元素与它们之前的状态进行比较,并只会进行必要的更新来使 DOM 达到预期的状态。

4. 组件 & Props

组件,从概念上类似于 JavaScript 函数。它接受任意的入参(即 “props”),并返回用于描述页面展示内容的 React 元素。

定义组件的两种方式:

  • 函数组件
    接收唯一带有数据的 “props”(代表属性)对象与并返回一个 React元素
    function Welcome(props) {
          
          
      return <h1>Hello, {
          
          props.name}</h1>;
    }
    
  • class组件 (ES6里的class)
    class Welcome extends React.Component {
          
          
      render() {
          
          
        return <h1>Hello, {
          
          this.props.name}</h1>;
      }
    }
    

注意: 组件名称必须以大写字母开头
React 元素为用户自定义组件时,它会将 JSX所接收的属性(attributes)以及子组件(children)转换为单个对象传递给组件,这个对象被称之为 “props”。

// 这段代码会在页面上渲染 “Hello, Sara”:
function Welcome(props) {
    
    
  return <h1>Hello, {
    
    props.name}</h1>;
}

const element = <Welcome name="Sara" />;
ReactDOM.render(
  element,
  document.getElementById('root')
);
  • 组件可以在其输出中引用其他组件

Props 的只读性

  • 组件无论是使用函数声明还是通过 class 声明,都决不能修改自身的 props
  • 所有 React 组件都必须像纯函数一样保护它们的 props 不被更改。

5. State & 生命周期

Stateprops 类似,但是 state 是私有的,并且完全受控于当前组件。
使用state, 要将函数组件转换成class组件

案例:定时器

class Clock extends React.Component {
    
    
  constructor(props) {
    
    
    super(props);
    this.state = {
    
    date: new Date()};
  }
// componentDidMount() 方法会在组件已经被渲染到 DOM 中后运行
  componentDidMount() {
    
    
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }
// 组件被删除的时候, 执行该方法
  componentWillUnmount() {
    
    
    clearInterval(this.timerID);
  }

  tick() {
    
    
    this.setState({
    
    
      date: new Date()
    });
  }

  render() {
    
    
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {
    
    this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

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

使用state的注意事项:

  • 不能直接修改state的值,要使用setState()
  • 构造函数是唯一可以给 this.state 赋值的地方
  • State 的更新可能是异步的
    出于性能考虑,React可能会把多个 setState()调用合并成一个调用。
    因为this.propsthis.state 可能会异步更新,所以你不要依赖他们的值来更新下一个状态。
    解决方法:
    	// 此代码可能会无法更新计数器
    	this.setState({
          
          
    	  counter: this.state.counter + this.props.increment,
    	});
    	// 可以让 setState() 接收一个函数而不是一个对象。这个函数用上一个 state 作为第一个参数,将此次更新被应用时的 props 做为第二个参数
    	this.setState((state, props) => ({
          
          
    	  counter: state.counter + props.increment
    	}));
    
  • State的更新会被合并;可以使用setState() 来单独更新state里的独立的变量
  • 数据是向下流动的
    组件可以选择把它的 state 作为props向下传递到它的子组件中:
    但是子组件本身无法知道传递下来的值是来自于父组件的stateprops,还是手动输入的。

6. 事件处理

  • React 事件的命名采用小驼峰式(camelCase),而不是纯小写。
  • 使用 JSX语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。
    // React中要这样
    <button onClick={
          
          activateLasers}>
      Activate Lasers
    </button>
    
  • 在 React 中,不能通过返回 false的方式阻止默认行为
    // 传统html中阻止默认事件
    <a href="#" onclick="console.log('The link was clicked.'); return false">
      Click me
    </a>
    // react中阻止默认事件,要使用e.preventDefault();
    function ActionLink() {
          
          
      function handleClick(e) {
          
          
        e.preventDefault();
        console.log('The link was clicked.');
      }
    
      return (
        <a href="#" onClick={
          
          handleClick}>
          Click me
        </a>
      );
    }
    
  • 当你使用 ES6 class 语法定义一个组件的时候,通常的做法是将事件处理函数声明为 class 中的方法
  • class 的方法默认不会绑定this
    // 1. 可以在构造函数中通过bind()绑定this
      constructor(props) {
          
          
    	// ...
        this.changeTheme = this.changeTheme.bind(this)
      }
      // 2. 可以使用实验性的 public class fields 语法
      class LoggingButton extends React.Component {
          
          
    	  // 此语法确保 `handleClick` 内的 `this` 已被绑定。
    	  // 注意: 这是 *实验性* 语法。
    	  handleClick = () => {
          
          
    	    console.log('this is:', this);
    	  }
    	  render() {
          
          
    	    return (
    	      <button onClick={
          
          this.handleClick}>
    	        Click me
    	      </button>
    	    );
    	  }
      }
      // 3. 可以在回调中使用箭头函数:
      // 注意: 如果该回调函数作为 prop 传入子组件时,这些组件可能会进行额外的重新渲染
      // 建议使用前2种方法
      class LoggingButton extends React.Component {
          
          
    	  handleClick() {
          
          
    	    console.log('this is:', this);
    	  }
    	  render() {
          
          
    	    // 此语法确保 `handleClick` 内的 `this` 已被绑定。
    	    return (
    	      <button onClick={
          
          () => this.handleClick()}>
    	        Click me
    	      </button>
    	    );
    	  }
      }
    
  • 向事件处理程序传递参数
    // 通过箭头函数实现
    // 如果通过箭头函数的方式,事件对象e必须显式的进行传递
    <button onClick={
          
          (e) => this.deleteRow(id, e)}>Delete Row</button>
    // 通过Function.prototype.bind 实现
    // 通过 bind 的方式,事件对象e以及更多的参数将会被隐式的进行传递
    <button onClick={
          
          this.deleteRow.bind(this, id)}>Delete Row</button>
    

7. 条件渲染

  • 运算符if
    声明一个变量并使用 if 语句进行条件渲染
  • 与运算符 &&
    true && expression 总是会返回 expression, 而 false && expression 总是会返回 false
    如果条件是 true,&& 右侧的元素就会被渲染,如果是 false,React 会忽略并跳过它。
  • 三目运算符 ? :

阻止组件渲染:
render 方法直接返回 null,就能不进行任何渲染。
在组件的 render 方法中返回 null 并不会影响组件的生命周期

8. 列表 & Key

  • 基础列表组件
    function NumberList(props) {
          
          
      const numbers = props.numbers;
      const listItems = numbers.map((number) =>
        <li key={
          
          number.toString()}>{
          
          number}</li>
      );
      return (
        <ul>{
          
          listItems}</ul>
      );
    }
    
    const numbers = [1, 2, 3, 4, 5];
    ReactDOM.render(
      <NumberList numbers={
          
          numbers} />,
      document.getElementById('root')
    );
    

key

  • key 帮助 React 识别哪些元素改变了,比如被添加或删除
  • 一个元素的 key 最好是这个元素在列表中拥有的一个独一无二的字符串(如id)
  • 当元素没有确定id 的时候,万不得已你可以使用元素索引 index 作为 key
    如果列表项目的顺序变化,会导致性能变差,还可能引起组件状态的问题
  • 如果你选择不指定显式的 key值,那么 React将默认使用索引用作为列表项目的 key
  • 元素的 key 只有放在就近的数组上下文中才有意义
    使用一个组件,把key放在组件上,而不是组件里面的元素上
    一个好的经验法则是:在map()方法中的元素需要设置 key 属性
  • key只是在兄弟节点之间必须唯一
  • key 会传递信息给 React,但不会传递给你的组件

9. 表单

受控组件

  • 在 HTML 中,表单元素(如<input>, <textarea> , <select>)之类的表单元素通常自己维护 state,并根据用户输入进行更新。
  • 而在 React中,可变状态(mutable state)通常保存在组件的 state 属性中,并且只能通过使用 setState()来更新。

我们可以把两者结合起来,使 Reactstate 成为“唯一数据源”。
渲染表单的 React组件还控制着用户输入过程中表单发生的操作。
React以这种方式控制取值的表单输入元素就叫做“受控组件”。

<input type="text">, <textarea><select>之类的标签都非常相似,它们都接受一个 value 属性,你可以使用它来实现受控组件。

 <input type="text" value={
    
    this.state.value} onChange={
    
    this.handleChange} />
 <textarea value={
    
    this.state.value} onChange={
    
    this.handleChange} />
 <select value={
    
    this.state.value} onChange={
    
    this.handleChange}>
    <option value="grapefruit">葡萄柚</option>
    <option value="lime">酸橙</option>
    <option value="coconut">椰子</option>
    <option value="mango">芒果</option>
 </select>
 // 将数组传递到 value 属性中,以支持在 select 标签中选择多个选项
 <select multiple={
    
    true} value={
    
    ['B', 'C']}>

<input type="file"> 允许用户从存储设备中选择一个或多个文件,将其上传到服务器,或通过使用 JavaScriptFile API进行控制。
因为它的 value只读,所以它是 React中的一个非受控组件

当需要处理多个 input 元素时,我们可以给每个元素添加 name 属性,并让处理函数根据 event.target.name 的值选择要执行的操作。

使用 ES6 计算属性名称的语法更新给定输入名称对应的 state

// 使用了 ES6 计算属性名称的语法
this.setState({
    
    
  [name]: value
});
// 等同 ES5:
var partialState = {
    
    };
partialState[name] = value;
this.setState(partialState);

Formik :
https://formik.org/
包含验证、追踪访问字段以及处理表单提交的完整解决方案

10. 状态提升

通常,多个组件需要反映相同的变化数据,这时我们建议将共享状态提升到最近的共同父组件中去。

11. 组合 vs 继承

  • 包含关系
    <FancyBorder> JSX 标签中的所有内容都会作为一个 children prop 传递给 FancyBorder 组件。因为 FancyBorder{props.children} 渲染在一个 <div>中,被传递的这些子组件最终都会出现在输出结果中。
function FancyBorder(props) {
    
    
  return (
    <div className={
    
    'FancyBorder FancyBorder-' + props.color}>
      {
    
    props.children}
    </div>
  );
}

function WelcomeDialog() {
    
    
  return (
    <FancyBorder color="blue">
      <h1 className="Dialog-title">
        Welcome
      </h1>
      <p className="Dialog-message">
        Thank you for visiting our spacecraft!
      </p>
    </FancyBorder>
  );
}

也可以自行约定输入内容

function SplitPane(props) {
    
    
  return (
    <div className="SplitPane">
      <div className="SplitPane-left">
        {
    
    props.left}
      </div>
      <div className="SplitPane-right">
        {
    
    props.right}
      </div>
    </div>
  );
}

function App() {
    
    
  return (
    <SplitPane
      left={
    
    
        <Contacts />
      }
      right={
    
    
        <Chat />
      } />
  );
}

注意:组件可以接受任意 props,包括基本数据类型,React元素以及函数。
如果你想要在组件间复用非 UI 的功能,我们建议将其提取为一个单独的 JavaScript模块,如函数、对象或者类。组件可以直接引入(import)而无需通过extend继承它们。

12. React 哲学

未完待续。。。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_40693643/article/details/114640471