React基础学习-Day05
常见的React API及基础使用方式
1.useContext
createContext
是 React 提供的一个 API,用于创建一个上下文对象,用于在组件树中跨层级传递数据而不必一级一级手动传递 props。
基本用法
以下是 createContext
的基本用法示例:
import React, { createContext, useContext, useState } from 'react';
// 创建一个上下文对象
const ThemeContext = createContext();
// 提供一个上下文的提供者组件
const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
);
};
// 使用上下文的消费者组件
const ThemeToggler = () => {
const { theme, setTheme } = useContext(ThemeContext);
const toggleTheme = () => {
setTheme(theme === 'light' ? 'dark' : 'light');
};
return (
<div>
<p>Current Theme: {theme}</p>
<button onClick={toggleTheme}>Toggle Theme</button>
</div>
);
};
// 在应用中使用上下文
const App = () => {
return (
<ThemeProvider>
<div>
<h1>Theme Toggler</h1>
<ThemeToggler />
</div>
</ThemeProvider>
);
};
export default App;
在这个示例中:
createContext
创建了一个ThemeContext
对象,它包含了theme
和setTheme
。ThemeProvider
是一个上下文的提供者组件,使用ThemeContext.Provider
提供了theme
和setTheme
给它的子组件。ThemeToggler
是一个消费者组件,通过useContext(ThemeContext)
获取了theme
和setTheme
。App
组件将ThemeProvider
包裹在最外层,以便整个应用都可以访问到ThemeContext
提供的数据。
注意事项
createContext
返回的对象包含Provider
和Consumer
组件。Provider
用于提供数据,通过value
属性传递给后代组件。Consumer
可以通过useContext
钩子或者<ThemeContext.Consumer>
组件消费上下文数据。- 如果没有提供
Provider
,useContext(ThemeContext)
将返回上下文的默认值(如果有的话),否则会报错。
高级用法
设置默认值
const ThemeContext = createContext('light');
在这个示例中,如果没有在组件树中的任何地方提供 ThemeProvider
,useContext(ThemeContext)
将会返回 'light'
。
使用多个上下文
const ThemeContext = createContext();
const UserContext = createContext();
可以在同一个应用中创建多个上下文,并通过嵌套的方式传递数据。
分离提供者和消费者
const ThemeConsumer = ThemeContext.Consumer;
const SomeComponent = () => (
<ThemeConsumer>
{value => <div>Current Theme: {value}</div>}
</ThemeConsumer>
);
你可以使用 ThemeContext.Consumer
显式地包装需要消费上下文的部分。
总结
createContext
是 React 提供的一个非常有用的 API,用于在组件树中传递数据,而不必显式地通过 props 传递。它允许你有效地组织和管理应用中的状态和数据流,使得组件之间的通信更加简单和高效。
2.forwardRef
forwardRef
是 React 提供的一个 API,用于在组件中向子组件转发 ref
。它允许父组件通过 ref
访问子组件的 DOM 节点或实例。
基本用法
以下是 forwardRef
的基本用法示例:
import React, { forwardRef, useRef } from 'react';
// 子组件
const ChildComponent = forwardRef((props, ref) => {
return <input ref={ref} />;
});
// 父组件
const ParentComponent = () => {
const inputRef = useRef(null);
const focusInput = () => {
inputRef.current.focus();
};
return (
<div>
<button onClick={focusInput}>Focus Input</button>
<ChildComponent ref={inputRef} />
</div>
);
};
export default ParentComponent;
在这个示例中:
ChildComponent
使用forwardRef
包装,允许父组件通过ref
访问子组件的<input>
元素。ParentComponent
创建了一个inputRef
,并将其作为ref
属性传递给ChildComponent
。- 当点击 “Focus Input” 按钮时,调用
focusInput
函数使<input>
元素获取焦点。
注意事项
forwardRef
接受一个渲染函数作为参数,该函数接收props
和ref
参数,并返回一个 React 元素。ref
必须通过forwardRef
的第二个参数(即ref
参数)传递给子组件内部需要引用的 DOM 元素或组件实例。- 使用
forwardRef
可以确保子组件能够正确处理ref
,从而实现对子组件内部 DOM 的访问或操作。
高级用法
包装子组件
import React, { forwardRef, useRef, useImperativeHandle } from 'react';
// 子组件
const ChildComponent = forwardRef((props, ref) => {
const inputRef = useRef(null);
// 暴露方法给父组件
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
},
blur: () => {
inputRef.current.blur();
}
}));
return <input ref={inputRef} />;
});
// 父组件
const ParentComponent = () => {
const childRef = useRef(null);
const focusInput = () => {
childRef.current.focus();
};
const blurInput = () => {
childRef.current.blur();
};
return (
<div>
<button onClick={focusInput}>Focus Input</button>
<button onClick={blurInput}>Blur Input</button>
<ChildComponent ref={childRef} />
</div>
);
};
export default ParentComponent;
在这个示例中,ChildComponent
使用 useImperativeHandle
来暴露 focus
和 blur
方法给父组件,以便父组件可以直接调用子组件的方法来操作 <input>
元素。
总结
forwardRef
是一个非常有用的 React API,用于在函数组件中向子组件转发 ref
。它使得在函数式组件中访问子组件的 DOM 元素或实例变得简单和直观。通过 forwardRef
,你可以更灵活地管理 React 组件之间的交互和数据流动。
3.lazy
lazy
是 React 提供的一个 API,用于实现组件的懒加载(延迟加载)。它允许你在组件需要时再进行加载,从而优化应用程序的性能,特别是在大型应用中使用。
基本用法
以下是 lazy
的基本用法示例:
import React, { lazy, Suspense } from 'react';
// 懒加载组件
const LazyComponent = lazy(() => import('./LazyComponent'));
// 父组件
const ParentComponent = () => (
<div>
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
</div>
);
export default ParentComponent;
在这个示例中:
LazyComponent
是一个通过lazy
函数动态导入的懒加载组件。Suspense
组件用于在组件加载完成前显示一个加载指示器(即fallback
属性指定的内容)。- 当
LazyComponent
加载完成后,它会被渲染到父组件中。
注意事项
lazy
函数接受一个函数作为参数,该函数调用import()
来动态加载组件。这种方式只支持默认导出的组件。- 使用
lazy
必须和Suspense
组件一起使用,以便在组件加载完成前提供一个备用内容(例如加载指示器)。 Suspense
组件只能用在包含动态加载组件的父组件中,不能单独使用。
高级用法
多个懒加载组件
import React, { lazy, Suspense } from 'react';
// 懒加载组件
const LazyComponent1 = lazy(() => import('./LazyComponent1'));
const LazyComponent2 = lazy(() => import('./LazyComponent2'));
// 父组件
const ParentComponent = () => (
<div>
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent1 />
<LazyComponent2 />
</Suspense>
</div>
);
export default ParentComponent;
可以同时在一个父组件中使用多个懒加载组件,每个懒加载组件都会在需要时进行加载。
自定义加载指示器
import React, { lazy, Suspense } from 'react';
import LoadingSpinner from './LoadingSpinner';
// 懒加载组件
const LazyComponent = lazy(() => import('./LazyComponent'));
// 父组件
const ParentComponent = () => (
<div>
<Suspense fallback={<LoadingSpinner />}>
<LazyComponent />
</Suspense>
</div>
);
export default ParentComponent;
可以自定义 Suspense
组件中的 fallback
属性,以展示自定义的加载指示器(例如 LoadingSpinner
组件)。
总结
lazy
和 Suspense
是 React 中用于实现组件懒加载的重要工具。通过将组件的加载推迟到需要时再进行,可以显著提高应用程序的性能和加载速度,尤其是在处理大型应用时。使用 lazy
和 Suspense
可以帮助你更有效地管理和优化 React 应用的性能。
4.memo
当你使用 React.memo
来优化函数组件的性能时,它实际上是在帮助你避免不必要的重新渲染。这对于那些在相同 props 下渲染结果不变的组件特别有用,因为 React 默认情况下会在每次父组件重新渲染时,即使 props 没有变化,也会重新渲染子组件。
基本工作原理
- 缓存组件的渲染结果: 当你使用
React.memo
包裹一个函数组件时,React 会缓存该组件的渲染结果。 - 比较 props: 在下一次渲染时,React 会比较当前 props 和上一次渲染时的 props。
- 条件性重新渲染: 如果当前 props 和上一次渲染的 props 是浅层相等的(即
Object.is(prevProps, nextProps)
返回true
),则 React 会重用上一次的渲染结果,从而跳过不必要的重新渲染。
使用示例
以下是一个更详细的示例,展示了如何使用 React.memo
:
import React from 'react';
const MyComponent = React.memo((props) => {
console.log('MyComponent 渲染了'); // 仅在首次渲染或 props 变化时打印
return (
<div>
<h2>{props.title}</h2>
<p>{props.content}</p>
</div>
);
});
export default MyComponent;
在这个例子中,MyComponent
是一个简单的函数组件,它接受 title
和 content
作为 props。使用 React.memo
可以确保只有在 title
或 content
发生变化时才会重新渲染组件。
自定义比较函数
有时候,你可能需要更精确地控制何时重新渲染组件,特别是当 props 包含复杂的数据结构时。这时可以通过传递第二个参数给 React.memo
,来定义一个自定义的比较函数:
import React from 'react';
const MyComponent = React.memo((props) => {
console.log('MyComponent 渲染了'); // 仅在首次渲染或 props.id 变化时打印
return (
<div>
<h2>{props.title}</h2>
<p>{props.content}</p>
</div>
);
}, (prevProps, nextProps) => {
// 自定义比较函数示例:仅当 props.id 发生变化时重新渲染
return prevProps.id === nextProps.id;
});
export default MyComponent;
在这个例子中,比较函数 (prevProps, nextProps) => prevProps.id === nextProps.id
确保只有当 id
发生变化时,才会触发重新渲染 MyComponent
。
总结
使用 React.memo
可以显著提升 React 应用的性能,特别是在大型应用中或者需要频繁渲染的场景下。它通过缓存和比较 props 的方式,有效地减少了不必要的组件重新渲染,从而提升了用户体验和应用性能。
5.startTransition
在 React 中,startTransition
是一个用于启动转换(transition)的函数,通常与 Suspense
和 useTransition
配合使用,用于优化异步操作时的用户体验。
基本用法
startTransition
主要用于启动一个由 useTransition
提供的过渡。这种过渡通常用于告知 React 在加载或者异步更新期间的状态,并可以帮助优化性能。
import React, { useState, useTransition } from 'react';
function MyComponent() {
const [startTransition, isPending] = useTransition();
const [data, setData] = useState(null);
const fetchData = () => {
startTransition(() => {
fetchSomeData().then(response => {
setData(response.data);
});
});
};
return (
<div>
{isPending ? <p>Loading...</p> : null}
<button onClick={fetchData} disabled={isPending}>
{isPending ? 'Fetching...' : 'Fetch Data'}
</button>
{data && <p>{data}</p>}
</div>
);
}
export default MyComponent;
使用说明
- useTransition Hook: 使用
useTransition
Hook 来获取startTransition
函数和一个布尔值isPending
,用来指示当前是否处于过渡状态。 - startTransition 函数:
startTransition
接受一个回调函数作为参数,这个回调函数包含了需要进行转换的异步操作。 - 优化用户体验: 使用
startTransition
可以帮助你在进行异步操作时提供更好的用户体验,例如在数据加载期间显示加载指示器,避免页面看起来卡顿或者无响应。
注意事项
startTransition
应该始终与useTransition
一起使用,以确保正确的过渡状态管理。- 尽管
startTransition
可以帮助提升用户体验,但在具体使用时应根据实际情况权衡,避免滥用导致过渡效果对用户体验造成负面影响。
总结
startTransition
是 React 中用于启动过渡的函数,通常与 useTransition
和异步操作一起使用,以优化用户体验和应用性能。它提供了一种方式来管理在数据加载或者其他异步更新过程中的状态,并能够帮助你更好地控制和优化页面的响应性。