在 React 中设置焦点
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
// 创造一个 textInput DOM 元素的 ref
this.textInput = React.createRef();
}
focus() {
// 使用原始的 DOM API 显式地聚焦在 text input 上
// 注意:我们通过访问 “current” 来获得 DOM 节点
this.textInput.current.focus();
}
render() {
// 使用 `ref` 回调函数以在实例的一个变量中存储文本输入 DOM 元素
//(比如,this.textInput)。
return (
<input
type="text"
ref={this.textInput}
/>
);
}
}
有时,父组件需要把焦点设置在其子组件的一个元素上。我们可以通过在子组件上设置一个特殊的 prop 来对父组件暴露 DOM refs 从而把父组件的 ref 传向子节点的 DOM 节点。
function CustomTextInput(props) {
return (
<div>
<input ref={props.inputRef} />
</div>
);
}
class Parent extends React.Component {
constructor(props) {
super(props);
this.inputElement = React.createRef();
}
render() {
return (
<CustomTextInput inputRef={this.inputElement} />
);
}
}
// 现在你就可以在需要时设置焦点了
this.inputElement.current.focus();
鼠标和指针事件
外部点击模式,用户可以通过点击元素以外的地方来关闭已打开的弹出框。
常规做法是组件加载时监听 window click 事件,卸载时移除,但是对于键盘切换会失效。故可以运用 onBlur 和 onFocus,实现这项功能。
class BlurExample extends React.Component {
constructor(props) {
super(props);
this.state = { isOpen: false };
this.timeOutId = null;
this.onClickHandler = this.onClickHandler.bind(this);
this.onBlurHandler = this.onBlurHandler.bind(this);
this.onFocusHandler = this.onFocusHandler.bind(this);
}
onClickHandler() {
this.setState(currentState => ({
isOpen: !currentState.isOpen
}));
}
// 我们在下一个时间点使用 setTimeout 关闭弹窗。
// 这是必要的,因为失去焦点事件会在新的焦点事件前被触发,
// 我们需要通过这个步骤确认这个元素的一个子节点
// 是否得到了焦点。
onBlurHandler() {
this.timeOutId = setTimeout(() => {
this.setState({
isOpen: false
});
});
}
// 如果一个子节点获得了焦点,不要关闭弹窗。
onFocusHandler() {
clearTimeout(this.timeOutId);
}
render() {
// React 通过把失去焦点和获得焦点事件传输给父节点
// 来帮助我们。
return (
<div onBlur={this.onBlurHandler}
onFocus={this.onFocusHandler}>
<button onClick={this.onClickHandler}
aria-haspopup="true"
aria-expanded={this.state.isOpen}>
Select an option
</button>
{this.state.isOpen && (
<ul>
<li>Option 1</li>
<li>Option 2</li>
<li>Option 3</li>
</ul>
)}
</div>
);
}
}
语义化的 HTML
JSX 需要有一个根元素,有时为了不破坏语义化,可使用 Fragment 或者短语法
function ListItem({ item }) {
return (
<Fragment>
<dt>{item.term}</dt>
<dd>{item.description}</dd>
</Fragment>
);
}
function ListItem({ item }) {
return (
<>
<dt>{item.term}</dt>
<dd>{item.description}</dd>
</>
);
}
React.lazy 组件懒加载
fallback
属性接受任何在组件加载过程中你想展示的 React
元素。你可以将 Suspense
组件置于懒加载组件之上的任何位置。你甚至可以用一个 Suspense
组件包裹多个懒加载组件。
import React, { Suspense } from 'react';
const OtherComponent = React.lazy(() => import('./OtherComponent'));
const AnotherComponent = React.lazy(() => import('./AnotherComponent'));
function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<section>
<OtherComponent />
<AnotherComponent />
</section>
</Suspense>
</div>
);
}
context
context 设计目的是为了共享那些对于一个组件树而言是“全局”的数据,例如当前认证的用户、主题或首选语言。
// Context 可以让我们无须明确地传遍每一个组件,就能将值深入传递进组件树。
// 为当前的 theme 创建一个 context(“light”为默认值)。
const ThemeContext = React.createContext('light');
class App extends React.Component {
render() {
// 使用一个 Provider 来将当前的 theme 传递给以下的组件树。
// 无论多深,任何组件都能读取这个值。
// 在这个例子中,我们将 “dark” 作为当前的值传递下去。
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
}
// 中间的组件再也不必指明往下传递 theme 了。
function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}
class ThemedButton extends React.Component {
// 指定 contextType 读取当前的 theme context。
// React 会往上找到最近的 theme Provider,然后使用它的值。
// 在这个例子中,当前的 theme 值为 “dark”。
static contextType = ThemeContext;
render() {
return <Button theme={this.context} />;
}
}
网友评论