Error in Firebase cloud messaging in React PWA - reactjs

I am trying to add FCM into my Reactjs PWA, but I am unable to resolve the below error
This a very basic app that fetches some data from firebase and shows it on screen.
firebase-messaging-sw.js:
importScripts('https://www.gstatic.com/firebasejs/4.8.1/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/4.8.1/firebase-messaging.js')
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register(`../firebase-messaging-sw.js`)
.then(function(registration) {
console.log('Registration successful, scope is:', registration.scope);
}).catch(function(err) {
console.log('Service worker registration failed, error:', err);
});
}
firebase.initializeApp({
messagingSenderId: SENDER_ID,
})
const initMessaging = firebase.messaging()
App.js:
import React from 'react';
import './App.css';
import Routing from './Components/Routing';
import { BrowserRouter } from 'react-router-dom';
import fire from './config/fire';
function App() {
React.useEffect(() => {
const msg=fire.messaging();
msg.requestPermission().then(()=>{
return msg.getToken();
}).then((data)=>{
console.warn("token",data)
})
})
return (
<BrowserRouter basename={process.env.PUBLIC_URL}>
<div className="App">
<Routing />
</div>
</BrowserRouter>
);
}
export default App;
I have a guess that this is happening because it cannot find any file on the link http://localhost:3000/firebase-messaging-sw.js therefore by default of react-router it is returning the index.html file.

Related

TypeError: Cannot read property 'useContext' of null nextjs

I am going to get user from context and use it in header in nextjs strapi apollo graphql project User is accessable in App function but outside its giving above error. Is context values accessable outside function if yes how can I access it if no how to structure it so that I can use it in request header.
import "../styles/globals.css";
import Layout from "../components/Layout";
import { Provider } from "../context/AppContext";
import Cookies from "js-cookie";
import withApollo from "next-with-apollo";
import { BACKEND_URL } from "../helpers";
import React, { useContext } from "react";
import { AppContext } from "../context/AppContext";
import { ApolloClient, ApolloProvider, InMemoryCache } from "#apollo/client";
const { user } = useContext(AppContext);
console.log("user from context in _app", user);
function App({ Component, pageProps, apollo }) {
return (
<Provider>
<ApolloProvider client={apollo}>
<Layout>
<Component {...pageProps} />
</Layout>
</ApolloProvider>
</Provider>
);
}
export default withApollo(({ initialState, headers }) => {
return new ApolloClient({
uri: `${BACKEND_URL}/graphql`,
cache: new InMemoryCache().restore(initialState || {}),
...(user && {
headers: {
authorization: `Bearer ${user.token}`,
},
}),
});
})(App);
On my machine, Next.js didn't work if, in Windows Terminal, the disk letter (for example, C:) of the "current directory" was written in lowercase (as c: in this example).
After I changed the current directory from c:\dev\project to C:\dev\project, the error went away.
Source: https://github.com/vercel/next.js/issues/7626#issuecomment-541430221

How can I prevent metamask from popping up?

I followed a tutorial on youtube on how to create a button to connect metamask with my Dapp, I got a problem is when I've launched the Dapp metamask pop up even before I click on the button to connect to it, I've tried to remove the web3.js code from the app.js because I know is that "web3 = new Web3(window.ethereum);" who makes metamask to popup but I got another problem in my App.js.
Index.js code
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { Web3ReactProvider } from '#web3-react/core';
import Web3 from "web3";
// get and inject web3 provider
const getLibrary = (provider) => {
return new Web3(provider)
};
ReactDOM.render(
<React.StrictMode>
<Web3ReactProvider getLibrary={getLibrary}>
<App />
</Web3ReactProvider>
</React.StrictMode>,
document.getElementById('root')
);
App.js code
import web3 from './web3';
import { useWeb3React } from "#web3-react/core";
import { injected } from "./components/Wallet/connector";
const { active, account, library, connector, activate, deactivate } = useWeb3React();
// Connect to metamask
const Connect = async () => {
try {
await activate(injected);
} catch(err) {
console.log(err)
}
}
const winnerHandler = async () => {
// get the accounts
const account = await web3.eth.getAccounts();
// Call the pickWinner function from the contract
await lottery.methods.pickWinner().send({
from: account[0]
});
}
<main>
<Navbar>
<Left>
<Logo>LTR</Logo>
</Left>
<Right>
{active ? <Button widthBtn hightBtn >{account.substring(0,13)}...</Button> :
<Button widthBtn hightBtn onClick={Connect}>Connect MetaMask</Button>}
</Right>
</Navbar>
</main>
web3.js code
import Web3 from "web3";
let web3;
if (window.ethereum && window.ethereum.isMetaMask) {
console.log('MetaMask Here!');
web3 = new Web3(window.ethereum);
window.ethereum.request({ method: 'eth_requestAccounts'})
} else {
console.log('Need to install MetaMask');
window.Error('Please install MetaMask browser extension to interact');
}
export default web3;
I just met this problem today. You need to change the function in the onClick on the app.js
From:
<Button widthBtn hightBtn onClick={Connect}>Connect MetaMask</Button>}
To:
<Button widthBtn hightBtn onClick={()=>Connect}>Connect MetaMask</Button>}

