Clicking on link changes route but not Component itself - React Hook Router - javascript

I'm facing the ReactJS routing issue. Working Demo. I'm using the hookrouter package.
Issue:
As mentioned in the demo, if I'm on the /users route and when I click on about link, the URL changes but About Component is not getting loaded.
What I want?
Is there a way to load a Component when I click on its link?
import { A, useRoutes } from "hookrouter";
const Users = () => {
return (
<div>
<h1>Users</h1>
About
</div>
);
};
const About = () => {
return (
<div>
<h1>About</h1>
Users
</div>
);
};
const routes = {
"/users": () => <Users />,
"/about": () => <About />
};
function App() {
const routeResult = useRoutes(routes);
return (
<div className="App">
<div>
Users Page
</div>
<div>
About Page
</div>
{routeResult}
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<React.StrictMode><App /></React.StrictMode>, rootElement);

There is an open issue in hookrouter library where if you wrap your app with <React.StrictMode> the navigations doesn't work.
So, for now, remove the strict mode and you will be fine.
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
const rootElement = document.getElementById("root");
ReactDOM.render(
// <React.StrictMode> // <------ comment this for now.
<App />,
// </React.StrictMode>,
rootElement
);
working copy of your codesandbox

Related

How can I use React Context with react-router-dom?

AuthContext:
import { createContext } from "react";
export const AuthContext = createContext(null);
App.js:
const App = () => {
const isLogin = false;
if (isLogin) {
return (
<RouterProvider router={privateRoute} />
);
} else {
return (
<RouterProvider router={publicRoute} />
);
}
};
export default App;
I try to put <RouterProvider> in AuthContext like this:
<AuthContext.RouterProvider router={privateRoute} />
and like this:
<AuthContext>
<RouterProvider router={privateRoute} />
</AuthContext>
None of these options worked. What am I doing wrong?
One has nothing to do with the other. The issue is that AuthContext doesn't have any RouterProvider property nor is the code you are trying to use actually using a React context Provider component and value.
Just wrap the App component with the AuthContext.Provider component and ensure a context value is passed.
Example:
<AuthContext.Provider value={{ ..... }}>
<App />
</AuthContext.Provider>
you are trying to use the AuthContext with the RouterProvider but AuthContext have no property or component called RouterProvider.
To use AuthContext in combination with the RouterProvider, you will need to wrap the RouterProvider component in a component that consumes the AuthContext's value (i.e. useContext(AuthContext)).
Here a snippet to help you out...
In this we are using AuthContext value to detemine the value of routes and then use it with RouterProvider
const App = () => {
const auth = useContext(AuthContext);
const routes = auth.isLoggedIn ? privateRoute : publicRoute;
return (
<RouterProvider router={routes} />
);
};
export default App;
inside and you need to wrap the App component inside AuthContext like ...
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<AuthContext>
<App />
</AuthContext>
</React.StrictMode>
);

React Bootstrap Row issue

Ok, so. I am currently following this tutorial: https://www.freecodecamp.org/news/react-movie-app-tutorial/ . I have copied the code verbatim. I have installed bootstrap via the instructions on this website: https://react-bootstrap.github.io/getting-started/introduction#stylesheets . I have tried every configuration in every place of importing 'bootstrap/dist/css/bootstrap.min.css' including the <link>. The Row class is not working. Here is my Code...
import 'bootstrap/dist/css/bootstrap.min.css'
import './index.css'
import MovieList from "./components/MovieList"
const App = () => {
const [movies, setMovies] = useState([])
//const [favorite, setFavorite] = useState([])
//const [searchValue, setSearchValue] = useState("")
const getMovieRequest = (searchValue) => {
const url = `http://www.omdbapi.com/?s=jaws&apikey=76fd1ead`
fetch(url)
.then(resp => resp.json())
.then(data => {
if (data.Search) {
setMovies(data.Search)
}
})
}
useEffect(() => {
getMovieRequest()
}, [])
console.log(movies)
return (
<div className="container-fluid">
<div className="row">
<MovieList movies={movies} />
</div>
</div>
)
}
export default App;
import React from "react"
/*export default function MovieList(props) {
const displayMovies = props.movies.map(movie => {
return (
<div>
<img src={movie.Poster} alt="moive" />
</div>
)
})
return(
<>
{displayMovies}
</>
)
}*/
const MovieList = (props) => {
return (
<>
{props.movies.map((movie, index) => (
<div>
<img src={movie.Poster} alt="movie" ></img>
</div>
))}
</>
)
}
export default MovieList;
import React, {useState} from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import 'bootstrap/dist/css/bootstrap.min.css'
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
Any help would be greatly appreciated!
There is "bootstrap" itself and it is independent of what kind of framework you are using (React, Vue, Angular or just vanilla). It uses mostly css classes and jQuery for some functionality. Then there is "react-bootstrap", which is a complete re-write of bootstrap logic. It's written in React and offers a collection of components. That's why when you use react-bootstrap you only need the css part of bootstrap, but not the js/jQuery part.
Using only bootstrap?
npm i bootstrap
import 'bootstrap/dist/css/bootstrap.min.css' in your App.js or index.js
https://codesandbox.io/s/crazy-meninsky-9lmpmr?file=/src/App.js
Using react-bootstrap?
npm i react-bootstrap boostrap
import 'bootstrap/dist/css/bootstrap.min.css' in your App.js or index.js
https://codesandbox.io/s/serene-heisenberg-1xfvut
When you look into the both sandboxes you see that row is working either way.

