I must say first that I come from mobile development. I am very new with web development so this is probably an amateur questions.
I am building a react.js project using create-react-app (which uses Babel). I am trying to follow a tutorial where I am supposed to import a *.json file when my component mounts. I can't seem to be able to access my data, and I get an error saying "filteredApts.map is not a function".
Here are my imports:
import React from 'react';
import './App.css';
import $ from 'jquery';
Here is my componentWillMount method:
componentDidMount: function() {
console.log($.get('./data.json', function(){}.bind(this))) //This seems to get an HTML Page returned!
this.serverRequest = $.get('./data.json', function(result) {
var tempApts = result;
this.setState({
myAppointments: tempApts
}); //setState
}.bind(this));
},
my render method:
render: function() {
var filteredApts = this.state.myAppointments;
filteredApts = filteredApts.map(function(item, index) {
return (<li className="pet-item media" key={index}>
<div className="pet-info media-body">
<div className="pet-head">
<span className="pet-name">{this.state.myAppointments[index].petName}</span>
<span className="apt-date pull right">{this.state.myAppointments[index].petName}</span>
</div>
<div className="owner-name"><span className="label-item">Owner:</span>
{this.state.myAppointments[index].ownerName}</div>
<div className="apt-notes">
{this.state.myAppointments[index].aptNotes}</div>
</div>
</li>)
}.bind(this));
return (<div className="interface">
<div className="item-list media-list">
<ul className="item-list media-list"></ul>
</div>
</div>)
} //render
}); //MainInterface
Here is my map of files:
And finally my console log:
Is somebody capable of pointing out what I might be doing wrong?
I'd suggest to change this line:
var filteredApts = this.state.myAppointments;
to this
var filteredApts = this.state.myAppointments || [];
You use asynchronous data fetching and at the moment of rendering it can be no myAppointments yet.
Looks like your responseText is html.
I figured it out.
First, './data.json' was pointing to the public folder by default.
Second, I was missing {filteredApts} in
return (<div className="interface">
<ul className="item-list media-list">{filteredApts}</ul>
</div>)
Thanks anyways to all.
Related
I am trying to convert a next.js app(https://medium.com/strapi/how-to-create-pages-on-the-fly-with-dynamic-zone-8eebe64a2e1) to a nuxt.js app. In this app I can fetch data from an API and the next.js app uses the APIs data to generate new pages with its corresponding content. Works well in Next.js.
The data/content from the API consists of Seo data for the page, some static values and very important of blocks. These blocks have an attribute called __component where the components name is saved and also have the components data like images, text, etc. So I only have to deal with next.js when adding new components.
In next.js I used the catch-all-route ./pages/[[...slug]].js to catch any slug an user may enter. Then the API is fired with the slug from the context.query and I get back the pages data if it exists. Now the APIs json data only needs to be passed to the blockmanager component.
const Universals = ({blocks}) => {
return <div><BlockManager blocks={blocks}></BlockManager></div>;
};
Here the blockmanager gets the json list of blocks, from which to parse the components.
import Hero from '../../blocks/Hero';
import Pricing from '../../blocks/Pricing';
const getBlockComponent = ({__component, ...rest}, index) => {
let Block;
switch (__component) {
case 'blocks.hero':
Block = Hero;
break;
case "blocks.prices":
Block = Pricing;
break;
}
return Block ? <Block key={`index-${index}`} {...rest}/> : null;
};
const BlockManager = ({ blocks }) => {
return <div> {blocks.map(getBlockComponent)} </div>;
};
BlockManager.defaultProps = {
blocks: [],
};
export default BlockManager;
How can I replicate this line now in nuxt js?
return Block ? <Block key={`index-${index}`} {...rest}/> : null;
How to return a component/component-tag dynamically in vue/nuxt ?
Is there maybe another solution to automatically insert the wanted component?
Maybe someones knows ho to convert the blockmanagers logic to vue/nuxt logic entirely.
I think you're looking for the is attribute. You can read about it here.
Your template would look like:
<component
:is="__component"
key={`index-${index}`}
/>
Ok I think I got it. No strange stuff actually. I thought about it too complicated. Wanted all dynamically created but no need as I saw later ...
<template v-if="blocks">
<div id="example-1">
<div v-for="({__component, ...rest}=block, i) in blocks" :key="i">
<Hero :data="rest" v-if="__component === 'blocks.hero'"/>
<Pricing :data="rest" v-if="__component === 'blocks.pricing'"/>
</div>
</div>
</template>
<script>
import Hero from '../../blocks/Hero/Hero.vue';
import Pricing from '../../blocks/Pricing/Pricing.vue';
export default {
components: {
Hero, Pricing
},
props: {
blocks: Array
}
}
</script>
I am new to react and this is my first site and I have some plan JavaScript I found online that will allow a word to be typed out and updated over a course of time. I have already made it into a react Component. But I am not sure how to covert this JavaScript Function into react code.
Here is my new React Component.
import React, {Component} from 'react';
class Hero extends Component {
render () {
return (
<div>
<section id="hero" className="d-flex flex-column justify-content-center align-items-center">
<div className="hero-container" data-aos="fade-in">
<h1>Augusto J. Rodriguez</h1>
<p>I'm a <span className="typed" data-typed-items="opption1, opption2, opption3, opption4"></span></p>
</div>
</section>
</div>
);
}
}
export default Hero;
Here is the vanilla JavaScript that I want to use in my code. Currently this is living in my main.js file that is being called from the index.html. this is the only part of the code that is not working.
if ($('.typed').length) {
var typed_strings = $('.typed').data('typed-items');
typed_strings = typed_strings.split(',')
new Typed('.typed', {
strings: typed_strings,
loop: true,
typeSpeed: 100,
backSpeed: 50,
backDelay: 2000
});
}
I am assuming I need to create a function where my tag is. But I am not sure how to do that in React.
any article references would be awesome or tips on how to resolve this. I have the full code for this project on GitHub.
Looks like that piece of code is using a library called Typed.js.
From looking at your project, I see you setup the Typed.js library inside your public/assets/vendor folder. Instead I would recommend using the NPM package manager to install and setup Typed.js, and copy over the code to work the React way. https://github.com/mattboldt/typed.js/.
Here's an example using Typed.js with React. https://jsfiddle.net/mattboldt/ovat9jmp/
class TypedReactDemo extends React.Component {
componentDidMount() {
// If you want to pass more options as props, simply add
// your desired props to this destructuring assignment.
const { strings } = this.props;
// You can pass other options here, such as typing speed, back speed, etc.
const options = {
strings: strings,
typeSpeed: 50,
backSpeed: 50
};
// this.el refers to the <span> in the render() method
this.typed = new Typed(this.el, options);
}
componentWillUnmount() {
// Make sure to destroy Typed instance on unmounting
// to prevent memory leaks
this.typed.destroy();
}
render() {
return (
<div className="wrap">
<h1>Typed.js</h1>
<div className="type-wrap">
<span
style={{ whiteSpace: 'pre' }}
ref={(el) => { this.el = el; }}
/>
</div>
<button onClick={() => this.typed.toggle()}>Toggle</button>
<button onClick={() => this.typed.start()}>Start</button>
<button onClick={() => this.typed.stop()}>Stop</button>
<button onClick={() => this.typed.reset()}>Reset</button>
<button onClick={() => this.typed.destroy()}>Destroy</button>
</div>
);
}
}
ReactDOM.render(
<TypedReactDemo
strings={[
'Some <i>strings</i> are slanted',
'Some <strong>strings</strong> are bold',
'HTML characters × ©'
]}
/>,
document.getElementById('react-root')
);
It looks like currently you're using the 'typed' library to create this typed list. There are some community packages that act as React wrappers for that, like this one:
https://www.npmjs.com/package/react-typed
Alternatively, you could do what that library does yourself, by loading the 'typed' package in a call to componentDidMount, passing in a React ref instead of a DOM element.
By the way, currently your code uses jQuery (assigned to the variable $) so it's not quite vanilla JS. You could replace the calls to $ with calls to document.querySelector, to make this vanilla JS (though your code might depend on jQuery elsewhere)
I am building a website using React, and I want to integrate a shop from spreadshop.com / spreadshirt.com, to my React website.
Spreadshop.com gives quite good instructions on how to use script-tags to integrate their shop to an html-site (instructions can be found here).
I am not an experienced programmer, and I'm a little confused about how scripts work with React and especially about where I should put the spread_shop_config, which the Spreadshop instructions tells me to have available in window Scope. I have tried to use a useScript-hook, which I found here. But it doesn't seem to work.
Below is my implementation attempt so far.
What am I doing wrong? How can I integrate the Spreadshirt shop to my React website?
import React from 'react';
import useScript from './Hooks/useScript';
function Shop() {
const [loaded, error] = useScript('https://shop.spreadshirt.no/shopfiles/shopclient/shopclient.nocache.js');
var spread_shop_config = {
shopName: 'awesome-merch-shop',
locale: 'US',
prefix: 'https://shop.spreadshirt.com',
baseId: 'shop'
}
return (
<div className="shopBody">
{loaded && !error && (
<div id="shop">
<div>
<i id="spinner" className="fa fa-spinner" aria-hidden="true"/>
<p>Loading The Shop...</p>
</div>
</div>
)}
</div>
);
}
export default Shop;
I'll answer myself here, since I figured a better way and which actually works (better) for all scripts even if you need to add multiple different scripts to a page/component.
(Now I'm actually confused why we need a useScript-hook at all).
Inside the react component that needs to use the script, it seems better to use javascript to create a script-element and then append it to the document.body.
So in example, to add the Spreadshop.com script inside the Shop-component:
import React from 'react';
import './Shop.css';
function Shop() {
var js = document.createElement("script");
js.type = "text/javascript";
js.src = "https://shop.spreadshirt.no/shopfiles/shopclient/shopclient.nocache.js";
document.body.appendChild(js);
return (
<div className="shopBody">
<div id="shop">
<i id="spinner" className="fa fa-spinner" aria-hidden="true"/>
<p>Loading The Shop...</p>
</div>
</div>
);
}
export default Shop;
And the Spreadshop configurations variable I just add normally with script tags inside the index.html in the publics folder.
<script>
var spread_shop_config = {
shopName: 'awesome-merch-shop',
locale: 'US',
prefix: 'https://shop.spreadshirt.com',
baseId: 'shop'
}
</script>
By doing it this way, the Spreadshop script won't give an error message when loading every component, because the script is only appended when that component loads.
And also, since the script is loaded whenever that component is loaded, it will work even if you refresh the page, while if the script was only in the index.html then the index.html would have to be loaded for the script to be loaded.
Include the javascript and Spreadshirt config in your high-level index.js file. For most it's something like /public/index.html (the same folder you have your manifest.json, robots.txt, etc) along with my google fonts and bootstrap include before </html>
For my implementation I added
<script>
var spread_shop_config = {
shopName: 'YourShopNameHere',
locale: 'us_US',
prefix: 'https://shop.spreadshirt.com',
baseId: 'myShop'
};
</script>
<script type="text/javascript" src="https://shop.spreadshirt.com/shopfiles/shopclient/shopclient.nocache.js"></script>
And then in the React component:
import React from 'react';
import './Shop.css';
type Props = {
testProp: string
};
export const Shop = ({ testProp }: Props) => {
return (
<div id="Shop-Component">
<div id="myShop">
<div>is loading text here...</div>
</div>
</div>
);
};
export default(Shop);
I'm playing with Contentful! and I'm having trouble with Rich text content field.
I'm using '#contentful/rich-text-types' and #contentful/rich-text-html-renderer modules to customize the way this block is rendered and to display some assets and reference linked in Rich text content.
After calling getEntries in nuxt asyncData function, I've a description data available in my page component.
I'm using documentToHtmlString function with options.
Everything is working fine, but I would like to use a component I have already written (Post.vue), instead of returning the template in ES6 Template Strings.
I know that is possible, but I'm quite new to JS world.
I've tried to require components/post/Post.vue, but I don't know how to use it.
import { BLOCKS } from '#contentful/rich-text-types';
import { documentToHtmlString } from "#contentful/rich-text-html-renderer"
Vue component template where rich text field is rendered
<section class="container">
<div class="columns">
<div class="column">
<div v-html="formatContent(description)" />
</div>
</div>
</section>
I simply call formatContent method to call documentToHtmlString as follow (it works):
methods: {
formatContent(content) {
return documentToHtmlString(content, options)
}
}
And customize documentToHtmlString with options as described in doc:
const embeddedEntryRender = (node) => {
const { data: { target: entry} } = node
const fields = entry.fields
const sys = entry.sys
// LOOK HERE
// const postComponent = require('~/components/post/Post')
return `
<div class="column is-4">
<div class="card">
<div class="card-content">
<div class="media">
<div class="media-content">
<h3 class="title is-4">${fields.title}</h3>
<div class="subtitle is-6">${fields.description}</div>
</div>
</div>
<div class="content">
</div>
</div>
</div>
</div> `
}
const options = {
renderNode: {
[BLOCKS.EMBEDDED_ENTRY]: (node) => embeddedEntryRender(node),
// [BLOCKS.EMBEDDED_ASSET]: (node) => `<custom-component>${customComponentRenderer(node)}</custom-component>`
}
}
No errors detected
--
Thanks a lot
yep you can have a custom vue component in there with a different npm library, I had this same problem.
npm i contentful-rich-text-vue-renderer
in template:
<rich-text-renderer :document="document" :nodeRenderers="renderNode" />
where 'document' is the data sent form contentful, looks like your calling it description. RenderNode is a method described below.
in script:
data () {
return {
renderNode: [INLINES.ASSET_HYPERLINK]: (node, key, h) => {
return h('my-vue-component', { key: hey, props: { myProp: 'blah blah' }},'what I want inside the <my-vue-component> tag'`)
}
}
this might be kind of confusing. So First imprt the richTextRenderer component from that npm library and make sure to declare it in the components section of your vue component. (or gloablly)
Next pass into its 'document' prop the contentful rich text field
if you want custom rendering, pass into the nodeRenders prop a function (I had to declare it in the data section)
My example takes any asset hyperlink type and replaces it with a component of what I want inside the tag
I only got this to work if I globally declared the my-vue-component in the main.js file.
import MyVueComponent from 'wherever/it/is';
Vue.component('my-vue-component', MyVueComponent);
there are more configurations for this, just read the npm libs documentation (though its not great docs, it took my a long time to figure out how to pass props down, I had to read their github code to figure that out lol)
I am having a bear of a time getting my VueJs app to render data from an external API. I've attempted to search for a similar issue, but everything I've found has been of no help.
I'm using the the USDA's nutrition database. When I run the code below, I can see through dev tools that my getNutrients function is making a successful call to the database when I click the button, yet my v-for element won't render any data. If I attempt to simply render nutrients from my data object, I'm able to render all of the raw JSON, just not when I try to render singular items within the v-for element.
Any help with getting the render to work would be greatly appreciated.
Thank you in advance
<template>
<div>
<button #click="getNutrients">Click</button>
<ul>
<li v-for="nutrient in nutrients">{{nutrient.nutrient_id}}</li>
</ul>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'home',
data () {
return {
nutrients: {}
}
},
methods: {
getNutrients: function () {
axios.get('https://api.nal.usda.gov/ndb/nutrients/?format=json&api_key=DEMO_KEY&nutrients=205&nutrients=204&nutrients=208&nutrients=269')
.then(response => {this.nutrients = response.data})
}
}
}
</script>
If it helps, I'm using the Vue Webpack template through the Vue-CLI.
The API's returning a report object, which contains an array of foods, each of which contains an array of nutrients, so you'd need to loop through the foods, then through the nutrients in each food:
<ul>
<li v-for="food in foods">
<h2>{{food.name}}</h2>
<ul>
<li v-for="nutrient in food.nutrients">{{nutrient.nutrient_id}}</li>
</ul>
</li>
</ul>
axios.get(url).then(response => {
this.foods = response.data.report.foods
})