Property 'history' does not exist on type 'IntrinsicAttributes & RouterProps' - react-router / react-router-dom to v6 - react-router

import { Router } from 'react-router-dom';
type AppShellProps = {
store: AppStore;
history: History;
federation?: FederationProps;
};
type FederatedShellProps = {
federation?: FederationProps;
children: React.ReactNode;
history: History;
};
const FederatedWrapper: FC<FederatedShellProps> = ({ federation, history, children }) => {
if (federation?.shellEnabled) {
const { providerPath, applicationName, environment } = federation.federatedProps;
return (
<Shell history={history} providerPath={providerPath} applicationName={applicationName} environment={environment}>
{children}
</Shell>
);
}
return <Fragment>{children}</Fragment>;
};
const AppShell: FC<AppShellProps> = ({ store, history, children, federation }) => {
return (
<ApolloProvider client={getGqlClient()}>
<FederatedWrapper history={history} federation={federation}>
<Provider store={store}>
<Router history={history}>{children}</Router>
</Provider>
</FederatedWrapper>
</ApolloProvider>
);
};
export default AppShell;
This line errors on history:
<Router history={history}>{children}</Router>
The error is: Type '{ children: ReactNode; history: History; }' is not assignable to type 'IntrinsicAttributes & RouterProps'.
Property 'history' does not exist on type 'IntrinsicAttributes & RouterProps'.
I just bumped up react-router and react-router-dom to v6 from v5.

Related

react-router 6 Navigate to using params

In v5 i have such structure
{
path: '/someurl/:id',
exact: true,
render: ({ params }) => (<Redirect to={`/someurl/extraurl/${params.id}`} />),
}
How to refactor this to V6?
react-router-dom v6 no longer has route props, so you'll need to create a new component to gather the "props", or match.params in this case, and render the redirect as a Navigate component.
const MyRedirect = () => {
const { id } = useParams();
return <Navigate to={`/someurl/extraurl/${id}`} replace />;
};
...
{
path: '/someurl/:id',
element: <MyRedirect />,
}
...
<Route path={obj.path} element={obj.element} />
The accepted answer will work but I'll add my solution too, since it's a bit more dynamic. You can set up a function component that will make use of the useParams hook and the generatePath function so your intended destination gets the params from the initial route (whatever they may be):
import React, { FunctionComponent } from 'react';
import { generatePath, Navigate, useParams } from 'react-router-dom';
interface IProps {
to: string;
replace?: boolean;
state?: any;
}
const Redirect: FunctionComponent<IProps> = ({ to, replace, state }) => {
const params = useParams();
const redirectWithParams = generatePath(to, params);
return (
<Navigate to={redirectWithParams} replace={replace} state={state} />
);
};
export default Redirect;
Using this should work with your first example (and any other routes / redirects with dynamic params).

Extracting data from json object from API with JavaScript React Native

