En mi página de inicio, tengo un código como este
{selectedTab===0 && <XList allItemList={some_list/>} {selectedTab===1 && <YList allItemList={some_list2/>}Ahora, en XList, tengo algo como esto:
{props.allItemList.map(item => <XItem item={item}/>)}Ahora, dentro de XItem, estoy llamando a una API para obtener la imagen de XItem.
Ahora mi problema es cuando en la página de inicio, cambié la pestaña de 0 a 1 o de 1 a 0, está llamando a todas las API en XItem nuevamente. Cada vez que cambié de pestaña, vuelve a llamar a la API. no quiero eso Ya usé useEffect dentro de XItem con [] matriz como segundo parámetro.
Tengo mi código de back-end donde hice una API para obtener la imagen de XItem. La API devuelve la imagen directamente y no la URL, por lo que no puedo llamar a todas las API una vez.
Necesito alguna solución para poder minimizar la llamada api. Gracias por la ayuda.
El problema básico es que con la forma en que selecciona la pestaña seleccionada, está montando y desmontando los componentes. Volver a montar los componentes necesariamente vuelve a ejecutar cualquier devolución de llamada useEffect de montaje que realice solicitudes de red y almacene cualquier resultado en el estado del componente local. Desmontar el componente necesariamente elimina el estado del componente.
{selectedTab === 0 && <XList allItemList={some_list} />} {selectedTab === 1 && <YList allItemList={some_list2} />} Una solución podría ser pasar un accesorio isActive tanto a XList como a YList y establecer el valor en función del valor de la pestaña selectedTab . Cada componente representa condicionalmente su contenido en función de la propiedad isActive . La idea es mantener los componentes montados para que solo obtengan los datos una vez cuando se montaron inicialmente.
<XList allItemList={some_list} isActive={selectedTab === 0} /> <YList allItemList={some_list2} isActive={selectedTab === 1} /> Ejemplo XList
const XList = ({ allItemList, isActive }) => { useEffect(() => { // expensive network call }, []); return isActive ? props.allItemList.map(item => <XItem item={item}/>) : null; };Los medios alternativos incluyen elevar las solicitudes de API y el estado al componente principal y pasarlas como accesorios. O usando un contexto React para hacer lo mismo y proporcionar el estado a través del contexto. O implementar/añadir a una gestión de estado global como Redux/Thunks.
Solo para expandir rápidamente la respuesta de Drew Reese , considere hacer que sus pestañas sean elementos secundarios de un componente Tabs. De esa manera, sus componentes están (ligeramente) más desacoplados.
const MyTabulator = ({ children }) => { const kids = React.useMemo(() => React.Children.toArray(children), [children]); const [state, setState] = React.useState(0); return ( <div> {kids.map((k, i) => ( <button key={k.props.name} onClick={() => setState(i)}> {k.props.name} </button> ))} {kids.map((k, i) => React.cloneElement(k, { key: k.props.name, isActive: i === state }) )} </div> ); };y un envoltorio para manejar el accesorio isActive
const Tab = ({ isActive, children }) => <div hidden={!isActive}>{children}</div>Luego renderízalos así
<MyTabulator> <Tab name="x list"><XList allItemList={some_list} /></Tab> <Tab name="y list"><YList allItemList={some_list2} /></Tab> </MyTabulator>Mi opinión sobre este tema. Puede envolver el componente XItem con React.memo :
const XItem = (props) => { ... } const areEqual = (prevProps, nextProps) => { /* Add your logic here to check if you want to rerender XItem return true if you don't want rerender return false if you want a rerender */ } export default React.memo(XItem, areEqual); La lógica es la misma si elige usar useMemo .
Si desea usar useCallback (mi opción predeterminada), solo necesitaría envolver la llamada que realiza a la API.