Issue
I have a React Native code, which consists of a Markdown editor that parses the text and extracts information about Headers. I plan to build a menu with the headers and when clicked jump to the header inside the editor. Something like a Table of Contents.
const Editor = ({ initValue, style, onChange = () => {} }: EditorProps) => {
const [value, setValue] = useState<string>(initValue);
const { setHeaderNodes } = useHeaderNavigation();
const changeHandler = (text: string) => {
setValue(text);
onChange(text);
};
const ast = parse(value);
const headers: HeaderNavigationNode[] = useMemo(() => {
return ast.filter(isHeaderNode).map(node => {
const { content, loc: { start: { line } } } = node;
return { content, line };
});
}, [ast]);
useEffect(() => {
setHeaderNodes(headers);
}, [headers]);
console.log(JSON.stringify(headers, null, 4));
...
};
// Context.ts
import { createContext, useContext } from 'react';
export interface HeaderNavigationNode {
content: string;
line: number;
}
export interface Context {
headerNodes: HeaderNavigationNode[];
setHeaderNodes: (nodes: HeaderNavigationNode[]) => void;
}
export const NavigationContext = createContext<Context>(null)
export const useHeaderNavigation = () => useContext(NavigationContext);
// App.tsx
export default function App() {
const [headerNodes, setHeaderNodes] = useState<HeaderNavigationNode[]>([]);
return (
<NavigationContext.Provider value={{ headerNodes, setHeaderNodes }}>
<NavigationContainer>
<Drawer.Navigator initialRouteName="Main" drawerContent={CustomDrawer}>
<Drawer.Screen name="Main" component={Main} />
</Drawer.Navigator>
</NavigationContainer>
<StatusBar style="auto" />
</NavigationContext.Provider>
);
}
const Main = () => {
return (
<Layout>
<Editor
initValue={`# HEADER 1
\`\`\`
function hello(name) {
return \`hello $\{name}\`;
}
\`\`\``} />
</Layout>
);
};
The problem is that it this creates infinite loop of rerender. I've tried to add useMemo for the headers
but this didn't fix the issue. I think that I add React.memo for the editor. But this sounds like a hack the same as useMemo in my code.
What should I do to make the array inside Context doesn't rerender everything in a loop?
I know that ast
is new array/object each time the components re-render so I need some kind of deep checking if the array of HeaderNodes is the same as before when calling setHeaderNodes
but I'm not sure how to do that.
Solution
I ended up solving the issue by serializing the headers array to a string and using that as a dependency:
useEffect(() => {
setHeaderNodes(headers);
}, [JSON.stringify(headers)]);
The component is rendered twice when headers
change but I don't think you can do anything with this issue.
Answered By - jcubic
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.