How to pass state with React Router? - reactjs

I'm fetching data of list of champions from JSON file, and am trying to make a link to view each champ and am not sure how to pass img property in the link from react-router.
I tried using state: champion.img but it's not giving anything. Any ideas how can I pass the image value?
import React, { Component } from 'react'
import axios from 'axios'
import { Link } from 'react-router-dom';
class PersonList extends Component {
state = {
persons: [],
name:"",
champs: [],
isLoaded: false,
Aatrox:''
}
componentDidMount(){
axios({
method: 'get',
url: 'https://api.myjson.com/bins/blcps'
})
.then(res => {
this.setState({ persons: res.data[1]})
console.log(res.data[0].name);
console.log('ldldl');
const champions = res.data.map((champion) => {
console.log(champion.name)
console.log(this.state.champs.name)
return <div classname="container-fluid">
<div classname="row">
<p>ldldl</p>
<h2 className="card-title">{champion.name}</h2> </div>
<img src={champion.img} />
<Link to={{ pathname:`/champions/${champion.name}`,// undefined state: {champion.img} }} > {champion.name} </Link>
</div>
})
this.setState({ champs: champions, isLoaded: true });
})
}
render() {
return (
<ul>
{this.state.isLoaded ? <div>{this.state.champs}</div> : <div>.</div>}
</ul>
)
}
}
export default PersonList;

when you console.log(champion.img), do you get a full url ? if not you have to place the complete url of the file not just filename for it to work. How you do this depends on what was returned from the server.

Related

Can not pass props to component

I am creating an embedded react application into a wordpress site. I have fetched the data to show a list of posts however I can not pass the props to the Single post page. I can only think that it has something to do with the BrowserRouter and react-router-dom. I've searched Stack Overflow and can not find anything that is recent, the things I have tried have all failed. There maybe something very simple that I am missing.
Home.js
import React from "react";
import axios from "axios";
import { Link } from "react-router-dom";
import "../sass/home.scss";
class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
posts: [],
error: "",
};
}
componentDidMount() {
const wordPressSiteUrl = "http://localhost/wordpress";
this.setState({ loading: true }, () => {
axios
.get(`${wordPressSiteUrl}/wp-json/acf/v3/property`)
.then((res) => {
this.setState({ loading: false, posts: res.data });
console.log(res.data);
})
.catch((error) =>
this.setState({ loading: false, error: error.response.data })
);
});
}
render() {
const { posts } = this.state;
return (
<div>
{posts.length ? (
<div className="post-container">
{posts.map((post) => (
<div key={post.id} className="card">
<div className="card-header">
<Link to={`/property/${post.id}`}>
{post.acf.property_title}
</Link>
</div>
<div className="card-img-top">
<img src={post.acf.featured_image.url} alt="" />
{console.log(post.id)}
</div>
</div>
))}
</div>
) : (
""
)}
</div>
);
}
}
export default Home;
As it stands, I am getting undefined in the console log.
SinglePost.js;
import React from "react";
import axios from "axios";
class SinglePost extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
post: {},
error: "",
};
}
componentDidMount() {
const wordPressSiteUrl = "http://localhost/wordpress";
console.warn(this.props.id);
this.setState({ loading: true }, () => {
axios
.get(`${wordPressSiteUrl}/wp-json/acf/v3/property/${this.props.id}`)
.then((res) => {
this.setState({ loading: false, post: res.data });
})
.catch((error) =>
this.setState({ loading: false, error: error.response.data })
);
// console.log(this.props.id);
});
}
render() {
const { post, error, loading } = this.state;
return (
<div>
{Object.keys(post).length ? (
<div className="post-container">
<div key={post.id} className="card">
<div className="card-header">{post.acf.property_title}</div>
<div className="card-img-top">
<img src={post.acf.featured_image.url} alt="" />
{console.log(post.id)}
</div>
</div>
</div>
) : (
""
)}
</div>
);
}
}
export default SinglePost;
App.js
import React from "react";
import Home from "./components/Home";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import SinglePost from "./components/SinglePost";
import Navbar from "./components/Navbar";
function App() {
return (
<div className="App">
<BrowserRouter>
<Navbar />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/property/:id" element={<SinglePost />} />
</Routes>
</BrowserRouter>
</div>
);
}
export default App;

