Merging two objects with useContext and state? - reactjs

So i have this problem where it doesn't merge the two objects since refsContext is empty when useEffect gets called after render. It ends with only one of the refs in the object. useEffect(() => {setRef(something)}, [ref]); results in an infinite empty object loop. Did i miss something?
refs.context.jsx
import { createContext } from "react";
const refsContext = createContext({});
export default refsContext;
Same code over multiple files
/** #jsx jsx */
import React, { useContext, useEffect, useRef } from "react";
import refsContext from "../../context/refs.context";
const StackoverflowExample= () => {
const projectsRef = useRef(null);
const [ref, setRef] = useContext(refsContext);
useEffect(() => {
setRef({ ...ref, projects: projectsRef.current });
}, []);
return (
<section ref={projectsRef}></section>
);
};
export default StackoverflowExample;
App.jsx
import React, { useState, useEffect } from "react";
import { render } from "react-dom";
import Pages from "./Pages";
import { BrowserRouter } from "react-router-dom";
import refsContext from "./context/refs.context";
const App = () => {
//Default Contexts
const refsHook = useState({});
console.log(refsHook[0]);
//All my wrappers/providers for my App
return (
<refsContext.Provider value={refsHook}>
<BrowserRouter>
<Pages/>
</BrowserRouter>
</refsContext.Provider>
);
};
render(<App />, document.getElementById("root"));

Related

React ScrollToTop component problem : it should work but it doesn't

I am coding a React app and I'm trying to use a ScrollToTop component in order to scroll down in the app. But the problem is that for some reason it is not working at all.
Please help I'm really struggling with this one...
import { useEffect } from "react";
import { useLocation } from "react-router-dom";
export default () => {
const { pathname } = useLocation();
useEffect(() => {
window.scrollTo({ top: 0, left: 0, behavior: "auto" });
}, [pathname]);
return null;
}
And I import this component in App.js
import React from 'react'
import { HashRouter } from "react-router-dom";
// import * as serviceWorker from './serviceWorker';
// core styles
import "./scss/volt.scss";
// vendor styles
import "#fortawesome/fontawesome-free/css/all.css";
import "react-datetime/css/react-datetime.css";
import HomePage from "./pages/HomePage";
import ScrollToTop from "./ScrollToTop";
function App() {
return (
<HashRouter>
<ScrollToTop/>
<HomePage />
</HashRouter>
)
}
export default App
Can anybody help me?
Please try with this.
import { useEffect } from "react";
import { useLocation } from "react-router-dom";
export default () => {
const { pathname } = useLocation();
useEffect(() => {
window.scrollTo(0,0);
}, [pathname]);
return null;
}

Getting "TypeError: render is not a function" error when i import context from another file

I am trying to do react context on a function. Initially, I created react context in the same file as the provider, but then I got a warning on the console saying that I should put context in a separate file, but when I do that, for some bizarre reason, I get an error, even though I am pretty much doing the exact same thing, what am I doing wrong? I am only showing the relevant bits of the code.
The following code below works fine
import * as React from 'react';
import {
BrowserRouter as Router,
NavLink,
Switch,
Route,
} from 'react-router-dom';
import Header from './header.js';
import './OldApp.css';
import { useState, useEffect } from 'react';
//Context import commented
//import UserObjAndDbProvider from './dbAndUserObjContext';
import routes from './routes';
import firebase from "firebase/app";
import "firebase/auth";
import "firebase/firestore";
const Context = React.createContext();
export const UserObjAndDbProvider = Context.Provider;
export const UserObjAndDbConsumer = Context.Consumer;
const App = ({ user, database }) => {
var [membership, setMembership] = useState(false);
const docRef = database.collection("userCollection").doc(`${user.uid}`)
//get data
const FindOutMembership = async () => {
var booleanVal = null;
docRef.get().then(function(doc) {
if (doc.exists) {
const booleanVal = doc.data().membership;
setMembership(membership = booleanVal);
} else {
console.log("Error: no such document exists")
}
})
}
useEffect(() => {
FindOutMembership();
})
return (
<UserObjAndDbProvider value={'i am sexy and i like it'}>
<Router>
//some routing stuff done here
</Router>
</UserObjAndDbProvider>
);
};
export default App;
but when i take context stuff out, and put in in another file(which is in the same folder) and import it i get a weird error titled "TypeError: render is not a function"
import * as React from 'react';
import {
BrowserRouter as Router,
NavLink,
Switch,
Route,
} from 'react-router-dom';
import Header from './header.js';
import './OldApp.css';
import { useState, useEffect } from 'react';
//Context import now uncomment
import UserObjAndDbProvider from './dbAndUserObjContext';
import routes from './routes';
import firebase from "firebase/app";
import "firebase/auth";
import "firebase/firestore";
import { useContext, createContext } from 'react';
const App = ({ user, database }) => {
var [membership, setMembership] = useState(false);
const docRef = database.collection("userCollection").doc(`${user.uid}`)
const FindOutMembership = async () => {
var booleanVal = null;
docRef.get().then(function(doc) {
if (doc.exists) {
const booleanVal = doc.data().membership;
setMembership(membership = booleanVal);
} else {
console.log("Error: no such document exists")
}
})
}
useEffect(() => {
FindOutMembership();
})
//console.log(membership);
return (
<UserObjAndDbProvider value={'i am sexy and i like it'}>
<Router>
//some routing stuff done here
</Router>
</UserObjAndDbProvider>
);
};
export default App;
my context file is called dbAndUserObjContext.js and looks like this
import React from 'react'
import { createContext } from 'react';
const Context = React.createContext();
export const UserObjAndDbProvider = Context.Provider;
export const UserObjAndDbConsumer = Context.Consumer;
export default Context;

