MIT实习前置培训笔记5---React组件通信与插槽训练

前言:React组件主要分为两种,一种是React Dom组件(react支持的所有html和svg标签),另一种是react组件。本节主要介绍组件间的通信与插槽操作。

一、React Dom组件

1.1 Dom 组件的类属性(className)

笔记4中并没有涉及到图片的使用,image其实是有其属性的,即className。

import logo from './logo.svg';
import image from './logo.svg';
import './App.css';
import{Fragment, useState} from "react"

function App(e) {

  return (
    <div>
      <img
        src={image}
        alt=""
        className='small'
      />
    </div>
  )
}

export default App;

1.2 Dom 组件的样式(style)

这里以设置一个简单长宽背景为例。

import logo from './logo.svg';
import image from './logo.svg';
import './App.css';
import{Fragment, useState} from "react"

function App(e) {

  return (
    <div>
      <img
        src={image}
        alt=""
        className='small'
        style={{
          width:200,
          height:200,
          background:'grey'
        }}
      />
    </div>
  )
}

export default App;

改变前:

改变后:

style里面直接套用这些,如果属性比较多,会感觉比较乱,所以可以用对象代替style。

import logo from './logo.svg';
import image from './logo.svg';
import './App.css';
import{Fragment, useState} from "react"

function App(e) {

  const imageStyleobj={
    width:200,
    height:200,
    background:'grey'
  }
  
  return (
    <div>
      <img
        src={image}
        alt=""
        className='small'
        style={imageStyleobj}
      />
    </div>
  )
}

export default App;

1.3 JSX的展开语法

可以看到上面那么写还是有点繁琐,写一个还行,如果写一堆就显得有些繁琐。可以利用JSX扩展语法写成如下形式(呈现效果和上面是一样的):

import logo from './logo.svg';
import image from './logo.svg';
import './App.css';
import{Fragment, useState} from "react"

function App() {

  const imagData={
    className:'small',
    style:{
      width:200,
      height:200,
      background:'grey'
    }

  }

  return (
    <div>
      <img
        src={image}
        alt=""
        {...imagData}
      />
    </div>
  )
}

export default App;

二. React组件的props

2.1 Article组件的demo

类似于C++中写函数,App就类似C++中的主函数,在外部定义一个函数组件后,在App中直接返回就可以显示最终效果。

function Article()
{
  return (
    <div>
    <h2>标题1</h2>
    <p>内容</p>
    </div>
  )
}

export default function App()
{
  return(
    <>
    <Article/>
    <Article/>
    <Article/>
    </>
  )
}

2.2 组件的传参(通信) 

这部分很简单,基本可以理解为C++中的函数传参,用法都是一样的,只是写法不太一样。具体用法如下:

function Article(props)
{
  return (
    <div>
    <h2>{props.title}</h2>
    <p>{props.content}</p>
    </div>
  )
}

export default function App()
{
  return(
    <>
    <Article

      title="标签1"
      content="内容1"
    />
    <Article

      title="标签2"
      content="内容2"
    />
    <Article
    
      title="标签3"
      content="内容3"
    />
    </>
  )
}

ES6新的语法特性允许将props写成如下形式,也是可以的,和上面的效果是一样的:

function Article({title,content})
{
  return (
    <div>
    <h2>{title}</h2>
    <p>{content}</p>
    </div>
  )
}

2.3 active显示状态

加个active参数即可。

function Article({title,content,acitve})
{
  return (
    <div>
    <h2>{title}</h2>
    <p>{content}</p>
    <p>{acitve?'显示中':'已隐藏'}</p>
    </div>
  )
}

export default function App()
{
  return(
    <>
    <Article

      title="标签1"
      content="内容1"
      acitve
    />
    <Article

      title="标签2"
      content="内容2"
    />
    <Article
    
      title="标签3"
      content="内容3"
      acitve
    />
    </>
  )
}

三、插槽

3.1 将父组件中的JSX作为props传递给子组件(以list为例简单的demo)

比如把App.js中的全部List作为children传到function List中去。

function List({children})
{
  return (
    <ul>
      {children}
    </ul>
  )
}

export default function App()
{
  return(
    <>
      <List>
        <li>列表1</li>
        <li>列表2</li>
        <li>列表3</li>
      </List>

      <List>
        <li>列表1</li>
        <li>列表2</li>
        <li>列表3</li>
      </List>
    </>
  )
}

如果还需要添加title和footer可以这么做:

function List({children,title,footer=<div>默认底部</div>})
{
  return (
  <>
    <h2>{title}</h2>
    <ul>
      {children}
    </ul>
    {footer}
  </>
  )
}

export default function App()
{
  return(
    <>
      <List
        title="列表1"
        footer={<p>这是底部内容1</p>}
      >
        <li>列表1</li>
        <li>列表2</li>
        <li>列表3</li>
      </List>

      <List
        title="列表2"
        footer={<p>这是底部内容2</p>}
      >
        <li>列表a</li>
        <li>列表b</li>
        <li>列表c</li>
      </List>

      <List
        title="列表3"
      >
        <li>列表x</li>
        <li>列表y</li>
        <li>列表z</li>
      </List>
    </>
  )
}

