Tengo un componente personalizado en el que quiero evitar que useEffect se active cada vez que se procesa el componente.
La idea principal es obtener el nombre de la familia de fuentes de la API y luego pasarlo al valor de estilo, por lo que quiero obtener la familia de fuentes solo una vez, no cada vez que el componente se muestra en otras pantallas.
Esto es lo que probé, pero no funciona como se esperaba, no actualiza el estado después de obtener el valor de la API (no se llama a getValue() ).
import React, {useCallback, useEffect, useRef} from 'react'; import {useState} from 'react'; import {Text, StyleSheet, Platform} from 'react-native'; import {COLORS} from '../../common'; const AppText = ({children, style, ...rest}) => { const isMounted = useRef(false); const [fontFamily, setFontFamily] = useState('Helvetica-Bold'); const getValue = useCallback(() => { // mock API setTimeout(() => { console.log('AppText: get font family name from API!!'); setFontFamily('HelveticaNeue'); }, 200); }, []); useEffect(() => { if (isMounted.current) { getValue(); } else { isMounted.current = true; return; } }, [getValue]); return ( <Text style={[ styles.text, style, { fontFamily: fontFamily, }, ]} {...rest}> {children} </Text> ); }; export {AppText};usando:
Home/About/etc // other screens const Home = () => { return( <View> <AppText> Hey from home </AppText> </View> ); }Puede usar un contexto para dividir el valor en múltiples componentes (o usar accesorios) y simplemente buscarlo una vez más arriba en el árbol.
//App.js import {useEffect, createContext, useState} from "react"; export const FontFamilyContext = createContext("DefaultFont"); const App = () =>{ const [font,setFont] = useState(); useEffect( () =>{ setFont(loadFont()); },[]); return ( <FontFamilyContext.Provider value={font} > <Screen /> <ScreenViaProp fontFamily={font} /> </FontFamilyContext.Provider> ); } export default App; //Screen.jsx //Advantage The font family can be used in nested components deep down import { useContext } from "react"; import {FontContext} from "./App"; const Screen = () =>{ const fontFamily = useContext(FontFamilyContext); return ( <div style={{fontFamily: fontFamily}}> </div> ) } // ScreenViaProp .jsx Easier and no context is required const ScreenViaProp = ({fontFamily}) =>{ return ( <div style={{fontFamily: fontFamily}}> </div> ) }const DEFAULT_FONT_FAMILY = 'Helvetica-Bold'; const AppText = ({children, style, ...rest}) => { const [fontFamily, setFontFamily] = useState(DEFAULT_FONT_FAMILY); useEffect(() => { // mock API setTimeout(() => { console.log('AppText: get font family name from API!!'); const FETCHED_FONT_FAMILY = 'HelveticaNeue'; if (FETCHED_FONT_FAMILY !== fontFamily) setFontFamily(FETCHED_FONT_FAMILY); }, 200); }, []); return ( <Text style={[ styles.text, style, { fontFamily: fontFamily, }, ]} {...rest}> {children} </Text> ); };También puede usar un custom hook para cargar el valor de la fuente solo una vez en su aplicación:
customHooks.js
let fontFromApi = null; const fontP = new Promise(resolve => { setTimeout(() => { console.log('get font family name from API!!'); fontFromApi = 'HelveticaNeue'; resolve(fontFromApi); }, 200); }); export function useFont() { const [font, setFont] = useState(fontFromApi || "Helvetica-Bold"); if (fontFromApi === null) { fontP.then(v => setFont(v)); } return font; } Declaré un enlace personalizado llamado useFont devolvía la fuente de la API. Si la fuente aún no está cargada, devolverá el valor de reserva Helvetica-Bold .
AppText.jsx
const { useFont } from './customHooks' const AppText = ({children, style, ...rest}) => { const fontFamily = useFont(); return ( <Text style={[ styles.text, style, { fontFamily } ]} {...rest}> {children} </Text> ); };