React建议在开发中将不同组件进行多个文件的分割,但为方便学习,这里将结构都在同一个文件(App.js)中展示。
组件通信
父子组件传值(props)都是只读的 React中的组件分为两种,
- ReactDOM组件 DOM是指React支持的所有的html和svg标签
DOM组件中的Props设置
JSX支持传统属性设置,但也存在一部分属性使用方式的变更
类名className(与js语法的class做区分)
样式style
设置一
function App() {
return (
<>
<img src={image} alt='' style={{
width: 200,//两种写法等价
height: '200px',
objectFit: 'cover'
}} />
</>
);
}
设置二
function App() {
const imageStyle = {
width: 200,
height: '200px'
}
return (
<>
<img src={image} alt='' style={imageStyle} />
</>
);
}
JSX的展开语法
当我们需要给标签设置一个属性对象集合时,使用展开语法{ ...myData }直接展开
function App() {
const myData = {
src: image,
style: {
width: 200,
height: '200px'
},
}
return (
<>
<img alt='' {...myData} />
</>
);
}
React组件
对如下父子组件
function Article() {
return (
<div>
<h1>Hello World</h1>
<p>Hello content</p>
</div>
);
}
export default function App() {
return (
<>
<Article />
<Article />
<Article />
</>
);
}
React组件父组件传值给子组件
当我们需要对其样式逻辑进行复用时,有以下步骤
- 请求服务端提供功能所需数据
- 创建子组件
- 将数据传递给子组件进行渲染
function Article(props) {//也可以直接解构出props的属性
// function Article({titele,content,active}) {
return (
<div>
<h1>{props.title}</h1>
<p>{props.content}</p>
{props.active?<p>显示中</p>:<p>已隐藏</p>}
</div>
);
}
export default function App() {
return (
<>
<Article title='标签1' content='内容1' active/>
<Article title='标签2' content='内容2'/>
<Article title='标签3' content='内容3'/>
</>
);
}
React组件嵌套传值及列表渲染
import React, { Fragment } from 'react';
function Detail({ content, active }) {
return (
<>
<p>{content}</p>
{active ? <p>显示中</p> : <p>已隐藏</p>}
</>
);
}
function Article({ title, detailData }) {
return (
<>
<h1>{title}</h1>
<Detail {...detailData} />
</>
);
}
export default function App() {
const articleList = [
{
id: 1,
title: '标签1',
detailData: {
content: '内容1',
active: true
}
},
//...省略了
];
const articleData = articleList.map(item => (
//JSX中只能有一个根元素,所以需要用一个空标签包裹
//如果循环中每次都存在多个根元素,那么就需要使用Fragment
<Fragment key={item.id}>
<Article {...item} />
</Fragment>
))
return (
<>
{articleData}
</>
);
}
将JSX作为Props传递(组件插槽)
React中预定义了属性children(组件开始与结束标记之间的所有内容)
向多个位置传递JSX
function List({ children, title, footer = <div>默认底部</div> }) {
return (
<>
<h2>{title}</h2>
<ul>{children}</ul>
{footer}
</>
);
}
export default function App() {
return (
<>
<List title="列表1">
<li>列表项1</li>
<li>列表项2</li>
<li>列表项3</li>
</List>
<List title="列表2" footer={<p>自定义底部</p>}>
<li>列表项1</li>
<li>列表项2</li>
<li>列表项3</li>
</List>
</>
);
}
最佳方案: 将列表在app中处理成一个数组包含对象的形式,更利于代码的处理
React组件子组件传值给父组件
通过父组件给子组件设置自定义事件,自定义事件触发后,向父组件传递参数
import React, { useState } from 'react';
function Detail({ onActive }) {
const [status, setStatus] = useState(true);//通过useState创建的状态来控制
function handleClick() { //点击事件被触发
setStatus(!status);
onActive(status);//调用父组件的方法,将参数传过去
}
return (
<div>
<button onClick={handleClick}>按钮</button>
<h1 style={{
display: status ? "block" : "none"
}}>Detail</h1>
</div>
);
}
export default function App() {
function handler(status) {//子组件中被触发的函数调用该函数将数据传回
console.log(status,"我是传给父组件的参数");
}
return (
<>
<Detail
onActive={handler} //绑定自定义事件
/>
</>
);
}
React组件中同级组件传值context
常用方式是用父组件进行中转(子传父=>父传子 = 兄弟传值)
React组件中多级组件传值hooks: context
在根组件中声明一个Context,在子组件中使用useContext获取当前的level值,然后根据level值渲染对应的标题。 levelContext.Provider 接受的属性 value 可以是从上一级组件传递下来的值,也可以是createContext设置的默认值。value + 1 后传递给子组件return 出去
import { createContext, useContext } from "react";
function Section({ children }) {
const level = useContext(levelContext);// 获取当前的level值
// 渲染子组件,传递下一级的level值
return (
<section className="section">
<levelContext.Provider value={level + 1}>
{children}
</levelContext.Provider>
</section>
);
}
function Heading({ children }) {
const level = useContext(levelContext);// 获取当前的level值
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:
return console.error("Invalid level value");
}
}
//在根组件中声明一个Context,默认值为1,在子组件中使用useContext获取当前的level值,然后根据level值渲染对应的标题。
const levelContext = createContext(1);
export default function App() {
return (
<>
<Section>
<Heading>主标题</Heading>
<Section>
<Heading>副标题</Heading>
<Heading>副标题</Heading>
<Heading>副标题</Heading>
<Section>
<Heading>子标题</Heading>
<Heading>子标题</Heading>
<Section>
<Heading>子子标题</Heading>
<Section>
<Heading>子子子标题</Heading>
<Section>
<Heading>子子子子标题</Heading>
</Section>
</Section>
</Section>
</Section>
</Section>
</Section>
</>
);
}