React setState of array of objects - reactjs

I have an array of 10 objects (Lets call them "Blogs") which contain title, description and image-URL properties. I need to wrap each of the properties in HTML tags and export them all so they all load on a webpage together.
With my current code, I am only getting 1 of the objects in the current state loading on the page. How do I get all the objects in the same state?
class NewBlogs extends React.Component {
constructor(props) {
this.state = {
title: [],
description: [],
image: [],
loading: true
};
}
componentDidMount() {
axios.get('/new-blogs').then(data => {
const blogs = data.data;
var component = this;
for(var i in blogs) {
component.setState({
title: blogs[i].title,
description: blogs[i].description,
image: blogs[i].image,
loading: false
});
}
})
.catch(function(error) {
console.log(error);
});
}
render() {
return (
<div>
<h2>New Blogs:</h2>
<h3>{this.state.title}</h3>
<em>{this.state.description}</em>
<img src={this.state.image}></img>
</div>
);
}
}
export default NewBlogs

I haven't run/test this but try something like this
The API call appears to return a list of objects. If so just set state once the xhr completes and set loading false once.
In the react render() is where you could iterate over your list. The easiest way to do that is with '.map()'. You then simply return react elements for each object in your list.
Also let's rename 'component' to 'list'
class NewBlogs extends React.Component {
constructor(props) {
this.state = {
list: [],
loading: true
};
}
componentDidMount() {
axios.get('/new-blogs').then(data => {
// const blogs = data.data;
// var component = this;
this.setState({list: data.data, loading: false })
// for(var i in blogs) {
// this.setState({
// title: blogs[i].title,
// description: blogs[i].description,
// image: blogs[i].image,
// loading: false
// });
// }
})
.catch(function(error) {
console.log(error);
});
}
render() {
return (
<div>
{this.state.list.map(e => (
<h2>New Blogs:</h2>
<h3>{e.title}</h3>
<em>{e.description}</em>
<img src={e.image}></img>
))}
</div>
);
}
}
export default NewBlogs

Related

How to use react-data-table-component to display array stored in the constructor this:state?