ReactJs change text upon button click problem

I have a large project with multiple files. I want a button to render the content of some other components upon clicking. I am trying to understand why the following does not work, and what could I do to make it work instead?
Index.js
import React from "react";
import ReactDOM from "react-dom";
import { unitState, setUnitState } from './changeUnit.js'
function App() {
return (
<div>
<h1>{unitState}</h1>
<button onClick={setUnitState("°C")}>°C</button>
<button onClick={setUnitState("°F")}>°F</button>
</div>
);
}
// ------
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
changeUnit.js
export let unitState = "°C";
export function setUnitState(unit) {
(unit==="°C") ? unitState="°C" : unitState="°F";
}
with codesandbox link here
Currently, upon clicking any of the buttons the text does not change. But the code does reach inside the setUnitState method. I suspect that is because the main component is not rerendering. I tried to change my changeUnit.js code to
import App from './index.js';
export let unitState = "°C";
export function setUnitState(unit) {
(unit==="°C") ? unitState="°C" : unitState="°F";
App.forceUpdate();
}
but I get the error _index.default.update is not a method.
I have tried to use the useState hook from React but I just can't make it work for the life of me. I have tried many combinations but it seems that I can't return the setState function as a return from the custom hook.
Does anyone know how I can solve this problem?
I'm not sure why you're not using the useState hook, or what went wrong with your custom hook.
With useState():
function App() {
let [unitState, setUnitState] = React.useState('°C')
return (
<div>
<h1>{unitState}</h1>
<button onClick={() => setUnitState('°C')}>°C</button>
<button onClick={() => setUnitState('°F')}>°F</button>
</div>
);
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>
With custom hook:
function App() {
let { unitState, setCelsius, setFahrenheit } = useSwitch()
return (
<div>
<h1>{unitState}</h1>
<button onClick={setCelsius}>°C</button>
<button onClick={setFahrenheit}>°F</button>
</div>
);
}
function useSwitch() {
let [unitState, setUnitState] = React.useState('°C')
let setCelsius = () => setUnitState('°C')
let setFahrenheit = () => setUnitState('°F')
return { unitState, setCelsius, setFahrenheit }
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I'm guessing you probaly weren't using useState right. this is fairly simple with use state.
import React, { useEffect, useState } from "react";
import ReactDOM from "react-dom";
// import { unitState, setUnitState } from "./changeUnit.js";
function App() {
const [unitState, setUnitState] = useState("°C");
return (
<div>
<h1>{unitState}</h1>
<button onClick={() => setUnitState("°C")}>°C</button>
<button onClick={() => setUnitState("°F")}>°F</button>
</div>
);
}
// ------
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
I think you should just use setState, it might be the case that you were trying to call the setState without the lambda?
import React, { useState } from "react";
import ReactDOM from "react-dom";
function App() {
const [unitState, setUnitState] = useState("C");
return (
<div>
<h1>{unitState}</h1>
<button onClick={() => setUnitState("C")}>C</button>
<button onClick={() => setUnitState("F")}>F</button>
</div>
);
}
// ------
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
https://codesandbox.io/s/changeunitstate-forked-zbrym

Passing react-router-dom's Link into external library

I'm rendering components from my external (node_modules) pattern library. In my main App, I'm passing my Link instance from react-router-dom into my external libraries' component like so:
import { Link } from 'react-router-dom';
import { Heading } from 'my-external-library';
const articleWithLinkProps = {
url: `/article/${article.slug}`,
routerLink: Link,
};
<Heading withLinkProps={articleWithLinkProps} />
In my library, it's rendering the Link as so:
const RouterLink = withLinkProps.routerLink;
<RouterLink
to={withLinkProps.url}
>
{props.children}
</RouterLink>
The RouterLink seems to render correctly, and even navigates to the URL when clicked.
My issue is that the RouterLink seems to have detached from my App's react-router-dom instance. When I click Heading, it "hard" navigates, posting-back the page rather than routing there seamlessly as Link normally would.
I'm not sure what to try at this point to allow it to navigate seamlessly. Any help or advice would be appreciated, thank you in advance.
Edit: Showing how my Router is set up.
import React from 'react';
import { hydrate, unmountComponentAtNode } from 'react-dom';
import { AppContainer } from 'react-hot-loader';
import { Provider } from 'react-redux';
import { createBrowserHistory } from 'history';
import { ConnectedRouter } from 'react-router-redux';
import RedBox from 'redbox-react';
import { Route } from 'react-router-dom';
import { Frontload } from 'react-frontload';
import App from './containers/App';
import configureStore from './redux/store';
import withTracker from './withTracker';
// Get initial state from server-side rendering
const initialState = window.__INITIAL_STATE__;
const history = createBrowserHistory();
const store = configureStore(history, initialState);
const mountNode = document.getElementById('react-view');
const noServerRender = window.__noServerRender__;
if (process.env.NODE_ENV !== 'production') {
console.log(`[react-frontload] server rendering configured ${noServerRender ? 'off' : 'on'}`);
}
const renderApp = () =>
hydrate(
<AppContainer errorReporter={({ error }) => <RedBox error={error} />}>
<Provider store={store}>
<Frontload noServerRender={window.__noServerRender__}>
<ConnectedRouter onUpdate={() => window.scrollTo(0, 0)} history={history}>
<Route
component={withTracker(() => (
<App noServerRender={noServerRender} />
))}
/>
</ConnectedRouter>
</Frontload>
</Provider>
</AppContainer>,
mountNode,
);
// Enable hot reload by react-hot-loader
if (module.hot) {
const reRenderApp = () => {
try {
renderApp();
} catch (error) {
hydrate(<RedBox error={error} />, mountNode);
}
};
module.hot.accept('./containers/App', () => {
setImmediate(() => {
// Preventing the hot reloading error from react-router
unmountComponentAtNode(mountNode);
reRenderApp();
});
});
}
renderApp();
I've reconstructed your use case in codesandbox.io and the "transition" works fine. So maybe checking out my implementation might help you. However, I replaced the library import by a file import, so I don't know if that's the decisive factor of why it doesn't work without a whole page reload.
By the way, what do you mean exactly by "seamlessly"? Are there elements that stay on every page and should not be reloaded again when clicking on the link? This is like I implemented it in the sandbox where a static picture stays at the top on every page.
Check out the sandbox.
This is the example.js file
// This sandbox is realted to this post https://stackoverflow.com/q/59630138/965548
import React from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import { Heading } from "./my-external-library.js";
export default function App() {
return (
<div>
<img
alt="flower from shutterstock"
src="https://image.shutterstock.com/image-photo/pink-flowers-blossom-on-blue-600w-1439541782.jpg"
/>
<Router>
<Route exact={true} path="/" render={Welcome} />
<Route path="/article/coolArticle" component={CoolArticleComponent} />
</Router>
</div>
);
}
const Welcome = () => {
const articleWithLinkProps = {
url: `/article/coolArticle`,
routerLink: Link
};
return (
<div>
<h1>This is a super fancy homepage ;)</h1>
<Heading withLinkProps={articleWithLinkProps} />
</div>
);
};
const CoolArticleComponent = () => (
<div>
<p>This is a handcrafted article component.</p>
<Link to="/">Back</Link>
</div>
);
And this is the my-external-library.js file:
import React from "react";
export const Heading = ({ withLinkProps }) => {
const RouterLink = withLinkProps.routerLink;
return <RouterLink to={withLinkProps.url}>Superlink</RouterLink>;
};

React Native - Nothing was returned from render

My application is stored in /src/index.js but i also have a /App.js and a /index.js.
I don't know the difference between these and i think thats the reason im getting this error.
/index.js
import { AppRegistry } from 'react-native';
import App from './App';
AppRegistry.registerComponent('client', () => App);
/App.js
import App from './src/index';
export default App;
/src/index.js
import React from 'react';
import { AppRegistry } from 'react-native';
import { Provider, connect } from 'react-redux';
import { addNavigationHelpers } from 'react-navigation';
import Navigator from './routes/route';
import store from './store/configureStore';
const App = ({ dispatch, nav }) => {
<Navigator
navigation={addNavigationHelpers({
dispatch,
state: nav,
})}
/>
};
const mapStateToProps = state => ({
nav: state.nav,
});
const AppWithNavigation = connect(mapStateToProps)(App);
export default () => {
<Provider store={store}>
<AppWithNavigation />
</Provider>
}
I used create react native package to build this project and then tried to follow some guides to implement react navigation with redux.
Your default export is not returning anything :
export default () => {
<Provider store={store}>
<AppWithNavigation />
</Provider>
}
To return JSX with an arrow function you need to use () => ( <JSX /> ) or the equivalent with curly braces : () => { return ( <JSX /> ) } :
export default () => (
<Provider store={store}>
<AppWithNavigation />
</Provider>
)
or :
export default () => {
return (
<Provider store={store}>
<AppWithNavigation />
</Provider>
)
}
You forgot to return the components
const App = ({ dispatch, nav }) => {
return(
<Navigator
navigation={addNavigationHelpers({
dispatch,
state: nav,
})}
/>
)
};
export default () => {
return(
<Provider store={store}>
<AppWithNavigation />
</Provider>
)
}
I didn't mention this
import React from 'react';
and all other react-native components in my other files of screens.
Because I was calling my screen component from another file, from App.js file, so I also had to import react and react-native components in that file too.

Categories