React SSR - React Router Dom staticContext undefined on the client

I am creating a blogging application using React with Server Side Rendering functionality. I create the application using Create React App.
I encounter an issue where my data coming from the server is rendered for a second then gone after react takes over the rendering process. I am using React Router Dom to pass the data from the server to the client react. Basically I am following this tutorial to create the application https://www.youtube.com/watch?v=NwyQONeqRXA but the video is lacking some information like getting the data on the API. So I reference this repository for getting the data on the API https://github.com/tylermcginnis/rrssr
Base on resources I gathered I ended up the following codes.
server.js
import express from "express";
import fs from "fs";
import path from "path";
import { StaticRouter, matchPath } from "react-router-dom";
import React from "react";
import ReactDOMServer from "react-dom/server";
import serialize from "serialize-javascript";
import App from "../src/App";
import routes from "../src/routes";
const app = express();
const PORT = 3001;
app.use(express.static(path.resolve(__dirname, "..", "build")));
app.get("*", (req, res, next) => {
// point to the html file created by CRA's build tool
const filePath = path.resolve(__dirname, "..", "build", "index.html");
fs.readFile(
path.resolve(filePath),
"utf-8",
(err, html_data) => {
if (err) {
console.error(err);
return res.status(500).send(`Some error happened: ${err}`);
}
const activeRoute =
routes.find(route => matchPath(req.url, route)) || {};
const promise = activeRoute.fetchInitialData
? activeRoute.fetchInitialData(req.path)
: Promise.resolve();
promise
.then(rawData => {
console.log('rawData', rawData[0]);
const context = { posts: rawData };
const markup = ReactDOMServer.renderToString(
<StaticRouter location={req.url} context={context}>
<App />
</StaticRouter>
);
return res
.status(200)
.send(
html_data
.replace(
'<div id="root" class="container-fluid"></div>',
`<div id="root" class="container-fluid">${markup}</div>`
)
.replace(
"__INITIAL_DATA__={}",
`__INITIAL_DATA__=${serialize(rawData)}`
)
);
})
.catch(next);
}
);
});
app.listen(PORT, () => {
console.log(`App launched at http://localhost:${PORT}`);
});
Node JS Server entry point index.js
require("ignore-styles");
require("#babel/register")({
ignore: [/(node_modules)/],
presets: ["#babel/preset-env", "#babel/preset-react"]
});
require("./server");
Client react index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { BrowserRouter } from "react-router-dom";
import "bootstrap/dist/css/bootstrap.css";
import "./index.css";
import "./fonts/VarelaRound-Regular.ttf";
ReactDOM.hydrate(
<BrowserRouter>
<App post_data={window.__INITIAL_DATA__} />
</BrowserRouter>,
document.getElementById("root")
);
Clieant react App.js
import React, { Component } from "react";
import "./App.css";
import { Route, Link, Redirect, Switch } from "react-router-dom";
import routes from "./routes";
class App extends Component {
render() {
return (
<div>
<Switch>
{routes.map(
({ path, exact, component: Component, ...rest }) => (
<Route
key={path}
path={path}
exact={exact}
render={props => (
<Component {...props} {...rest} />
)}
/>
)
)}
</Switch>
</div>
);
}
}
export default App;
When I am trying to output the data on the component it was gone and now staticContext pass from the server is undefined. What seems to be the issue here? Am I missing some configuration or library?
import React from "react";
export default class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
posts: this.props.staticContext
? this.props.staticContext.posts
: []
};
console.log("constructor", this.props); // STATIC CONTEXT UNDEFINED ON THIS OUTPUT
}
componentDidMount() {
console.log("componentDidMount", this.props);// STATIC CONTEXT UNDEFINED ON THIS OUTPUT
}
}

