How to send long list of parameters in URL - reactjs

I have the below link in one of the components of my project
<Link to={`http://localhost:8080/project/path/items?ids=18,19`}>
{itemCount}
</Link>
It redirects to another component. That component picks up the ids list from url and displays the result
Now my problem is when the ids list gets large enough (tens of thousands) it doesn't work.
I need a better approach of handling this
Is it possible through a post request?

I assume you are using Link from react-router?
The to props in Link isn't limited to string values. You can pass a state as well like this:
<Link
key={i.id}
to={{
pathname: `/someUrl`,
state: { someValue: 'asdad', someArray: [1, 2, 3] }
}}
>
Then at the destination route, you can access the state from this.props.location.state. This value only exist for that particular browser history push. If you type the url directly to the browser, this.props.location.state.someValue will be undefined.

I think it would be easier to handle if you save your id's in local state for the component that's supposed to link to the other component.
this.state = {
ids = [];
}
I'm not sure how you get your id's, normally you get them from props or an API. But just to make an example on how to add ids to your state:
componentDidMount() {
this.setState({
ids: [18, 19, 20, 21]
})
}
This way you'll have them all in one place, and you can send them to the other component through props.
<MyComponent ids={this.state.ids.toString().split(',').join()} />
To create your new component (don't know how experienced you are):
export default class MyComponent extends React.Component {
constructor(props) {
super(props)
}
render() {
let itemCount = {this.props.ids.length}
return(
<Link to={`http://localhost:8080/project/path/items?ids={this.props.ids}`}>
{itemCount}
</Link>
)
}
}
It's important though to know that every element that's supposed to be shown on screen, needs to be kept in the client devices memory.
Therefor it'll be challenging rendering thousands of element without noticing performance issues. You should prepare yourself for showing a batch of all the id's if you're noticing that the app is getting slow or takes a long time to load.
Two common ways of "batching" a long list is either pagination or lazy-loading.

Related

ReactJS: How to render a collection of objects

So I'm quite new on web development last couple of days. I come from c++ background and I can't wrap my head through all the principles of reactjs. I have 2 classes. The child class called JobAd should render some information that it got from props.
export default class JobAd extends Component {
constructor(props) {
super(props);
this.state ={
index: props.index,
id: props.jobId,
name: props.name,
description: props.description,
location: props.location,
adress: props.adress,
alreadyApplied: props.alreadyApplied,
open: false,
// toggleJob: props.toggleJob,
};
this.toggleJob = props.toggleJob;
}
render() {
return (
<div className={`${styles.jobAd} d-flex` + "job " + (this.state.open ? 'open': '')} key={this.state.index} onClick={() => this.toggleJob(this.state.index)}>
<div className={`${styles.jobTitle}`}>
{this.state.location} - {this.state.name}
</div>
<div className={`${styles.jobDetails}`}>
<div className={`${styles.jobDescription}`}> {this.state.description}</div>
<div className={`${styles.jobAdress}`}>{this.state.adress}</div>
<ApplyButton jobId= {this.props.id} alreadyApplied = {this.props.alreadyApplied}/>
</div>
</div>
)
}
}
The second class, queries a mongoDB db and creates jobAd objects populating them from the info gotten from db.
class JobExplorer extends React.Component
{
...
result.data.jobs.forEach(job => {
var find = job.employees.find(obj => obj === userId);
if (!(find === undefined)) {
alreadyApplied = true;
}
var toPush = new JobAd ({
index: i,
id:job._id,
description:job.description,
name:job.name,
location:job.locationName,
adress:job.locationAdress,
alreadyApplied:alreadyApplied,
open:false,
toggleJob: this.toggleJob.bind(this)
});
jobList2.push(toPush);
console.log("look");
console.log(jobList2)
});
this.setState({
jobList: jobList2
})
this.setState({
error: null,
jobs: result.data.jobs
});
...
render()
{
console.log("look2");
console.log(this.state.jobList);
return (
<div><Navigation />
{this.state.jobList}
</div>
);
}
But I am faced with the following error which I cannot find a fix for.
Error: Objects are not valid as a React child (found: object with keys {props, context, refs, updater, state, toggleJob}). If you meant to render a collection of children, use an array instead.
How should I instantiate those objects so I could render them using the "architecture" I wrote. Is there a fundamental flaw that I have in my classes?
The below snippet doesn't work because new will return an object (this) not the react component.
So, instead of
var toPush = new JobAd({
index: i,
id: job._id,
...
});
jobList2.push(toPush);
you can do this
var toPush = <JobAd
index={i}
id={job._id}
...
/>;
The above snippet works because <JobAd ... /> is converted to React.createElement(JobAd, ... ). However, you still shouldn't do it like this. since there are a lot of better ways to do this. one of them is:
save just the data in joblist and then render the data list on JobAd component
like below:-
render(){
return this.state.joblist.map((job, i) => (
<JobAd
key={job._id}
index={i}
...
/>
));
}
The key is a really important thing. Read about it: https://reactjs.org/docs/lists-and-keys.html
Things that could be improved:-
Don't copy props in the state as you are doing in JobAd class instead directly render the props.
Don't call setState twice as in JobExplorer. you could set all the keys in
setState at the same time. since that would render the component twice.
Suggestions:-
You should avoid using var as that might cause some issues here.
since, you are just a starter, try using functional component first. they are
quite easier to grasp
You seem to have a misconception about state/props in React and web development. It's very normal; I learned python and Java first and many tutorials seem to assume that people just know this already.
"State" in generally refers to variables containing/referring to values that can change without a page refresh in your application. If you know a value is not going to change, it does not need to be held in state. Storing it in a normal variable is exactly what you should do.
"Props" is just another word for arguments that are passed to React components. There's more to it in reality, but as a beginner, that's all you need to really know for now.
So in your job add, things like name, address, jobs, description shouldn't go in state because they aren't going to change as a result of user interaction or for any other reason, unless the underlying data they are loaded from changes, but then that wouldn't be handled by React but instead by the API that your app gets data from. They should just be rendered, so refer to them like this.props.address in your render method. The value for open, however, need to be in state, because that definitely can change.
As for the error, it looks like you are not calling JobAd correctly. You need to use the syntax <Job Ad/> rather than new JobAd...that won't work in React.
I would recommend doing a tutorial to get the basics down.

passing mapped data from an api to another component

so i have data that i get from an api in componentDidMount, and then i map over it in the render. lets say the map returns 4 objects. How do i create a button click event that captures that specific objects data, and passes it along a route to another component?
code:
clickEvent(){
???
}
this.example = this.state.data.slice(1).map((data, key) =>
<div key={item.Id}>
<div>{data.dataIWantToPass}</div>
<Link to='/next_component_path' onClick={clickEvent}}>Click</Link>
</div>
So lets say the above returns 4 objects. I want the third one, when the link is clicked to pass its data.
clickEvent(dataUWantToPass){
<NewComponent dataPassed={dataUWantToPass} />
}
this.example = this.state.data.slice(1).map((data, key) =>
<div key={data.Id}>
<div>{data.dataIWantToPass}</div>
//Link is a react-router-dom component, this helps you to redirect to other component (to which you have added the route for
<Link to='/next_component_path'>
<button onClick={()=>this.clickEvent(data.dataIWantToPass)} value="Click"/>
</Link>
</div>
))
You can receive the data in the NewComponent as props.
If you want to check than you can write the componentWillReceiveProps() method in the NewComponent as:
componentWillReceiveProps(reveivedProps){
console.log(reveivedProps);
}
Ok, I have solved this by piecing together various bits from comments, so thank you for your contributions. This is how it was resolved:
On the link tag i did this:
<Link to={{ pathname: '/path', query:{passed_id: data.id} }}></Link>
Then on the component that the path routes to:
this.setState({passed_id: this.props.location.query.passed_id});
And that gave me access to the data i was passing, in this case an ID. Now I just need to figure out how to compare that ID, with the looped data I also pass (via local storage), and map over it. Another question i suppose.
You need to use redux. This allows you to store data in global application store, and get the data from any component which is subscribed to the store. Today almost every react project needs redux to manage the data across the application

Preserve internal state on page refresh in React.js

It must be pretty regular issue.
I'm passing props down to the children and I'm using it there to request to the endpoint. More detailed: I'm clicking on the list item, I'm checking which item was clicked, I'm passing it to the child component and there basing on prop I passed I'd like to request certain data. All works fine and I'm getting what I need, but only for the first time, ie. when refreshing page incoming props are gone and I cannot construct proper URL where as a query I'd like to use the prop value. Is there a way to preserve the prop so when the page will be refresh it will preserve last prop.
Thank you!
(You might want to take a look at: https://github.com/rt2zz/redux-persist, it is one of my favorites)
Just like a normal web application if the user reloads the page you're going to have your code reloaded. The solution is you need to store the critical data somewhere other than the React state if you want it to survive.
Here's a "template" in pseudo code. I just used a "LocalStorage" class that doesn't exist. You could pick whatever method you wanted.
class Persist extends React.Component {
constuctor(props) {
this.state = {
criticalData = null
}
}
componentDidMount() {
//pseudo code
let criticalData = LocalStorage.get('criticalData')
this.setState({
criticalData: criticalData
})
}
_handleCriticalUpdate(update) {
const merge = {
...LocalStorage.get('criticalData')
...update
}
LocalStorage.put('criticalData', merge)
this.setState({
criticalData: merge
})
}
render() {
<div>
...
<button
onClick={e => {
let update = ...my business logic
this._handleCriticalUpdate(update) //instead of set state
}}
>
....
</div>
}
}
By offloading your critical data to a cookie or the local storage you are injecting persistence into the lifecycle of the component. This means when a user refreshes the page you keep your state.
I hope that helps!

How to define state?

Does anyone have a good definition for state in the context of a web app?
And more specifically: what does state mean in the context of React - does that differ at all from the first definition?
I see the term state being used a lot in React development but I haven't been able to find a solid, concise definition for it.
State in the context of both cases (react and web apps) is the same.
From wikipedia
In information technology and computer science, a program is described as stateful if it is designed to remember preceding events or user interactions; the remembered information is called the state of the system.
The important part of that quote is remember preceding events or user interactions.
In a web app
State is typically stored in a database somewhere. The web app retrieves the 'state' (data) from the database, presents a view that allows the user to interact with the state, then sends the new 'state' (data) back to the database.
In react
React can be thought of as presenting the 'state' of an application to the user. Data is retrieved from somewhere, react displays the data (state) to the user, allows the user to modify it, and then sends it back to where it found it (remembering).
However, when people talk about 'state' in the context of react, they are generally referring to the internal representation of the data or interactions that react is holding in memory while the user is busy interacting with it.
A simple react component that holds some state:
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {
userName: 'Leeloo'
};
// This binding is necessary to make `this` work in the callback
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
const name = (this.state.userName === 'Leeloo') ? 'Korben' : 'Leeloo'
this.setState({
userName: name
})
}
render() {
return ( <
button onClick = {
this.handleClick
} > {
this.state.userName
} <
/button>
);
}
}
ReactDOM.render( < Toggle / > , document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
In the example above, the component creates some state and stores it in a 'state' property of the class.
It is remembering it's internal state.
When the component renders, it looks up the value stored in state and displays it on the button label. When the button is clicked, this.state is updated to 'remember' the event of clicking the button.
In a full featured web app, you would be retrieving data from a database, storing that data in state, allowing the user to interact with it, then sending that data back to the database.
For example, you might display a user profile page, the user changes their name, password, description, etc... You would store the 'state' of all the changes they made on that page until they click a submit button. Then you could gather up all the changes from the components state and send it back to the database for storage (remembering).
Also, you may want to store state in a react component to describe how the appearance of the app should be based on interactions with it. For example, an InputBox component may have a hasError state and when true, adds a red border to the component.
General: State is all data currently stored by the application.
In context of React: State is an object that defines - besides props - how a component is rendered. State can be (unlike props) changed by the component itself.

How to inherit query parameters on Link Component without knowledge of the location object

My App has some globally available query parameters ?from=2016-05-01&to=2016-05-7&interval=daily
I am using react-router 2.4.0 and the location object is available via props on all of the routing components.
So whenever I am on a Component where the location object is available I can simply do this to keep the query params on the link:
<Link to={{ pathname: '/whatever', query: this.props.location.query }}>
whatever
</Link>
By now I pass down the location as prop to all child components that need to have links with inherited query params. But I quickly realized that nearly any Component needs to know the location because I want to have the opportunity to put links anywhere. This endet up in very long prop chains.
Currently the Link Component itself does not provide an API for query inheritance, so I am wondering if anyone has a good workaround for a Link Component that can be placed anywhere but can inherit the query params!?
Update:
I'd like to thank QoP for his answer but I forgot to mention that getting the location from the context is also no suitable solution for me, as all parent Components lose their 'pureness' which means that I can't rely on 'shallowCompare' anymore.
You can create an enhanced link component which automatically includes the query params.
Something like this.
class EnhancedLink extends React.Component {
constructor(props) {
super(props);
}
render(){
return <Link to={{ pathname: {this.props.path}, query: this.context.location.query }}>
{this.props.text}
</Link>
}
}
EnhancedLink.contextTypes = {
location: React.PropTypes.object
};
export default EnhancedLink
And use it like this
<EnhancedLink path="/yourNewUrl" text="yourLinkText" />

Resources