useImperativeHandle 用于子组件但无法从父组件获取函数
useImperativeHandle usage for children componenent but cannot get function from parent
我有反应写的应用程序:
主要应用程序是:
function App({articles}) {
...
const SortVote=()=>{
console.log(childRef.current);
console.log(Object.getOwnPropertyNames(childRef.current))
childRef.current.SortVote();
}
const [art, setArt]= useState(articles);
const childRef = useRef();
return (
<div className="App">
<h8k-navbar header={title}></h8k-navbar>
<div className="layout-row align-items-center justify-content-center my-20 navigation">
<label className="form-hint mb-0 text-uppercase font-weight-light">Sort By</label>
<button data-testid="most-upvoted-link" className="small" onClick={SortVote}>Most Upvoted</button>
</div>
<Articles articles={art} cRef={childRef}/>
</div>
);
}
子组件是:
function Articles({ articles, cRef }) {
const [arts, setArts] = useState(articles);
const sortVote = () => {
const result = articles.sort((a, b) => {
if (a.upvotes > b.upvotes) {
return -1;
}
if (a.upvotes < b.upvotes) {
return 1;
}
return 0;
});
setArts(result);
};
const sortDate = () => {
const result = articles.sort((a, b) => {
if (a.date > b.date) {
return -1;
}
if (a.date < b.date) {
return 1;
}
return 0;
});
setArts(result);
};
useImperativeHandle(cRef, () => ({
sortVote,
sortDate
}));
if (articles)
return (
<div className="card w-50 mx-auto">
<table>
<thead>
<tr>
<th>Title</th>
<th>Upvotes</th>
<th>Date</th>
</tr>
</thead>
<tbody>
{arts.map((item, index) => (
<tr data-testid="article" key={index}>
<td data-testid="article-title">{item.title}</td>
<td data-testid="article-upvotes">{item.upvotes}</td>
<td data-testid="article-date">{item.date}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
我在子组件中使用 useImperativeHandle 并尝试在父组件中使用 'childRef.current.SortVote()' 来调用子组件函数。但是浏览器报错:
childRef.current.SortVote is not a function
完整代码开启:https://stackblitz.com/edit/react-vy7df9
在useImpertiveHandle hook时,SortVote和sortDate是已经定义好的函数,为什么这里还是报错SortVote is not function?
问题
useImperativeHandle
与传递的 React 引用一起使用,不是持有引用值的道具。
useImperativeHandle
customizes the instance value that is exposed to
parent components when using ref
. As always, imperative code using
refs should be avoided in most cases. useImperativeHandle
should
be used with forwardRef
:
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);
在您的代码中,您没有将 ref 传递给子组件,而是传递了一个具有 ref 值的 prop。
<Articles cRef={childRef} articles={art} />
对
<Articles ref={childRef} articles={art} />
解决方案
首先,更新 Articles
组件的函数签名以使用 React 引用。请注意,这是传递给函数的 second 参数,props
对象是第一个。
function Articles({ articles }, ref) {
...
useImperativeHandle(ref, () => ({
sortVote,
sortDate
}));
if (articles) {
return (
...
);
}
return null;
}
接下来,将 Articles
组件包装在 React.forwardRef 中。
Articles = forwardRef(Articles);
最后,将 ref 传递给 Articles
组件。注意,是sortVote
,不是SortVote
.
function App({articles}) {
const [art, setArt]= useState(articles);
const childRef = useRef();
...
const SortVote=()=>{
console.log(childRef.current);
console.log(Object.getOwnPropertyNames(childRef.current))
childRef.current.sortVote();
}
return (
<div className="App">
...
<Articles
ref={childRef}
articles={art}
/>
</div>
);
}
更新
您的子 Articles
组件中也存在错误。 Array.prototype.sort
进行就地排序,这意味着它会改变 arts
状态。您首先需要在排序之前复制数组。 Array.prototype.slice
是一种简单的函数式编程方法,可在排序前内联复制数组。
function Articles({ articles }, ref) {
const [arts, setArts] = useState(articles);
const sortVote = () => {
const result = articles.slice().sort((a, b) => {
if (a.upvotes > b.upvotes) {
return -1;
}
if (a.upvotes < b.upvotes) {
return 1;
}
return 0;
});
setArts(result);
};
const sortDate = () => {
const result = articles.slice().sort((a, b) => {
if (a.date > b.date) {
return -1;
}
if (a.date < b.date) {
return 1;
}
return 0;
});
setArts(result);
};
...
我有反应写的应用程序:
主要应用程序是:
function App({articles}) {
...
const SortVote=()=>{
console.log(childRef.current);
console.log(Object.getOwnPropertyNames(childRef.current))
childRef.current.SortVote();
}
const [art, setArt]= useState(articles);
const childRef = useRef();
return (
<div className="App">
<h8k-navbar header={title}></h8k-navbar>
<div className="layout-row align-items-center justify-content-center my-20 navigation">
<label className="form-hint mb-0 text-uppercase font-weight-light">Sort By</label>
<button data-testid="most-upvoted-link" className="small" onClick={SortVote}>Most Upvoted</button>
</div>
<Articles articles={art} cRef={childRef}/>
</div>
);
}
子组件是:
function Articles({ articles, cRef }) {
const [arts, setArts] = useState(articles);
const sortVote = () => {
const result = articles.sort((a, b) => {
if (a.upvotes > b.upvotes) {
return -1;
}
if (a.upvotes < b.upvotes) {
return 1;
}
return 0;
});
setArts(result);
};
const sortDate = () => {
const result = articles.sort((a, b) => {
if (a.date > b.date) {
return -1;
}
if (a.date < b.date) {
return 1;
}
return 0;
});
setArts(result);
};
useImperativeHandle(cRef, () => ({
sortVote,
sortDate
}));
if (articles)
return (
<div className="card w-50 mx-auto">
<table>
<thead>
<tr>
<th>Title</th>
<th>Upvotes</th>
<th>Date</th>
</tr>
</thead>
<tbody>
{arts.map((item, index) => (
<tr data-testid="article" key={index}>
<td data-testid="article-title">{item.title}</td>
<td data-testid="article-upvotes">{item.upvotes}</td>
<td data-testid="article-date">{item.date}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
我在子组件中使用 useImperativeHandle 并尝试在父组件中使用 'childRef.current.SortVote()' 来调用子组件函数。但是浏览器报错:
childRef.current.SortVote is not a function
完整代码开启:https://stackblitz.com/edit/react-vy7df9
在useImpertiveHandle hook时,SortVote和sortDate是已经定义好的函数,为什么这里还是报错SortVote is not function?
问题
useImperativeHandle
与传递的 React 引用一起使用,不是持有引用值的道具。
useImperativeHandle
customizes the instance value that is exposed to parent components when usingref
. As always, imperative code using refs should be avoided in most cases.useImperativeHandle
should be used withforwardRef
:function FancyInput(props, ref) { const inputRef = useRef(); useImperativeHandle(ref, () => ({ focus: () => { inputRef.current.focus(); } })); return <input ref={inputRef} ... />; } FancyInput = forwardRef(FancyInput);
在您的代码中,您没有将 ref 传递给子组件,而是传递了一个具有 ref 值的 prop。
<Articles cRef={childRef} articles={art} />
对
<Articles ref={childRef} articles={art} />
解决方案
首先,更新 Articles
组件的函数签名以使用 React 引用。请注意,这是传递给函数的 second 参数,props
对象是第一个。
function Articles({ articles }, ref) {
...
useImperativeHandle(ref, () => ({
sortVote,
sortDate
}));
if (articles) {
return (
...
);
}
return null;
}
接下来,将 Articles
组件包装在 React.forwardRef 中。
Articles = forwardRef(Articles);
最后,将 ref 传递给 Articles
组件。注意,是sortVote
,不是SortVote
.
function App({articles}) {
const [art, setArt]= useState(articles);
const childRef = useRef();
...
const SortVote=()=>{
console.log(childRef.current);
console.log(Object.getOwnPropertyNames(childRef.current))
childRef.current.sortVote();
}
return (
<div className="App">
...
<Articles
ref={childRef}
articles={art}
/>
</div>
);
}
更新
您的子 Articles
组件中也存在错误。 Array.prototype.sort
进行就地排序,这意味着它会改变 arts
状态。您首先需要在排序之前复制数组。 Array.prototype.slice
是一种简单的函数式编程方法,可在排序前内联复制数组。
function Articles({ articles }, ref) {
const [arts, setArts] = useState(articles);
const sortVote = () => {
const result = articles.slice().sort((a, b) => {
if (a.upvotes > b.upvotes) {
return -1;
}
if (a.upvotes < b.upvotes) {
return 1;
}
return 0;
});
setArts(result);
};
const sortDate = () => {
const result = articles.slice().sort((a, b) => {
if (a.date > b.date) {
return -1;
}
if (a.date < b.date) {
return 1;
}
return 0;
});
setArts(result);
};
...