Markdown component not rendering from content stored in State

I'm attempting to render Markdown using 'react-markdown' and setting the content as state. This state is set in componentDidMount, and console logging the state successfully logs the content like so (it's just nonsense as this is an example while I set it up):
**Bold text**
*Italic text*
__Underlined text__
~~Strikethrough text~~
List
- Hello
Numbered list
1. Number one
Image
![AA.png](/uploads/AA_6834a9a7ea.png)
However, when I then try to render my content in my component, it just comes through as blank.... Which I can't figure out why it's happening.
Here's my component code:
import React, { Component } from 'react';
import Strapi from 'strapi-sdk-javascript/build/main';
import Moment from 'react-moment';
import Markdown from 'react-markdown';
import './blog.css';
import MainHeader from '../global/main-header'
import Footer from '../global/footer'
class IndividualBlogPost extends Component {
constructor(props) {
super(props)
this.state = {
title: '',
description: '',
datePosted: '',
content: '',
author: ''
}
}
async componentDidMount() {
const params = this.props.match.params.id
try {
const posts = await strapiInstance.getEntry('blog-posts', params)
this.setState({
title: posts.Title,
description: posts.Description,
datePosted: posts.created_at,
content: posts.Content,
author: `${posts.created_by.firstname} ${posts.created_by.lastname}`
})
console.log(this.state.content)
}
catch(err) {
console.log(err)
}
}
render() {
const content = this.state.content
return (
<div>
<MainHeader />
<section className="individual-blogpost-section">
<div className="individual-blogpost-container">
<h1 className="individual-blogpost-heading">{this.state.title}</h1>
<div className="individual-blogpost-author-datePosted">
<p className="individual-blog-post-title-paragraph">{this.state.author} | <Moment format="MMM Do YYYY">{this.state.datePosted}</Moment></p>
</div>
<h4 className="individual-blogpost-description">{this.state.description}</h4>
<div className="individual-blogpost-content">
<Markdown src={content} />
</div>
</div>
</section>
<Footer />
</div>
)
}
}
export default IndividualBlogPost
As you can hopefully see, I'm attempting to set a const named content as this.state.content, and then passing the source of the markdown in to the Markdown component.
This is the first time I'm using Markdown, so I'm probably doing something obviously wrong, but any help would be appreciated!
According to their documentation, the content is actually passed as children to Markdown.
So you can do this:
<div className="individual-blogpost-content">
<Markdown >
{content}
</Markdown>
</div>
i am add package npm i remarkable.
and wrote this code
import React from "react";
import { Remarkable } from "remarkable";
class MarkdownEditor extends React.Component {
constructor(props) {
super(props);
this.md = new Remarkable();
this.handleChange = this.handleChange.bind(this);
this.state = { value: "Hello, **world**!" };
}
handleChange(e) {
this.setState({ value: e.target.value });
}
getRawMarkup() {
return { __html: this.md.render(this.state.value) };
}
render() {
return (
<div className="MarkdownEditor">
<h3>Input</h3>
<label htmlFor="markdown-content">Enter some markdown</label>
<textarea
id="markdown-content"
onChange={this.handleChange}
defaultValue={this.state.value}
/>
<h3>Output</h3>
<div
className="content"
dangerouslySetInnerHTML={this.getRawMarkup()}
/>
</div>
);
}
}
export default MarkdownEditor;
Work Demo

React API elements not displaying on page

I've been looking for about 2 hours into why I am not displaying any of the information to the page. I've console logged my response from a simple random quote api and it shows, Author: and Quote: in the console, however these are not appearing in my fields, All I am seeing is the button.
import React, { Component } from 'react';
import QuoteMachine from './Quotemachine';
const END_POINT = 'https://random-quote-
generator.herokuapp.com/api/quotes/random';
class App extends Component {
constructor(props) {
super(props);
this.state = {
quote: {
text: '',
author: ''
}
}
}
getQuote() {
fetch(END_POINT)
.then(response => response.json())
.then(response => {
this.setState = ({
quote: response
});
console.log(response);
})
}
componentDidMount() {
this.getQuote();
}
render() {
return (
<div className="App">
<div className="container">
<QuoteMachine quote= {this.state.quote} />
<button id="new-quote" className="primary-color-
background" onClick={() => this.getQuote()}>New quote</button>
</div>
</div>
);
}
}
export default App;
And then here is my Quotemachine.js
import React from 'react'
import PropTypes from 'prop-types';
const QuoteMachine = (props) => {
return (
<div className="quote-box">
<div className="text">
<span>{props.quote.text}</span>
</div>
<div className="author">
<span >{props.quote.author}</span>
</div>
</div>
);
};
QuoteMachine.propTypes = {
quote: PropTypes.object.isRequired
};
export default QuoteMachine;
It is only displaying the button, but the console.log shows
Object
author:
"Thomas Henry Huxley (1825-1895)"
quote:
"Try to learn something about everything and everything about something."
proto
:
Object
Install React Developer Tools plugin and check if your state is changing after the API call

