背景
父组件A和子组件B都需要各自使用context来管理自己的状态,我平时都是这么用的
Context.tsx文件
import { makeContext } from '@ali/cs-react-context-utils';
function useLayoutContext() {
const [state, setState] = React.useState();
return {
state
};
}
const [LayoutContext, LayoutContextProvider] = makeContext<LayoutContextType>(useLayoutContext);
export { LayoutContext as default, LayoutContextProvider };
context提供者index.tsx文件
import React, { useContext } from 'react';
import { withContextProvider } from '@ali/cs-react-context-utils';
import LayoutContext, { LayoutContextProvider } from './LayoutContext';
function LayoutPage() {
const contextValue = useContext(LayoutContext);
return (
<div>
这里是Context提供者
</div>
);
}
export default withContextProvider(LayoutContextProvider)(LayoutPage);
问题
然而这种方式有一个问题,就是当我想要在它的父组件使用ref来用这个实例组件的一些state和function的时候,会发现拿不到,打印ref.current结果为undefined,ref我是这么用的
子组件
import React, { forwardRef, useContext, useImperativeHandle } from 'react';
const LayoutPage = forwardRef((_, ref) => {
const {state} = useContext(LayoutContext);
// 通过useImperativeHandle将组件的state和functions暴露给父组件
useImperativeHandle(ref, () => ({
state,
}));
return <div>xxx</PageContainerDiv>;
});
export default withContextProvider(LayoutContextProvider)(LayoutPage);
父组件
import React, { useRef } from 'react';
const Parent = () => {
const layoutRef = useRef();
console.log(layoutRef?.current);
return <LayoutPage ref={layoutRef} />
};
export default Parent;
查了资料发现,出现该问题的原因就是withContextProvider是一个高阶组件(HOC),它包裹了LayoutPage组件,导致ref指向HOC的实例而非原始组件,所以尽量避免这种写法
解决方案
就是使用react自己的createContext
Context.tsx文件
const LayoutContext = createContext(null);
const LayoutContextProvider = ListContext.Provider;
function useLayoutContext() {
const [state, setState] = React.useState();
return {
state
};
}
export { LayoutContext, LayoutContextProvider };
context提供者index.tsx文件
import React, { useContext } from 'react';
import { LayoutContextProvider, useLayoutContext } from './ListContext';
function LayoutPage() {
const value = useListContext();
return (
<ListContextProvider value={value}>
xxx
</ListContextProvider>
);
}
export default LayoutPage;
这样再打印ref.current就没问题了