React server side rendering page source is not updating

I'm working with server side rendering for my React Js App.showing page content and routes are working fine.but when i hit 'page source',it's not showing all content inside html.also when i navigate to another page and hit 'page source',it's not updated old html.
Any idea about this issue?
server.js
import 'babel-polyfill';
import express from 'express';
import { matchRoutes } from 'react-router-config';
import Routes from './client/Routes';
import renderer from './helpers/renderer';
import createStore from './helpers/createStore';
const app = express();
app.use(express.static('public'));
app.get('*', (req, res) => {
const store = createStore(req);
const promises = matchRoutes(Routes, req.path)
.map(({ route }) => {
return route.loadData ? route.loadData(store) : null;
})
.map(promise => {
if (promise) {
return new Promise((resolve, reject) => {
promise.then(resolve).catch(resolve);
});
}
});
Promise.all(promises).then(() => {
const context = {};
const content = renderer(req, store, context);
res.send(content);
});
});
app.listen(3000, () => {
console.log('Listening on prot 3000');
});
renderer.js
import React from 'react';
import { renderToString } from 'react-dom/server';
import { StaticRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import { renderRoutes } from 'react-router-config';
import serialize from 'serialize-javascript';
import { Helmet } from 'react-helmet';
import Routes from '../client/Routes';
export default (req, store, context) => {
const content = renderToString(
<Provider store={store}>
<StaticRouter location={req.path} context={context}>
<div>{renderRoutes(Routes)}</div>
</StaticRouter>
</Provider>
);
const helmet = Helmet.renderStatic();
return `<!doctype html>
<html lang="en">
<head>
${helmet.title.toString()}
${helmet.meta.toString()}
</head>
<body>
<div id="root">${content.toString()}</div>
<script>
window.INITIAL_STATE = ${serialize(store.getState())}
</script>
<script src="bundle.js"></script>
</body>
</html>
`;
};
App.js
import React from 'react';
import { renderRoutes } from 'react-router-config';
import { fetchHomeSliders } from './actions/home';
const App = ({ route }) => {
return (
<div>
{renderRoutes(route.routes)}
</div>
);
};
export default {
component: App,
loadData: ({ dispatch }) => dispatch(fetchHomeSliders())
};
Routes.js
import React from 'react';
import App from './App';
import HomePage from './components/home';
import About from './components/about';
export default [
{
...App,
routes: [
{
...HomePage,
path: '/',
exact: true
}
,
{
...About,
path: '/about-us'
}
]
}
];
fetchHomeSliders API
export const fetchHomeSliders = () => async (dispatch, getState, api) => {
const request = await api.get(`https://example.com/api/contents/ABOUT`);
dispatch ({type: FETCH_HOME_SLIDERS, payload: request});
console.log("request request",request)
};
The reason why it might be happening is that on doing view page source only the server rendered page is shown in SSR website.
So anything you do on the client like add an html element or listener will be seen only it the inspect element.The inspect
element is kind of dynamic meaning that it updates itself to server as well as client side changes.So whenever you are doing anything like
show/hide a div/button, it will be shown in the inspect element. Whereas when you try to View page souce what happens is it hits the server and
whatever HTML content the server returned it will show.
As an example you can check https://preactjs.com/. If you do View page souce in it the html content is very less and won't contain
majority of elements compared to inspect element.So here only a part of the html is sent by Server and majority of things happen on
client side.
For your case I think you need to hydrate elements rendered by server.It will ensure that the content is the same on
the server and the client and won't override it.
Something like
import React from 'react'
import {hydrate} from 'react-dom'
import {Provider} from 'react-redux'
import configureStore from './redux/configureStore'
import App from './components/app'
const state = window.__STATE__;
delete window.__STATE__;
const store = configureStore(state)
//Here we are hydrating.
hydrate(
<Provider store={store} >
<App />
</Provider>,
document.querySelector('#app')
)
Also you can check in network request if server is returning content.toString()
Hope that helps.

Add Server Side Rendering to create-react-app

i am studying create-react-app and SSR.
I have add redux and react-router in this repo => https://github.com/sarovin/StarteKit.
Now i want add SSR ( server side rendering ) without any modification to create-react-app.
I have a PR where i try to implement it => https://github.com/sarovin/StarteKit/pull/1
But i have some error because the function onClick() not work in my example:
// App.js
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { switcher } from './actions/switcher';
import logo from './logo.svg';
import './App.css';
const propTypes = {
switch: PropTypes.bool,
dispatch: PropTypes.func,
};
class App extends Component {
constructor(props) {
super(props);
this.onClick = this.onClick.bind(this);
}
onClick() {
console.log('onClick');
this.props.dispatch(switcher());
}
render() {
console.log('Switch', this.props.switch);
return (
<div className="App">
<div className="App-header">
{this.props.switch ? <img src={logo} className="App-logo" alt="logo" /> : null }
<h2>Welcome to React</h2>
</div>
<label className="switch" >
<input checked={this.props.switch} type="checkbox" onChange={this.onClick} />
<div className="slider round"></div>
</label>
</div>
);
}
}
function mapStateToProps(state) {
return {
switch: state.switcher.get('switch'),
};
}
App.propTypes = propTypes;
export default connect(mapStateToProps)(App);
//server.js
import express from 'express';
import path from 'path';
import bodyParser from 'body-parser';
import hbs from 'express-hbs';
import cors from 'cors';
import React from 'react';
import { createStore, combineReducers } from 'redux';
import { Provider } from 'react-redux';
import { renderToStaticMarkup } from 'react-dom/server';
import { RouterContext, match } from 'react-router';
import routes from './routes';
import * as reducers from './reducers';
console.log('info', 'Init App');
const app = express();
app.set("port", process.env.PORT || 8080);
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
// Make index false, so that it is not resolved by default.
app.use(express.static(path.resolve('build'), {index: false}));
app.set("views", path.resolve('build'));
app.set("view engine", "html");
app.engine("html", hbs.express4());
app.use((req, res, next) => {
match({routes: routes, location: req.url}, (err, redirectLocation, renderProps) => {
if (err) {
return res.status(500).send(err.message);
} else if (redirectLocation) {
res.redirect(302, redirectLocation.pathname + redirectLocation.search);
} else if(renderProps){
res.status(200);
console.log(renderProps);
const reducer = combineReducers(reducers);
const initialState = {};
let store = createStore(reducer, initialState);
let html = renderToStaticMarkup(
<Provider store={store}>
<RouterContext {...renderProps}/>
</Provider>
);
console.log('store', store.getState());
res.render('index.html', { content: html });
}
else res.status(404).send('Page not found');
});
});
app.listen(app.get("port"), () => {
console.log("Express server starting on port: " + app.get("port"));
});
Have any suggestion?
If you need server side rendering, I would suggest Next.js instead of create-react-app:
https://github.com/zeit/next.js/
I'll strongly recommend razzle for your project. it abstracts all the required tooling for your universal JavaScript application into a single dependency which is a great gain doing SSR.
I've been thinking about the same thing. I ended up with a project https://github.com/haukurk/cra-ssr-ts-recipe. It's an isomorphic web app that allows you to do server rendering for React (with support for React Router and Redux). You simply add fetchData function to your route component if you want to do any pre-fetching of data.
SSR is not something that is trivial nor built into React/CRA and will always include some extra work for your web app.
I've also been looking into NextJS, as people seem to be praising it a lot. I encourage you to look at that.
Please try
https://github.com/antonybudianto/cra-universal
No need to eject and it's zero config by default (v3.0.x)

Resources