好了,俺要开始学习React了(基础二)

上集精彩

回顾上集:

上集说到了state 数据自动重新渲染和遍历数据时不建议使用元素自身的 index 建议使用数据中自带的 id 作为元素的 key 值。

本集继续

兄弟们,俺又回来了😁

React组件化

在 React 中网页被拆分为了一个一个组件,组件是独立可复用的代码片段。具体来说,组件可能是页面中的一个按钮,一个对话框,一个弹出层等。React中定义组件的方式有两种:基于函数的组件和基于类的组件。

基于函数的组件(个人推荐)

  • 基于函数的组件其实就是一个会返回JSX(React元素)的普通的JS函数,你可以这样定义:
js 复制代码
// App.js
// function App() {
//   return <h1>我是一个React的组件!</h1>;
// }

// 箭头函数
const App = () => {
  return <h1>我是一个React的组件!</h1>;
};
// 导出App组件
export default App;

个人推荐用箭头函数去定义组件比较好 。至于为啥呢,

俺也给忘了,想知道的可以网上查查看。没事滴,不知道这个也不会影响后面的学习的。

  • 渲染组件:引入后通过<组件名/><组件名></组件名>即可引入组件:
js 复制代码
// index.js
root.render(<App />);
  • 同样在一个组件中可以直接使用其他组件:
js 复制代码
// Button.js
import "./index.css";

const Button = () => {
  return <button>我是一个按钮</button>;
};

export default Button;
  • App.js中可以直接引入该组件:
js 复制代码
import Button from "./components/Button";
const App = () => {
  return (
    <div>
      <h1>我是一个React的组件!</h1>
      <Button />
    </div>
  );
};
// 导出App组件
export default App;

基于类的组件

  • 除了函数组件外,在React中还有一种类组件,但类组件使用起来并不方便,所以在React中类组件的使用场景越来越少:新建 H2.js 组件:
js 复制代码
// 类组件
import React from "react";
// 类组件必须要继承React.Component
class H2 extends React.Component {
  // 类组件必须添加一个render,且返回值要是一个js
  render() {
    return <h2>我是一个类组件</h2>;
  }
}

export default H2;

引入和使用跟函数组件是一样的。

小小提示: React 的组件都会统一放在 src/components 目录下,然后你需要啥组件就在该目录下创建个跟该组件相关的名字目录(首字母建议大写,好区分)。然后里面写你需要的样式文件和脚本文件就行了。样式不建议都写在同一个文件里,分开写,啥组件就对应引入啥样式:建议目录形式

React事件

在React中事件需要通过元素的属性来设置,和原生JS不同,在React中事件的属性需要使用驼峰命名法:onclick -> onClick。属性值不能直接执行代码,而是需要一个回调函数:onClick={()=>{alert(123)}}

js 复制代码
return <button onClick={() => alert(123)}>我是一个按钮</button>
  • 触发一个函数:
js 复制代码
const Button = () => {
  const handleClick = () => {
    alert("Clicked!");
  };
  return (
    <div>
      <button onClick={handleClick}>Click me</button>
    </div>
  );
};

export default Button;
  • 在React中,无法通过return false取消默认行为,用事件对象:React事件中同样会传递事件对象,可以在响应函数中定义参数来接收事件对象,React中的事件对象同样不是原生的事件对象,是经过React包装后的事件对象,由于对象进行过包装,所以使用过程中我们无需再去考虑兼容性问题。
js 复制代码
const Button = () => {
  const handleClick = (event) => {
    event.preventDefault(); // 阻止默认行为
    alert("Clicked!");
  };
  return (
    <div>
      <a href="www.baidu.com" onClick={handleClick}>
        超链接
      </a>
    </div>
  );
};

export default Button;

a 标签点击后会默认跳转到百度网页,但当使用 event.preventDefault() 后会取消 a 标签默认跳转的行为。

  • 取消事件的冒泡:就是事件的向上触发:
js 复制代码
const Button = () => {
  const handleClick = (event) => {
    event.stopPropagation(); // 取消事件的冒泡
    alert("我是按钮");
  };
  return (
    <div
      style={{ backgroundColor: "lightblue", width: "200px", height: "200px" }}
      onClick={() => {
        alert("我是div");
      }}
    >
      <button onClick={handleClick}>Click me</button>
    </div>
  );
};

export default Button;