I have this json object which I have taken from the news API and want to print out the author of just one of the articles. I wanted to know how to do it within a react component which I have called 'author'.
Here is the json object: it's too long to include here but have the link for you to see.
It's accessible from https://newsapi.org/ and has a total of 20 articles.
I have this react component which I am trying to then print one of the article's authors:
import React, { Component } from 'react';
const APIurl = 'https://newsapi.org/v2/top-headlines?
country=it&apiKey=0b3e87958d0b4e71a9e2ed3eea69237a';
class Author extends Component {
constructor(props) {
super(props);
this.state = {};
}
componentDidMount() {
fetch(APIurl)
.then(response => response.json())
.then(response => {
this.setState({
articles: response
})
})
}
render() {
return (
<h5 class="f6 ttu tracked black-80">
{this.state.articles.article[0].author}
</h5>
);
}
}
export default Author;
However, something must not be quite right because I get this error:
TypeError: Cannot read property 'articles' of undefined
21 | render() {
22 | return (
23 | <h5 class="f6 ttu tracked black-80">
> 24 | {this.state.articles.articles[0].author}
25 | </h5>
26 | );
27 | }
I'm not sure what I have done wrong. Also sorry for the poor formating of the json object.
I've now made some changes after seeing what has been suggested below so that my code looks like this:
import React, { Component } from 'react';
const APIurl = 'https://newsapi.org/v2/top-headlines? country=it&apiKey=0b3e87958d0b4e71a9e2ed3eea69237a';
class Author extends Component {
constructor(props) {
super(props);
this.state = {
articles: []
};
}
componentDidMount() {
fetch(APIurl)
.then(response => response.json())
.then(response => {
this.setState({
articles: response
})
})
}
render() {
const { articles } = this.state;
return (
<h5 class="f6 ttu tracked black-80">
{articles.length>0 && articles.articles[1].author}
</h5>
);
}
}
export default Author;
However, it still doesn't print out anything in the author react component even though when I go to the chrome developer tools and see the state of the component it looks like this:
State
articles: {…}
articles: Array[20]
0: {…}
1: {…}
author: "Davide Stoppini"
description: "A Pisa, divertente pareggio con i russi, più avanti per quanto riguarda la condizione fisica. Passi in avanti rispetto al Sion: bene gli esterni offensivi, anche i due attaccanti confermano la confide…"
publishedAt: "2018-07-21T20:20:21Z"
source: {…}
title: "Inter, fuochi d'artificio con lo Zenit: è 3-3. In gol Icardi e Lautaro"
url: "https://www.gazzetta.it/Calcio/Serie-A/Inter/21-07-2018/inter-fuochi-d-artificio-lo-zenit-3-3-gol-icardi-lautaro-280799153444.shtml"
urlToImage:"https://images2.gazzettaobjects.it/methode_image/2018/07/21/Calcio/Foto%20Calcio%20-%20Trattate/1d50f03c94d965c2ca84bd3eec0137c9_169_xl.jpg
*Note: this is only showing the first second element of the articles array.
Basically, you have to declare articles as empty array initially as follows:
this.state = {
articles: []
};
And also need to modify your code inside render as follows:
{this.state.articles && (this.state.articles.article.length>0) &&
this.state.articles.article[0].author
}
Hope it will help you.
The problem you are having is because your code is not prepared to go through the lifecycle of React. Before you get the data in the componentDidMount phase there is a render phase, that is where the error is happening. In that render phase articles should be an empty array without data and then you need a check to avoid rendering any stuff if the array is empty. So to avoid to have that error in the render phase before the componentDidMount phase you need to set in state an empty array called articles, and in the render method to check if it is not empty, to render the value you want.
import React, { Component } from 'react';
const APIurl = 'https://newsapi.org/v2/top-headlines?
country=it&apiKey=0b3e87958d0b4e71a9e2ed3eea69237a';
class Author extends Component {
constructor(props) {
super(props);
this.state = { articles: []};
}
componentDidMount() {
fetch(APIurl)
.then(response => response.json())
.then(response => {
this.setState({
articles: response.articles
})
})
}
render() {
const { articles } = this.state;
return (
<h5 class="f6 ttu tracked black-80">
{articles.length > 0 && articles[0].author}
</h5>
);
}
}
export default Author;
News App in React Native:
const SITE_URL =
"https://newsapi.org/v2/top-headlines?country=us&category=business&apiKey=a39bbc7131c649a3ad23fe79063d996f";
const TestScreen = () => {
const [myData, setMyData] = useState();
useEffect(() => {
axios
.get(SITE_URL)
.then((res) => {
// console.log("Response from main API: ", res);
console.log(
"----------------------------------------------------------- Start"
);
// console.log("Response from Home Data Data: ", res.data.data);
console.log(
"Response from NEWS data articles: ",
res.data.articles
);
console.log(
"----------------------------------------------------------- End"
);
// let companyData = res.data.data;
let companyData = res.data.articles;
setMyData(companyData);
setData({
Company: companyData,
Description: "",
});
})
.catch((err) => {
console.log(err);
});
}, []);
// console.log("myData:", { myData });
const renderItem = ({ item, index }) => (
<TouchableOpacity style={styles.container}>
<Text style={styles.title}>
{index}. {item.author}
</Text>
<Text> {item.description} </Text>
<View>
<Image
style={{
width: 500,
height: 100,
}}
source={{
uri: item.urlToImage,
}}
/>
</View>
</TouchableOpacity>
);
return (
<View style={styles.container}>
<Text>Read Later Screen</Text>
<Text>|</Text>
{<FlatList data={myData} renderItem={renderItem} />}
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});
export default TestScreen;

TypeError: element.type.toLowerCase is not a function

