以结果为导向,写给刚学完前端三剑客和想要了解 React 框架的小伙伴,使得他们能快速上手(省略了历史以及一些不必要的介绍)。
children prop
You can think of a component with a
children
prop as having a “hole” that can be “filled in” by its parent components with arbitrary JSX.
我们将通过 React 的 children prop 像使用 HTML 开合标签一样使用 React 元素,把之前使用的文本 ”Search: “ 从上层传下来,不再使用 label prop:
const App = () => { ... return ( <> <InputWithLabel id="search" value={searchTerm} onInputChange={handleSearch} > <strong>Search:</strong> </InputWithLabel> <hr /> <List list={searchedStories} /> </> ); }; const InputWithLabel = ({ id, value, type = "text", onInputChange, children, }) => ( <> <label htmlFor={id}>{children}</label> <input id={id} type={type} value={value} onChange={onInputChange} /> </> ); 复制代码
我们可以把字符串, HTML 元素 <strong>
,以及【组件】等任意 JSX 元素当作 React children 传递,有了这个特性,我们可以就像使用 HTML 元素一样交织使用 React 组件。
指令式 React
从 JSX 到 hook,一直都是我们告诉 React 去渲染什么,而不是怎么去渲染,所以 React 天生是声明式的。
但并不是所有时候都能使用声明的方式,有些情况我们不免要通过指令式的方式去访问渲染好的 JSX 元素,比如我们需要调用 DOM API 的 focus()
方法给搜索框添加一个自动聚焦的功能。
- 命令式写法,设定属性值:
const App = () => { ... return ( <> <InputWithLabel id="search" value={searchTerm} onInputChange={handleSearch} isFocused > <strong>Search:</strong> </InputWithLabel> <hr /> <List list={searchedStories} /> </> ); }; const InputWithLabel = ({ id, value, type = "text", onInputChange, children, isFocused, }) => ( <> <label htmlFor={id}>{children}</label> <input id={id} type={type} value={value} onChange={onInputChange} autoFocus={isFocused} /> </> ); 复制代码
- 指令式写法,通过程序调用 DOM API:
const InputWithLabel = ({ id, value, type = "text", onInputChange, children, isFocused, }) => { const inputRef = React.useRef(); // 1 React.useEffect(() => { // 3 if (isFocused && inputRef.current) { inputRef.current.focus(); // 4 } }, [isFocused]); return ( <> <label htmlFor={id}>{children}</label> {/* 2 */} <input ref={inputRef} id={id} type={type} value={value} onChange={onInputChange} /> </> ); }; 复制代码
- 首先,使用 useRef hook 创建一个 ref ,也就是一个引用对象。它在组件的整个生命周期中保持不变,向外暴露一个可变的 current 属性,并把初始化被传入的参数作为 current 属性值。
- 把 ref 对象通过 JSX 的 ref 标签传递给输入框之后,这个 DOM 节点就会被赋给 current 属性,也就是说
inputRef.current
现在已经指向了挂载在 DOM 上的输入框节点。 - 调用 useEffect hook,当组件渲染或是依赖数组改变时,使焦点落在输入框上。
- 最后,当设置了
isFocused
并且 current 属性存在时,通过 current 属性访问到输入框实现自动聚焦。
Essentially,
useRef
is like a “box” that can hold a mutable value in its.current
property.
也就是说我们通过 useRef hook 拿到了 DOM 节点并且调用了 DOM API,把原来的声明式转换为了指令式,更多 useRef 的用法可以查看官方文档。