当你不添加 event.stopPropagation();,你会看到不一样的效果:当你点击div的区域是不会有啥问题,但当你点击button时,两个弹窗会先后出来

当然不止这一个事件还有其他事件,可以去官网看看。

React组件通信

之前我们所定义的组件内容几乎都是固定的,组件创建的时候什么样,使用时就是什么样。但在开发时,我们往往需要的是一些动态显示的组件,换句话组件中所显示的内容必须是动态设置的。在使用组件时,可以通过向组件传递参数的形式来向组件传递数据,这一点和JS中的函数非常相似。函数可以通过传递实参来决定函数的执行结果,组件也不例外。函数的参数如何传递我们是非常清楚的,那么组件的参数是怎么传递的呢?组件的参数需要通过属性传递。

父传子组件 props

  • 在函数组件中,属性就相当于是函数的参数,可以通过参数来访问
  • 可以在函数组件的形参中定义一个props,props指向的是一个对象
  • 它包含了父组件中传递的所有参数
  • 如果将组件中的数据全部写死,将会导致组件无法动态设置,不具有使用价值,我们希望组件数据可以由外部设置,在组件间,父组件可以通过props(属性)向子组件传递数据
  • props是只读属性,不可修改
js 复制代码
// components/Son/index.js
const Son = (props) => {
  console.log(props);
  return <div>Son {props.name}</div>;
};

export default Son;

// App.js
import Son from "./components/Son";

const App = () => {
  return (
    <div className="App">
      hello world!
      <Son name={"hello Son?"} />
    </div>
  );
};

export default App;
  • 不仅可以传属性,还可以传方法:
js 复制代码
<Son
        name={"hello Son?"}
        age={18}
        cb={() => console.log("123")}
        list={["Vue", "React", "Angular"]}
        obj={{ name: "why", age: 18 }} // 对象会被完全拷贝
        isTrue={false}
        child={<sapn>hi son?</sapn>}
      />
  • props.children:当把内容嵌套在子组件标签内时,可通过 props.children 获取嵌套的节点内容:
js 复制代码
// App.js
function Child(props) {
  return <div>Child {props.children}</div>;
}

function App() {
  return (
    <div className="App">
      Hello World!
      <Child>
        <span>hi Child?</span>
      </Child>
    </div>
  );
}

export default App;

子传父组件

由于视图发生改变,需要使用状态数据useState()

js 复制代码
// App.js
import { useState } from "react";

function Son({ getSonMsg }) {
  const sonMsg = "hello Son?";
  return (
    <div>
      Son
      <button onClick={() => getSonMsg(sonMsg)}>带你我</button>
    </div>
  );
}

function App() {
  const [msg, setMsg] = useState("");
  const getMsg = (message) => {
    console.log(message);
    setMsg(message);
  };
  return (
    <div className="App">
      Hello World! {msg}
      <Son getSonMsg={getMsg} />
    </div>
  );
}

export default App;

兄弟组件通信

状态提升 机制,通过父组件进行兄弟之间的数据传递:

js 复制代码
import { useState } from "react";

function A({ getAName }) {
  const aName = "炸,六个A";
  return (
    <div>
      this is A<button onClick={() => getAName(aName)}>send</button>
    </div>
  );
}

function B(props) {
  return <div>this is B;{props.name}</div>;
}

function App() {
  const [name, setName] = useState("");
  const getName = (names) => {
    console.log(names);
    setName(names);
  };
  return (
    <div className="App">
      Hello World!
      <A getAName={getName} />
      <B name={name} />
    </div>
  );
}

export default App;

大致步骤:

  1. 准备A和B两个兄弟组件,并在App父组件中引入;
  2. 子A传父App,使用 useState() 维护;
  3. 父App传子B,在B中通过props接收;

跨层级组件通信 Context

js 复制代码
import { createContext, useContext } from "react";

const MsgContext = createContext(); // 创建一个 Context 对象

function A() {
  return (
    <div>
      this is A
      <B />
    </div>
  );
}

function B() {
  const msg = useContext(MsgContext); // 使用 Context 对象
  return <div>this is B - {msg}</div>;
}

function App() {
  const msg = "this is App msg";
  return (
    <div className="App">
      <MsgContext.Provider value={msg}>
        Hello World!
        <A />
      </MsgContext.Provider>
    </div>
  );
}

export default App;

大致步骤:

  1. createContext 方法创建一个上下文对象