ReactJS error TypeError: Cannot read property 'map' of undefined

I'm attempting to consume a JSON API using fetch; the error mentioned above appears on the following line: **this.state.data.map( (dynamicData,key)=>**
This is my ReactJS code with the error line in bold:
import React, { Component } from 'react';
import './App.css';
class App extends Component {
//constructor
constructor() {
super();
this.state = {
data: [],
}
} //end constructor
componentDidMount(){
return fetch('https://jsonplaceholder.typicode.com/todos')
.then((response)=>response.json())
.then((responseJson)=>
{
this.setState({
data:responseJson.todos
})
console.log(this.state.data)
})
} // end component did mount
render() {
return (
<div>
<h2>Todo:</h2>
<div>
{
**this.state.data.map( (dynamicData,key)=>**
<div>
<span> {dynamicData.userId} </span>
<span> {dynamicData.id} </span>
</div>
)
}
</div>
</div>
);
}
}
export default App;
Could I get some help as to what I'm doing wrong? Thanks in advance
import React, { Component } from "react";
import { render } from "react-dom";
class App extends Component {
state = {
data:[],
url: "https://jsonplaceholder.typicode.com/todos"
};
componentDidMount() {
fetch(this.state.url)
.then(response => response.json())
.then(data => this.setState({ data }));
}
render() {
const { data } = this.state;
data && console.log(data);
return (
<div>
{data &&
data.map(item => <div> Hello User With Id: {item.userId} </div>)}
</div>
);
}
}
render(<App />, document.getElementById("root"));
Your didMount should look like mine also, setState takes a callback so if you wanted to see what the data looked like it would be like this
this.setState({ data }, () => console.log(this.state.data))
In your render it looks like you forgot the parenthesis after the arrow function in map.
render() {
return (
<div>
<h2>Todo:</h2>
<div>
{
this.state.data.map((dynamicData,key)=> (
<div>
<span> {dynamicData.userId} </span>
<span> {dynamicData.id} </span>
</div>
))
}
</div>
</div>
);
}

How to display loaded posts with React and Redux