I am new to the React, And I want to using react-data-table-component to display my fetch data from Api in a sorted table. but the issue I do not know the correct method to use the react-data-table-component.and the instruction of react-data-table-component do not include such example.
Following is my code:
I was trying to put offence or this.state.offence direct into data, but show nothing, anyone please give me some advises about the correct way to use this or some other way create sorted table to show this data.and there is link to the react-data-table-component a link:
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { off } from 'rsvp';
import DataTable from 'react-data-table-component';
const columns = [
{
name: 'Offences',
selector: 'Offences',
sortable: true,
},
{
name: 'Year',
selector: 'year',
sortable: true,
right: true,
},
];
class SignInForm extends Component {
constructor() {
super();
this.state = {
email: '',
password: '',
offence:[],
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleClick =this.handleClick.bind(this);
this.handleLogin =this.handleLogin.bind(this);
}
handleClick(){
const url ="https://xxxxxxxxxx.sh/offences";
fetch(url)
.then(response => {
console.log(response.clone().json())
console.log(response.headers.get('Content-Type'))
if (response.ok) {
return response.clone().json();
} else {
throw new Error('Something went wrong ...');
}
})
.then((res) =>{
console.log(res)
this.setState({
offence: [res]
});
}) // get just the list of articles
console.log(this.state.offence);
}
render() {
return (
<button className="FormField__offence" onClick{this.handleClick}>offence</button>
</div>
<div>
<DataTable
title="Offences"
columns={columns}
data={this.state.offence}
/>
</div>
</form>
</div>
);
}
}
export default SignInForm;
I was expecting one column decent table show
const columns = [
{
name: 'Offences',
selector: 'Offences',
sortable: true,
}
];
class SignInForm extends React.Component {
constructor() {
super();
this.state = {
email: '',
password: '',
offence: [],
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
const url = "https://xxxxxxxx.sh/offences";
fetch(url)
.then(response => {
if (response.ok) {
return response.clone().json();
} else {
throw new Error('Something went wrong ...');
}
})
.then((res) => {
this.setState({
offence: res.offences.map((item,id) => ({id, Offences: item}))
});
}) // get just the list of articles
}
render() {
console.log(this.state.offence)
return (
<div className="App">
<button
className="FormField__offence"
onClick={this.handleClick}>offence</button>
<DataTable
title="Offences"
columns={columns}
data={this.state.offence}
/>
</div>
);
}
}
Live Link
Replace this,
this.setState({
offence: [res]
});
with this,
this.setState({
offence: res
});
In your case this is res from API call
{offences: Array(88)}
offences: (88) ["Advertising Prostitution", ... "Weapons Act Offences", "Weapons Act Offences - Other"]
__proto__: Object
So you can get offences like this,
this.setState({
offence: res.offences
});

how to use react joyride in multiple pages

Is there a way of creating a react-joyride tour in multiple pages.so my index.js file looks like below? I added react-joyride in index page because all components run through the index.js file.
class IndexApp extends Component {
constructor(props) {
super(props);
this.state = {
view: false,
run: true,
steps: [
{
target: '.cc',
content: 'This is my awesome feature!',
},
],
stepIndex: 0
};
}
handleJoyrideCallback = data => {
const { action, index, status, type } = data;
console.log("ghgg")
if ([EVENTS.STEP_AFTER, EVENTS.TARGET_NOT_FOUND].includes(type)) {
// Update state to advance the tour
this.setState({ stepIndex: index + (action === ACTIONS.PREV ? -1 : 1) });
}
else if ([STATUS.FINISHED, STATUS.SKIPPED].includes(status)) {
// Need to set our running state to false, so we can restart if we click start again.
this.setState({ run: false });
}
console.groupCollapsed(type);
console.log(data); //eslint-disable-line no-console
console.groupEnd();
};
componentDidCatch(error, errorInfo) {
this.setState({ error });
unregister();
}
render() {
const { view,run, stepIndex, steps } = this.state;
if (view) {
return( <div>
{this.props.children}
<Joyride
callback={this.handleJoyrideCallback}
run={run}
stepIndex={stepIndex}
steps={steps}
/>
</div>);
} else {
return null;
}
}
}
You can use globalState for this, then create a hook on all pages.
For global state : https://endertech.com/blog/using-reacts-context-api-for-global-state-management
https://github.com/gilbarbara/react-joyride/discussions/756
const initialState = {
tour: {
run: false,
steps: []
}
}

React: Issues with Conditional Rendering

In my React-App, i use the Firebase SDK. If a user wants to reset his password, he will be redirected to a page within my app. If the code is valid, the component <PWResetConfirmForm /> should be rended. If the code is invalid, the component <PWResetOutdatedForm /> is to be rendered.
My Page Component looks like this:
class PWResetConfirmPage extends Component {
constructor(props) {
super(props);
this.state = {};
this.verfiyResetPassword = this.verfiyResetPassword.bind(this);
}
verfiyResetPassword() {
const params = (new URL(`http://dummy.com${this.props.location.search}`)).searchParams;
const code = params.get("oobCode")
auth.doVerfiyPasswordReset(code)
.then(function () {
return (
<div className="HomePage-Main">
<TopBar></TopBar>
<PWResetConfirmForm></PWResetConfirmForm>
</div>
);
})
.catch(function () {
return (
<div className="HomePage-Main">
<TopBar></TopBar>
<PWResetOutdatedForm></PWResetOutdatedForm>
</div>
);
})
}
render() {
return (
<div>
{this.verfiyResetPassword()}
</div>
);
}
}
export default PWResetConfirmPage
When i try to run, i get a blank page and not error.
Where is my issue and how can i fix that?
Thank you very much for your help and for your time
You will not be able to return JSX from within then()/catch() of auth.doVerfiyPasswordReset() like that. You can instead approach this by taking advantage of React.Component lifecycle method componentDidMount and using setState() to manipulate state properties for conditional rendering. I've added state properties to the component, one to track whether loading (API call has completed) and one to track whether the call was a success (then) or failure (catch). These properties are used to conditionally generate JSX content for rendering. This is assuming that verfiyResetPassword() is intended to run when the component is first mounted, instead of every time render() is called:
class App extends Component {
constructor() {
super();
this.state = {
isResetVerified: null,
loading: true
};
}
componentDidMount() {
this.verfiyResetPassword();
}
verfiyResetPassword() {
const params = (new URL(`http://dummy.com${this.props.location.search}`)).searchParams;
const code = params.get("oobCode")
auth.doVerfiyPasswordReset('foobar')
.then(() => {
this.setState({
...this.state,
isResetVerified: true,
loading: false
});
})
.catch(() => {
this.setState({
...this.state,
isResetVerified: false,
loading: false
});
})
}
getContent() {
if (this.state.loading) {
return (
<div>Loading...</div>
);
} else {
if (this.state.isResetVerified) {
return (
<div className="HomePage-Main">
<TopBar></TopBar>
<PWResetConfirmForm></PWResetConfirmForm>
</div>
);
} else {
return (
<div className="HomePage-Main">
<TopBar></TopBar>
<PWResetOutdatedForm></PWResetOutdatedForm>
</div>
);
}
}
}
Here is a basic example in action.
Also, in the constructor this.verfiyResetPassword = this.verfiyResetPassword.bind(this); would only be needed if verfiyResetPassword() is executed by a DOM event such as button onClick or similar.
Hopefully that helps!
I could still fix the error myself:
class PWResetConfirmPage extends Component {
constructor(props) {
super(props);
this.state = {
isValid: false,
code: "",
};
this.verfiyResetPassword = this.verfiyResetPassword.bind(this);
}
componentDidMount() {
const params = (new URL(`http://dummy.com${this.props.location.search}`)).searchParams;
const code = params.get("oobCode")
this.setState({code:code})
auth.doVerfiyPasswordReset(code)
.then(() => {
this.setState({
...this.state,
isValid: true,
});
})
.catch(() => {
this.setState({
...this.state,
isValid: false,
});
})
}
verfiyResetPassword() {
if (this.state.isValid) {
return (
<div>
<TopBar></TopBar>
<PWResetConfirmForm code={this.state.code}></PWResetConfirmForm>
</div>
);
} else {
return (
<div>
<TopBar></TopBar>
<PWResetOutdatedForm></PWResetOutdatedForm>
</div>
);
}
}
render() {
return (
<div className="HomePage-Main">
{this.verfiyResetPassword()}
</div>
);
}
}
export default PWResetConfirmPage

added item to state but can't render

I managed to add Item to the list but can't render it.
My App.js:
class App extends Component {
constructor(props) {
super(props);
this.state = {
recipes: [{
...sample data...
}]
}
}
createRecipe(recipe) {
this.state.recipes.push({
recipe
});
this.setState({ recipes: this.state.recipes });
}
render() {
...
export default App;
and my RecipeAdd:
export default class RecipeAdd extends Component {
constructor(props) {
super(props);
this.state = {
url: '',
title: '',
description: '',
error: ''
};
}
...event handlers...
onSubmit = (e) => {
e.preventDefault();
if (!this.state.url || !this.state.title || !this.state.description) {
this.setState(() => ({ error: 'Please provide url, title and description.'}));
} else {
this.setState(() => ({ error: ''}));
this.props.createRecipe({
url: this.state.url,
title: this.state.title,
description: this.state.description
});
}
}
render () {
return (
<div>
...form...
</div>
)
}
}
In React dev tools I see the recipe is added with 'recipe'. How should I change my createRecipe action to add new recipe properly? :
It looks like you're wrapping the recipe in an extra object. You can see in your screenshot that index 3 has an extra recipe property.
It should be more like this -- just .push the recipe object directly:
createRecipe(recipe) {
this.state.recipes.push(recipe);
this.setState({ recipes: this.state.recipes });
}
Even better would be to not mutate the state object directly, by using concat instead:
createRecipe(recipe) {
this.setState({
recipes: this.state.recipes.concat([recipe])
});
}

React - Cannot get property setState of null

I am intending to get snapshot val from Firebase within my React component. I want to get the values based on init of the component and attach a listener for changes.
class ChatMessages extends Component {
constructor(props) {
super(props);
this.state = {
messages: [],
};
this.getMessages = this.getMessages.bind(this);
}
getMessages(event) {
const messagesRef = firebase.database().ref('messages');
messagesRef.on('value', function(snapshot) {
this.setState({ messages: snapshot.val() });
});
}
componentDidMount() {
this.getMessages();
}
render() {
return (
<div className="container">
<ul>
<li>Default Chat Message</li>
{ this.state.messages }
</ul>
</div>
);
}
}
This is because 'this' is losing its context. So that, 'this.setState' is being undefined. You can have a reference for the actual 'this' via a variable called 'that'.
class ChatMessages extends Component {
constructor(props) {
super(props);
this.state = {
messages: [],
};
this.getMessages = this.getMessages.bind(this);
}
getMessages(event) {
const messagesRef = firebase.database().ref('messages');
let that = this
messagesRef.on('value', function(snapshot) {
// here
that.setState({ messages: snapshot.val() });
});
}
componentDidMount() {
this.getMessages();
}
render() {
return (
<div className="container">
<ul>
<li>Default Chat Message</li>
{ this.state.messages }
</ul>
</div>
);
}
}
Or if possible, you can use arrow function, which keeps its context.
getMessages(event) {
const messagesRef = firebase.database().ref('messages');
// here
messagesRef.on('value', snapshot => {
// here
that.setState({ messages: snapshot.val() });
});
}

Resources