js 复制代码
const MsgContext = createContext(); // 创建一个 Context 对象
  1. 在顶层组件(App),通过 Provider 组件提供数据
js 复制代码
<MsgContext.Provider value={msg}>
        Hello World!
        <A />
      </MsgContext.Provider>
  1. 在底层组件(B),通过 useContext 钩子函数使用数据
js 复制代码
const msg = useContext(MsgContext); // 使用 Context 对象
  return <div>this is B - {msg}</div>;

注意哈: 虽然俺上面的代码示例组件相关用的是function函数(其实那是俺懒,让 CodeGeeX 自动生成的😁),但俺还是建议你用箭头函数定义组件😃

React获取真实的DOM useRef()

React中所有的操作默认都是在React元素上进行,然后再通过虚拟DOM应用到真实页面上的。在React中依然为我们提供了可以直接访问原生DOM对象的方式。ref就是干这个事的。

注意哈: 尽量是读取而不要修改,如果必需要修改也要尽量减少修改的次数,总之能不用就不用

获取原生的DOM对象:

  1. 可以使用传统的document来对DOM进行操作

  2. 直接从React处获取DOM对象

    1. 创建一个存储DOM对象的容器
    2. 使用 useRef() 钩子函数
    3. 将容器设置为想要获取DOM对象元素的ref属性,<h1 ref={xxx}>....</h1>
    4. React会自动将当前元素的DOM对象,设置为容器current属性
  • 钩子函数的注意事项:
    1. React中的钩子函数只能用于函数组件或自定义钩子
    2. 钩子函数只能直接在函数组件中调用

useRef():

  • 返回的就是一个普通的JS对象
  • {current:undefined}
  • 所以我们直接创建一个js对象,也可以代替useRef()
    • 区别:
      • 我们创建的对象,组件每次重新渲染都会创建一个新对象
      • useRef()创建的对象,可以确保每次渲染获取到的都是同一个对象
      • 当你需要一个对象不会因为组件的重新渲染而改变时,就可以使用useRef()
js 复制代码
import { useRef, useState } from "react";
const App = () => {
  // 获取原生DOM对象
  const h1Ref = useRef(); // 创建一个容器
  const [count, setCount] = useState(1);
  const clickHandler = () => {
    console.log(h1Ref);
    // alert(h1Ref.current === header);
    h1Ref.current.innerText = "嘻嘻!";
  };

  const countAddHandler = () => {
    setCount((prevState) => prevState + 1);
  };

  return (
    <div className="app">
      <h1 ref={h1Ref}>我是标题{count}</h1>
      <button onClick={clickHandler}>1</button>
      <button onClick={countAddHandler}>2</button>
    </div>
  );
};

export default App;

下集精彩

天黑了,需要睡觉觉了,理解一下好不啦😁。

下篇俺会讲到哪些知识点呢: 俺在第一集的时候只说了React的JSX语法的注意事项,并没有说关于如何用JSX语法。(其实挺简单的,只要掌握React JSX的一些基础语法就可以了,在平时开发中是够用的,真看到不会的也别担心,会上网就行了😁)只要懂得这篇的知识点就很棒了

  • 啥是 useEffect ;
  • 啥又是 ReactHooks ;
  • 然后用一个简单的案例并结合之前的知识点收尾 ;
相关推荐
m0_748256784 分钟前
SpringBoot 依赖之Spring Web
前端·spring boot·spring
web1350858863533 分钟前
前端node.js
前端·node.js·vim
m0_5127446434 分钟前
极客大挑战2024-web-wp(详细)
android·前端
若川43 分钟前
Taro 源码揭秘:10. Taro 到底是怎样转换成小程序文件的?
前端·javascript·react.js
潜意识起点1 小时前
精通 CSS 阴影效果:从基础到高级应用
前端·css
奋斗吧程序媛1 小时前
删除VSCode上 origin/分支名,但GitLab上实际上不存在的分支
前端·vscode
IT女孩儿1 小时前
JavaScript--WebAPI查缺补漏(二)
开发语言·前端·javascript·html·ecmascript
m0_748256563 小时前
如何解决前端发送数据到后端为空的问题
前端
请叫我飞哥@3 小时前
HTML5适配手机
前端·html·html5
@解忧杂货铺5 小时前
前端vue如何实现数字框中通过鼠标滚轮上下滚动增减数字
前端·javascript·vue.js