I am facing an issue while setting up SSR for a react app.The Server side code for the render is as below:
app.use((req, res) => {
const context = {}
const body = ReactDOMServer.renderToString(
React.createElement(
Provider, { store },
React.createElement(
StaticRouter, { location: req.url, context: context },
React.createElement(Layout, null, React.createElement(Routes))
)
)
)
if (context.url) {
res.redirect(context.url)
} else {
res.status(200).send(template({ body }))
}
})
The route config is as below:
Routes.js
const Routes = () => {
return (
<Switch>
<Route path="/" exact component={Home}/>
<Route path="*" component={NotFound}/>
</Switch>
)
}
export default Routes
App.js
const App = () => {
return (
<Provider store={store}>
<BrowserRouter>
<Layout>
{router}
</Layout>
</BrowserRouter>
</Provider>
);
}
export default App
It throwing the below error:
Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: object.
TypeError: element.type.toLowerCase is not a function
at ReactDOMServerRenderer.renderDOM (../node_modules/react-dom/cjs/react-dom-server.node.development.js:2304:28)
at ReactDOMServerRenderer.render (../node_modules/react-dom/cjs/react-dom-server.node.development.js:2298:21)
at ReactDOMServerRenderer.read (../node_modules/react-dom/cjs/react-dom-server.node.development.js:2234:19)
at Object.renderToString (../node_modules/react-dom/cjs/react-dom-server.node.development.js:2501:25)
at app.use (../server.js:59:33)
When i tried printing console.log(React.createElement(Routes)); it shows as below:
{ '$$typeof': Symbol(react.element),
type: [Function: Routes],
key: null,
ref: null,
props: {},
_owner: null,
_store: {} }
I have created the CompiledRoutes file from the Routes file using babel and I am importing it into server.js as below:
const Routes = require('./client/CRoutes').default
Can someone pls guide me what could be the issue here?Thanks in advance.
Try changing
React.createElement(Layout, null, React.createElement(Routes))
to
React.createElement(Layout, null, React.createElement(Routes.default))
You might be using require on the server-side, instead of import, which results in some discrepancies.

GraphQL with React Router Relay: Expected type Int, found String for numeric route

I have the following Router and routes using the react-router-relay package
ReactDOM.render(
<Router
history={browserHistory}
render={applyRouterMiddleware(useRelay)}
environment={Relay.Store}
>
<Route
path="/user/:userId"
component={User}
queries={StoreQueries}
/>
</Router>,
document.getElementById('root')
);
My StoreType from GraphQL looks like the following, with the user field accepting an id argument representing a non-null integer:
let StoreType = new GraphQLObjectType({
name: 'Store',
fields: () => ({
user: {
type: UserType,
args: {
id: {
type: new GraphQLNonNull(GraphQLInt)
}
},
resolve: (root, args) => db.user.findById(args.id)
},
})
})
My Relay container for the user/:userId route:
import React from 'react';
import Relay from 'react-relay'
class User extends React.Component {
render () {
return <div>
User goes here!
</div>;
}
}
User = Relay.createContainer(User, {
initialVariables: {
userId: null,
},
fragments: {
store: () => Relay.QL`
fragment on Store {
user(id: $userId) {
name
}
}
`
}
});
export default User;
When I visit /user/1 in the browser, react-router-relay treats :userId as a string from the route instead of an integer, and GraphQL returns the JSON-encoded error message "Argument \"id\" has invalid value \"1\".\nExpected type \"Int\", found \"1\"."
Is there any way to cast the userId argument passed in the URL to an integer? Or is there a custom GraphQL scalar type that supports well-formed numeric strings as well as integers? Any input or direction on this is appreciated.
I faced with the same problem recently and ended up with this solution:
<Route
path="/user/:userId"
component={User}
queries={StoreQueries}
prepareParams={({userId}) => ({userId: parseInt(userId, 10)})}/>
/>

Routing is not work with react-router-redux actions

When use the Link, router works as expected, though i get a warning [history] pushState is deprecated; use push instead.
Using routeActions from react-router-redux does't work, url was change (http://localhost:3002/addCity), but view still the same (Home) or show error if i go to page by url for example: localhost:3002/addCity.
git: https://github.com/kirsanv43/Weather.git
reducers:
export default combineReducers({
cities,
routing: routeReducer
});
store config: https://github.com/kirsanv43/Weather/blob/master/app/redux/config/store.js
import rootReducer from '../reducers'
export default function configureStore(initialState) {
const history = createHistory();
const middleware = syncHistory(history)
const finalCreateStore = compose(
applyMiddleware(middleware)
)(createStore)
const store = finalCreateStore(rootReducer)
middleware.listenForReplays(store);
if (module.hot) {
// Enable Webpack hot module replacement for reducers
module.hot.accept('../reducers', () => {
const nextRootReducer = require('../reducers').default
store.replaceReducer(nextRootReducer)
})
}
return store
}
Router:
const store = configureStore()
ReactDOM.render(
<Provider store={store}>
<Router history={browserHistory}>
<Route path="/" component={App}>
<IndexRoute component={Home}/>
<Route path="addCity" component={AddCity}/>
</Route>
</Router>
</Provider>
,
document.getElementById('root')
);
Component:
class CitiesList extends React.Component {
onAddCity = () => {
this.props.route.push('/addCity')
};
render() {
return <div className="weatherContainer">
<ul>
<li className="listItem addBtn"><a onClick={this.onAddCity}><span>ADD CITY</span></a></li>
</ul>
</div>
}
}
function mapDispatchToProps(dispatch) {
return {
route:bindActionCreators(routeActions, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(CitiesList)
insted createHistory need use createHashHistory from 'history'
that working for me
Please try to change "react-router-redux" version to "^5.0.0-alpha.8". It solved my problem