3.2 将子组件的数值传递给父组件(以一个开关按钮为例)

父组件向子组件传参数都是只读的,子组件不能乱改。很多时候我们也希望父组件能从子组件中获得数据,如下为一个“开关按钮”实例:

import { useState } from "react"

function Detail()
{
  const [status,setStatus]=useState(false)
  function handleClick()
  {
    setStatus(!status)
  }

  return(
    <div>
      <button onClick={handleClick}>按钮</button>
      <p style={{display :status?'block':'none'}}>Detail中的内容</p>
    </div>
  )
}

export default function App()
{
  return(
    <>
      <Detail></Detail>
    </>
  )
}

点击前的效果:

点击后的隐藏效果:

上面的代码父组件实际上是没有感知的,要想让父组件感知子组件的内容,可以按如下操作:

在父函数中写一个函数用onActive参数与子组件互动即可:

import { useState } from "react"

function Detail({onActive})
{
  const [status,setStatus]=useState(false)
  function handleClick()
  {
    setStatus(!status)
    onActive(status)
  }

  return(
    <div>
      <button onClick={handleClick}>按钮</button>
      <p style={{display :status?'block':'none'}}>Detail中的内容</p>
    </div>
  )
}

export default function App()
{
  function handleActive(status){
    console.log(status)
  }
  return(
    <>
      <Detail
        onActive={handleActive}
      ></Detail>
    </>
  )
}

可以看到我每次点击的时候,子组件的状态值传到父组件中,并调用了console.log(status)。

3.3 使用Context进行多级组件传值

例如我们要实现一个多级目录,如果一个一个定义标题级别会比较麻烦,例如下面这个写法:

import { useState } from "react"

export function Section({children}){

  return(
  <section className="section">
    {children}
  </section>
  )
}

export function Heading({ level, children }) {
  switch (level) {
    case 1:
      return <h1>{children}</h1>;
    case 2:
      return <h2>{children}</h2>;
    case 3:
      return <h3>{children}</h3>;
    case 4:
      return <h4>{children}</h4>;
    case 5:
      return <h5>{children}</h5>;
    case 6:
      return <h6>{children}</h6>;
    default:
      throw Error('未知的 level: ' + level);
  }
}


export default function App() {
  return (
    <div>
      <Section>
        <Heading level={1}>主标题</Heading>
        <Section>
          <Heading level={2}>副标题1</Heading>
          <Heading level={2}>副标题2</Heading>
          <Heading level={2}>副标题3</Heading>
          <Section>
            <Heading level={3}>子标题1</Heading>
            <Heading level={3}>子标题2</Heading>
            <Heading level={3}>子标题3</Heading>
            <Section>
              <Heading level={4}>子子标题1</Heading>
              <Heading level={4}>子子标题2</Heading>
              <Heading level={4}>子子标题3</Heading>
            </Section>
          </Section>
        </Section>
      </Section>
    </div>
  );
}

效果:

用section去实现,每次都要手动去设置leve,这个很容易出错,且不方便。因此一种常用的做法是使用useContext组件来实现。这种方法使用 useContextContext.Provider 来自动管理和递增标题的层级,从而避免了在组件树中手动传递层级的复杂性。:

import React, { createContext, useContext, useState } from "react";

const HeadingLevelContext = createContext(1);


const HeadingLevelProvider = ({ children }) => {
  const parentLevel = useContext(HeadingLevelContext);
  const level = parentLevel < 6 ? parentLevel + 1 : 6;

  return (
    <HeadingLevelContext.Provider value={level}>
      {children}
    </HeadingLevelContext.Provider>
  );
};


const Heading = ({ children }) => {
  const level = useContext(HeadingLevelContext);
  const Tag = `h${level}`;

  return <Tag>{children}</Tag>;
};


export default function App() {
  return (
    <div>
      <HeadingLevelProvider>
        <Heading>主标题</Heading>
        <HeadingLevelProvider>
          <Heading>副标题</Heading>
          <HeadingLevelProvider>
            <Heading>子标题</Heading>
            <HeadingLevelProvider>
              <Heading>子子标题</Heading>
              <HeadingLevelProvider>
                <Heading>子子子标题</Heading>
                <HeadingLevelProvider>
                  <Heading>子子子子标题</Heading>
                </HeadingLevelProvider>
              </HeadingLevelProvider>
            </HeadingLevelProvider>
          </HeadingLevelProvider>
        </HeadingLevelProvider>
      </HeadingLevelProvider>
    </div>
  );
}

效果如下:

​​​​​​​

自此,“组件通信与插槽”的重要知识点简单训练就已经结束啦,下一节我将自学“React Hooks”的重要知识点使用,并呈现博客和具体实现的细节~~~

  • 27
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值