I'm new to React and Redux, and im trying to load posts from the WordPress REST API, and display them in my React App.
I'm using this as an example: https://github.com/jackreichert/a-wp-react-redux-theme
My action to get the posts look like this:
import axios from 'axios';
export const FETCH_POSTS = 'FETCH_POSTS';
export function fetchPosts(post_type = 'posts') {
return function (dispatch) {
axios.get(`http://localhost:8080/wp-json/wp/v2/${post_type}`)
.then(response => {
dispatch({
type: FETCH_POSTS,
payload: response.data
});
});
}
}
It's passed to the reducer, which looks like this:
import { FETCH_POSTS } from '../actions';
export default (state = [], action) => {
switch (action.type) {
case FETCH_POSTS:
return action.payload;
default :
state = '';
break;
}
return state;
}
And (though it's only one reducer) I'm combining it, because there are more reducers to follow (just like in the example), and then I'm storing it. Also pretty much the same way as the example.
Im loading everything in my Home.jsx file, which looks like this right now:
import React, { Component } from 'react';
import {connect} from 'react-redux';
import { Link } from 'react-router-dom';
import Header from '../Header';
import {fetchPosts} from '../../actions/';
class Home extends Component{
componentDidMount(){
document.title = 'Test';
}
componentWillMount() {
this.getPosts(this.props, true);
}
componentWillReceiveProps(nextProps) {
this.getPosts(nextProps);
}
getPosts(props, willMount = false) {
if (willMount) {
this.props.fetchPosts();
}
}
render() {
return(
<div>
<Header/>
<main>
<h1>Home</h1>
</main>
</div>
)
}
}
function mapStateToProps({posts}) {
return {posts};
}
export default connect(mapStateToProps, {fetchPosts})(Home);
I think my code above is right. Redux can also 'find' my posts, and logs in my console:
action FETCH_POSTS # 11:11:56.393
prev state Object {posts: ""}
action Object {type: "FETCH_POSTS", payload: Array(2)}
next state Object {posts: Array(2)}
Now I want to know: How can I simply display the posts which are loaded by Redux, in my Home.jsx file.
And after that: How can I configure the route and data, to go to a single post (but that will come later, for now I only want to know an easy but right way how to display the posts)
I have no idea about the structure of your Post object. But it should be something like this.
renderPosts() {
return _.map(this.props.posts, post => {
return (
<li className="list-group-item" key={post.id}>
{post.title}
</li>
);
});
}
Then in your render method merely call it like this.
render() {
return (
<div>
<h3>Posts</h3>
<ul className="list-group">
{this.renderPosts()}
</ul>
</div>
);
}
Also notice that I am using map helper from lodash library here. So you need to have following import statement in your component.
import _ from 'lodash';
Hope this helps. Happy coding !
If you implemented you combineReducers correctly then mapStateToPosts should be called with set of posts when it is changed.
import posts from './posts_reducer';
combineReducers({ posts });
To render posts in your Home component you need to modify the render function, see raw implementation below:
render() {
let postsElements = this.props.posts.map(p => {
return <div>p.title</div>
});
return(
<div>
<Header/>
<main>
<h1>Home</h1>
</main>
<div>
{postsElements}
</div>
</div>
)
}
You need to use this.props.posts to access your posts because react-redux maps properties from state to props object of the component using mapStateToProps function that is provided as a 1st argument when calling connect function.
To improve this you can implement you Blog component and replace div with that.
Also, review how it is implemented in the example you provided https://github.com/jackreichert/a-wp-react-redux-theme/blob/master/src/components/main.js in this file posts are rendered.
import React, { Component } from 'react';
import { connect } from 'react-redux'; // glue between react and redux
import Parser from 'html-react-parser';
import { LinkContainer } from 'react-router-bootstrap';
import { ListGroup, ListGroupItem, Image } from 'react-bootstrap';
class BlogPosts extends Component {
render() {
if (!this.props.posts) {
return (<div></div>);
}
return (
<div className="blog-items" >
<ListGroup>
{this.renderBlogPosts()}
</ListGroup>
</div>
)
};
renderBlogPosts() {
if (this.props.posts.posts) { //v1
const posts = this.props.posts.posts; // DRY
return posts.map((post, index) => {
const excerptText = JSON.stringify(post.excerpt);
const excerpt = excerptText.substring(1, excerptText.length-3);
return (
<LinkContainer className="blog-posts-link" key={post.ID} to={ "/blog/post/" + post.ID + '/'}>
{ this.getHtml(
post.ID,
(post.featured_image) ? post.featured_image : '',
post.title,
excerpt
)}
</LinkContainer>
);
});
};
const posts = this.props.posts; // DRY
return posts.map((post, index) => { // v2
return (
<div key={post.id}>
{this.getHtml(
post.id,
(post._embedded['wp:featuredmedia'])
? post._embedded['wp:featuredmedia'][0].media_details.sizes.thumbnail.source_url : '',
post.title.rendered,
post.excerpt.rendered
)}
</div>
);
});
};
getHtml(id, imageSrc, title, excerpt) {
return (
<ListGroupItem className="blog-posts-list-item">
{this.getImage(imageSrc, title)}
<h2 className="blog-posts-title">{ Parser(title) }</h2>
<div className="blog-posts-excerpt">{Parser(excerpt)}</div>
</ListGroupItem>
);
};
getImage(imageSrc, title) {
return (imageSrc === "")
? (<div></div>)
: (<div className="blog-posts-image-div">
<Image className="blog-posts-image" src={imageSrc} alt={title} />
</div>
);
};
};
const mapStateToProps = (state) => ({ posts: state.posts });
export default connect(mapStateToProps) (BlogPosts);

Resources