How to share components with hooks between two windows?

I'm trying to share components between two windows. index.html has an iframe the src of which is iframe.html. I want iframe.html to render components defined in index.html. This works well, as long as components don't use any hooks. If hooks are used, Invalid hook call error occurs. Here are code for explanation. Do you have any workaround?
index.html
<body><div id="root"></div><script src="index.js"></script></body>
index.ts
import React, { FC, useState } from 'react';
import ReactDOM from 'react-dom';
const ComponentWithHook: FC = () => {
const [value] = useState('xxxx');
return <>{value}</>;
};
(window as any).getComponent = () => ComponentWithHook;
ReactDOM.render(<iframe src="iframe.html" />, document.getElementById('root'));
iframe.html
<body><div id="root"></div><script src="iframe.js"></script></body>
iframe.ts
import React, { FC } from 'react';
import ReactDOM from 'react-dom';
const Dummy: FC = () => {
const ComponentWithHook = (top as any).getComponent();
return <ComponentWithHook />;
};
ReactDOM.render(<Dummy />, document.getElementById('root'));
Self-solving:
It has resolved by passing React as a prop and using it inside a component.
index.ts
import React, { FC, useState } from 'react';
import ReactDOM from 'react-dom';
const ComponentWithHook: FC<{ React: typeof React }> = ({ React }) => {
const [value] = React.useState('xxxx');
return <>{value}</>;
};
(window as any).getComponent = () => ComponentWithHook;
ReactDOM.render(<iframe src="iframe.html" />, document.getElementById('root'));
iframe.ts
import React, { FC } from 'react';
import ReactDOM from 'react-dom';
const Dummy: FC = () => {
const ComponentWithHook = (top as any).getComponent();
return <ComponentWithHook React={React} />;
};
ReactDOM.render(<Dummy />, document.getElementById('root'));

Context is not available right after page refresh in React

There's WarriorPage component which use context where is data I want to render. After page refresh, firstly I got an empty array from the context and only after a while I got array with my data. That causes error because I'm destructuring object from that array(which is empty in the start). Any sugestions?
WarriorPage
import React, { useContext } from 'react';
import { useParams } from 'react-router-dom';
import AllWarriorsContext from '../../contexts/AllWariorsContext';
export default function WarriorPage() {
let { identy } = useParams();
const { warriorsData } = useContext(AllWarriorsContext);
const {number, name, skill, description} = warriorsData[identy]; // got undefined here after page reload
return(...);
}
In Parent component
import React, { useEffect, useState, useContext } from 'react';
import AllWarriorsContext from '../../contexts/AllWariorsContext';
import WarriorPage from '../WarriorPage/WarriorPage';
export default function Parent() {
const [myWarriorsListContext, setMyWarriorsListContext] = useState([]);
useEffect( () => {
setMyWarriorsListContext(JSON.parse(localStorage.getItem('myWarriorsList')) || []);
},[]);
return(
<AllWarriorsContext.Provider value={{
warriorsData: allWarriorsData
}}>
<WarriorPage />
</AllWarriorsContext>
);
}

How to render an object of arrays with useEffect

I can't seem to get my object of arrays working. I want to pass an array from an api into a setstate function to turn that state into an array. Then iterate over that array. iterating should give me access to the object's properties. I want to access unique object properties to return and render them into my component. However, I get an error "Object Expected".
import React,{useState,useEffect} from 'react';
import './App.css';
import { CharacterComponent } from "../src/CharacterComponent"
import axios from "axios"
import ReactDOM from "react-dom";
export const Characters = () => {
// Try to think through what state you'll need for this app before starting. Then build out
// the state properties here.
// Fetch characters from the star wars api in an effect hook. Remember, anytime you have a
// side effect in a component, you want to think about which state and/or props it should
// sync up with, if any.
const [character,setCharacter] = useState({})
useEffect( () => {
axios.get("https://swapi.co/api/people")
.then(res => setCharacter(res.data.results) )
},[])
(console.log(character))
return (
<>
<div>
{character.map((element,index) => <CharacterComponent id={element} key={index} />)}
</div>
</>
)
}
That's weird, seems to be working fine in this sandbox: https://codesandbox.io/s/lingering-brook-veo3f
I initialized the state as an empty array as well:
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import axios from "axios";
import CharacterComponent from "./CharacterComponent";
import "./styles.css";
function App() {
const [character, setCharacter] = useState([]);
useEffect(() => {
axios
.get("https://swapi.co/api/people")
.then(res => setCharacter(res.data.results));
}, []);
return (
<div className="App">
{character.map(item => (
<CharacterComponent id={item} />
))}
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Maybe take a look to see if there's something wrong with your child component:
import React from "react";
const CharacterComponent = ({ id }) => {
return <div>{id.name}</div>;
};
export default CharacterComponent;

Resources