First of, I'm a newbie at Javascript and React.js as you will probably observe. I'm currently trying to train myself.
I'm trying to display a "keyboard" (all letters from A to Z) and am trying to collect the data (the letter displayed) by implementing an onclick event on each letters.
However, even though my onclick event seems to be working, I'm getting an "undefined" answer in the console.
The handleLetterClicked() method is working fine but the handleKeyClicked() is not so I'm doing something wrong but can't get my head around it...
I hope you can help. thx in advance.
This is my keyboard component:
import React from 'react'
import './Keyboard.css'
const alphabet = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
const displayKeyboard = alphabet.map((lettreAlphabet) =>
<div className="keyboardKey">
{lettreAlphabet}
</div>
)
const Keyboard = ({ lettreAlphabet, onClick }) => (
<div className={lettreAlphabet} onClick={() => onClick(lettreAlphabet)}>
<span className="touche">
{displayKeyboard}
{lettreAlphabet}
</span>
</div>
)
export default Keyboard
This is my app:
import React, { Component } from 'react'
import GuessCount from './GuessCount'
import Letter from './Letter'
import Keyboard from './Keyboard'
import './App.css'
class App extends Component {
handleKeyClicked(lettreAlphabet){
console.log(lettreAlphabet, 'clicked')
}
handleLetterClicked(letter){
console.log(letter, 'alsoClicked')
}
render() {
return (
<div className="container">
<div className="pendu">
<GuessCount guesses={0} />
<Letter letter="Z" feedback="visible" onClick={this.handleLetterClicked} />
</div>
<div className="keyboard">
<Keyboard onClick={this.handleKeyClicked}/>
</div>
</div>
)
}
}
export default App;
Related
i am trying to use PrimsJs in a react project, my objetive is create a static template page, and add snippets, i am not sure if is the best option(primsjs) but i am trying to auto-indent the code, because actually my code is rendered in one line
THIS IS MY PAGE
import { MainLayout } from "../components/layouts/MainLayout";
import { Hero1, Hero1Code} from "../theme/blocks/hero/Hero1";
export default function Home() {
return (
<MainLayout>
<h1>Home Page</h1>
<Hero1 />
<Hero1Code />
</MainLayout>
);
}
THIS IS MY PRIMSJS COMPONENT
import React, { useEffect } from "react";
import Prism from "prismjs";
import "prismjs/themes/prism-tomorrow.css";
export default function Code({ code, language }) {
useEffect(() => {
Prism.highlightAll();
}, []);
return (
<div className="Code">
<pre>
<code className={`language-${language}`}>{code}</code>
</pre>
</div>
);
}
THIS IS MY COMPONENT
import React from "react";
import { renderToString } from "react-dom/server";
import Code from "../../../components/prism/code";
export const Hero1 = () => {
return (
<section className="wrapper bg-light">
...
</section>
);
};
export const Hero1Code = () => {
const content = renderToString(<Hero1/>);
return (
<>
<div className="App">
<Code code={content} language="html" />
</div>
</>
);
};
Any help will be very welcome, also i am open to try other package
I don't think that PrismJS has such an option, in my opinion it would be best to just indent the code string before passing it to the <Code /> component.
You could use this library: https://github.com/zebzhao/indent.js
Import it:
import indent from 'indent.js';
And indent the code like this:
const content = indent.html(renderToString(<Hero1/>));
However, looking at your screenshot code example, I can see that you have a lot of divs smashed into one line. In this case, indentation would not really help, as it takes care of the relations between separate lines.
You could take a look at using a library like this, which seems to split code into separate lines.
https://www.npmjs.com/package/pretty
I tried many things. Same code is working in my other project but not in the current one
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import getProductCategories from '../../redux/actions/productCategoryAction'
import "./ProductCategory.css"
export class ProductCategory extends Component {
static propTypes = {
productCategories: PropTypes.array.isRequired
}
componentDidMount() {
console.log('Mounted!');
this.props.getProductCategories();
}
render() {
return (
<div className="main-card-body">
<div className="main-card-container">
{this.props.productCategories.map((pc, i) => {
return (
<div key={i} className="main-card-card" >
<div className="main-card-face main-card-face1">
<div className="main-card-content">
<img src={pc.image} alt={pc.alt} />
</div>
</div>
<div className="main-card-face main-card-face2">
<div className="main-card-content">
<h3> {pc.title}</h3>
<p>{pc.description}</p>
</div>
</div>
</div>
)
})}
</div>
</div>
)
}
}
const mapStateToProps = state => ({
productCategories: state.productCategory.productCategories
})
const mapDispatchToProps = dispatch => {
return {
getProductCategories: () => {
dispatch(getProductCategories())
}
};
};
export default connect(mapStateToProps, mapDispatchToProps)(ProductCategory)
tried without mapDispatchToProps as:
export default connect(mapStateToProps, {getProductCategories})(ProductCategory)
componentDidMount failing without any error, not showing console.log string as well.
Although i crosschecked with each and every means i do have still can't resolve.
enter image description here
Found answer all thanks to Michalis Garganourakis and cubrr
In App.js i was importing this class based component "ProductCategory" with curly braces. importing it without curly braces did the job as i am exporting it as "export default"
Again thanks Michalis Garganourakis and cubrr
Cubrr answered this on the very first go. it took me lot of time to understand this silly thing :D :D
Based on the image you added, the error seems to occur on render function, so the componentDidMount never gets triggered for this exact reason.
Try checking if this.props.productCategories exists before trying to use .map() on it. This should allow render function to run succesfully, and this will then trigger the componentDidMount as per react's lifecycle method order
this.props.productCategories && this.props.productCategories.map((pc, i) ...
Also, try removing the export on your first row, keeping just the export default of your last row where you also make use of connect HOC, like:
class ProductCategory extends Component {
// ...
}
export default connect(mapStateToProps, mapDispatchToProps)(ProductCategory)
I am trying to connect a component to the redux store, but am receiving:
Warning: Failed prop type: The prop 'store.subscribe' is marked as required inConnect(StoreLocation), but its value is 'undefined'.
I have been using redux with this project for awhile now without issue, but this component is erroring out for some reason and I'm clueless as to why at this point :(
The store populates a collection of stores (brick and mortar locations with addresses, phone numbers, etc used for shipping selections) within DeliverySection.js.
Then each StoreLocation.js component will allow the user to view it's info, select it, etc. It's bare bones right now as I am seeing the error even at this basic point. If I switch the export default connect()(StoreLocation) statement with export default StoreLocation it works without issue.
Any ideas?
DeliverySection.js
import React, { Component } from 'react'
import { connect } from 'react-redux'
// Components
import Loader from '../../utils/Loader'
import StoreLocation from './StoreLocation'
// Stote
import { getAllStores } from '../../../store/actions/storeLocation'
import { REACT_APP_SITE_KEY } from '../../../shared/vars'
// CSS
import '../../../css/delivery.css'
class DeliverySection extends Component {
componentDidMount(){
this.props.getAllStores(REACT_APP_SITE_KEY);
}
render() {
const { stores, isLoading } = this.props
return (
<div>
<div className="delivery-heading">
<h2>Choose a store near you:</h2>
<button className="btn btn--red btn--heading" name="ship-to-address">Ship To An Address</button>
</div>
<div>
{isLoading ? (
<Loader />
) : (
!isLoading && !!stores ? (
stores.map((store, i) => <StoreLocation key={i} store={store} />)
) : (
<div>
There are no store locations to deliver to.<br />
Ship to an address!
</div>
)
)}
</div>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
stores: state.storeLocation.stores,
isLoading: state.storeLocation.isLoading
}
}
export default connect(mapStateToProps, { getAllStores })(DeliverySection)
StoreLocation.js
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { setDelivery } from '../../../store/actions/checkout'
class StoreLocation extends Component {
render() {
const { store } = this.props
return (
<div className="store-location">
<div className="store-row">
<div className="store-col"><div className="store-title">{store.title}</div></div>
<div className="store-col">
{store.address}
{store.formatted_location &&
<div>{store.formatted_location}</div>
}
</div>
<div className="store-col">
<button className="btn select-store" onClick={() => this.props.setDelivery(store)}>Ship to this store<span className="icon-checkmark"></span></button>
</div>
</div>
<div className="store-row">
<div className="store-col">
<div className="ajax-message" data-hbs-id="postal-{id}"></div>
<input type="hidden" id={`postal-${store.id}`} value={store.postal} />
<div className="see-map"><span className="icon-location"></span>See on map</div>
</div>
<div className="store-col">{store.description}</div>
<div className="store-col"></div>
</div>
{store.phone &&
<div className="store-row">
<div className="store-col"></div>
<div className="store-col">{store.phone}</div>
<div className="store-col"></div>
</div>
}
</div>
)
}
}
export default connect(null, { setDelivery })(StoreLocation)
// export default StoreLocation
It's because you are using store as your prop name. You are overwriting the prop react-redux passes through the HOC. Since, the object you pass for store does not have a subscribe method, you get this error.
If you change the name of your prop, you'll be in good shape again.
After doing a quick Google I came across this post here.
That problem, which is similar to yours, was based on the way the store was exported. Have a look at that and see if gets you going in the right direction. I can't comment without seeing your store export code.
On a personal preference note I would use something other than 'store' as the variable for each instance in your map of stores. Since you are using Redux it could get semantically confusing whether you are referring to the Redux store or an instance of a store object.
I think it's fine that you are having StoreLocation handle the setting of delivery. I'm a big fan of breaking things down into smaller components.
Finally, just because I happen to notice it, you have a misspelling in DeliverySection. Line 8 reads //Stote. I'm guessing you meant //Store.
Apologies in advance as I think this should go under the comment section, but the code you pasted looks alright. You say disconnecting the StoreLocation component fixes things. Is there a reason you want to connect that component? You're not mapping any state to props or using dispatch in that component.
Otherwise, make sure that you're correctly initializing the store with the reducers you need and check that the modules you're using are imported properly - especially the ones you are passing to the connect function (getAllStores).
I'm learning React using JSX and ES6 and I've got a pretty decent handle on how to create components and route to different views using ReactRouter4.
What I still haven't been able to figure out is for example how i can create an Admin page where I input the details of a work for my portfolio and have all the works render on the another page, presumably Portfolio page.
Here's what I've got.
App.js loads the Portfolio.js component
import React from 'react';
import Navigation from './Navigation';
import Title from './Title';
import Portfolio from './Portfolio';
class App extends React.Component {
render() {
return(
<div className="container-fluid">
<div className="container">
<div className="row">
<div className="col-sm-12">
<Navigation />
<Title title="kuality.io"/>
<section className="app">
<Portfolio works={this.props.works} />
</section>
</div>
</div>
</div>
</div>
)
}
}
export default App;
The Portfolio.js component has a constructor to bind a unique method named addWork(), the React methods componentWillMount() and componentWillUnmount() to handle state, and the default render(). One more thing to mention about this component is that it's calling a component called ../base which has all the details to an online DB via Firebase. So if that's relevant as to where it is place, then take that into consideration otherwise don't sweat it.
import React from 'react';
import Work from './Work';
import Admin from './Admin';
import base from '../base';
class Portfolio extends React.Component {
constructor() {
super();
this.addWork = this.addWork.bind(this);
// getInitialState
this.state = {
works: {}
};
}
componentWillMount() {
this.ref = base.syncState(`/works`
, {
context: this,
state: 'works'
})
}
componentWillUnmount() {
base.removeBinding(this.ref);
}
addWork(work) {
// update our state
const works = {...this.state.works};
// add in our new works with a timestamp in seconds since Jan 1st 1970
const timestamp = Date.now();
works[`work-${timestamp}`] = work;
// set state
this.setState({ works });
}
render() {
return(
<div>
<section className="portfolio">
<h3>Portfolio</h3>
<ul className="list-of-work">
{
Object
.keys(this.state.works)
.map(key => <Work key={key} details={this.state.works[key]}/>)
}
</ul>
</section>
</div>
)
}
}
export default Portfolio;
Inside of the Object i'm mapping through the Work component that is just a list item I have made another component for and isn't really relevant in the question.
Finally I have the Admin.js and AddWorkForm.js components. I abstracted the AddWorkForm.js so that I could use it elsewhere if need be, basically the main idea behind React Components, so that's why I chose to do it that way.
import React from 'react';
import Title from './Title';
import AddWorkForm from './AddWorkForm';
class Admin extends React.Component {
constructor() {
super();
this.addWork = this.addWork.bind(this);
// getInitialState
this.state = {
works: {}
};
}
addWork(work) {
// update our state
const works = {...this.state.works};
// add in our new works with a timestamp in seconds since Jan 1st 1970
const timestamp = Date.now();
works[`work-${timestamp}`] = work;
// set state
this.setState({ works });
}
render() {
return(
<div className="container-fluid">
<div className="container">
<div className="row">
<div className="col-sm-12">
<Title title="Admin"/>
<section className="admin">
<AddWorkForm addWork={this.addWork} />
</section>
</div>
</div>
</div>
</div>
)
}
}
export default Admin;
and the AddWorkForm.js component which is basically a form that onSubmit creates and object and resets the form
import React from 'react';
class AddWorkForm extends React.Component {
createWork(event) {
event.preventDefault();
console.log('Creating some work');
const work = {
name: this.name.value,
desc: this.desc.value,
image: this.image.value
}
this.props.addWork(work);
this.workForm.reset();
}
render() {
return(
<form ref={(input) => this.workForm = input} className="work-edit form-group" onSubmit={(e) => this.createWork(e)}>
<input ref={(input) => this.name = input} type="text" className="form-control" placeholder="Work Title"/>
<textarea ref={(input) => this.desc = input} type="text" className="form-control" placeholder="Work Description"></textarea>
<input ref={(input) => this.image = input} type="text" className="form-control" placeholder="Work Image"/>
<button type="submit" className="btn btn-primary">+Add Work</button>
</form>
)
}
}
export default AddWorkForm;
Here is the file that includes where I'm using ReactRouter:
import React from 'react';
import { render } from 'react-dom';
// To render one method from a package user curly brackets, you would have to know what method you wan though
import { BrowserRouter, Match, Miss} from 'react-router';
import './css/normalize.css';
import './css/bootstrap.css';
import './css/style.css';
// import '../js/bootstrap.js';
import App from './components/App';
import WorkItem from './components/WorkItem';
import Capability from './components/Capability';
import Connect from './components/Connect';
import NotFound from './components/NotFound';
import Admin from './components/Admin';
const Root = ()=> {
return(
<BrowserRouter>
<div>
<Match exactly pattern="/" component={App} />
<Match pattern="/work/:workId" component={WorkItem} />
<Match exactly pattern="/capability" component={Capability} />
<Match exactly pattern="/connect" component={Connect} />
<Match exactly pattern="/admin" component={Admin} />
<Miss component={NotFound} />
</div>
</BrowserRouter>
)
}
render (<Root />, document.querySelector('#main'));
So here's what I've tried and failed to accomplish, and it's likely some kind of this.props solution that I haven't been able to define, I need to create the work in Admin.js component, which creates the object and then have it throw that object to Portfolio.js component so it can render it via the Work.js component and it doesn't add the object to the DB.
This works when i put all the components on the same page, which isn't ideal because then anyone accessing my Portfolio could add a work. Sure I could start the process of learning authentication and how to make that component appear or disappear based on user credentials, but I'd much rather also learn the very valuable skill of being able to have my admin page on a separate view all together because I see another application for learning to do so.
Would love to hear others opinions on this and where they may be able to determine I'm failing here.
Btw, I realize I have other components like Nav.js and Title.js but they are not necessary in order to illustrate the example.
Thank you.
You can pass components as props and when using React Router you can have named components.
For data sharing between siblings is better advised to have the data on a parent component although you could use context, but this is not advised and may be unacessible on future versions.
If you need to create something on another component (don't know why) you could pass a function that would render it.
I edited code that was working perfectly fine, until I added new code to make the button clicking work from video to video. I just can't find the error, and the terminal is not picking it up either.
Can someone tell me why the ./video_list_item.js is not being recognized anymore?
Attached is the parent, and 2 child components, though I have 5 total components the error is definitely only in one of the two.
index.js
import React, {Component } from 'react';
import ReactDOM from 'react-dom';
import YTSearch from 'youtube-api-search';
import SearchBar from './components/searchbar';
import VideoList from './components/video_list';
import VideoDetail from './components/video_detail';
const API_KEY = 'AIzaSyAi1CzVpifuFUDVQf3dzrTu3mwJDP2n8r8';
class App extends Component {
constructor(props){
super(props);
//Do i expect this component to play any type of state? aka pass props
this.state= {
videos: [],
selectedVideo:null
};
// ^proper name can be anything
YTSearch({key: API_KEY, term: 'surfboards'}, (videos) => {
// console.log(data);
this.setState({ videos:videos,
selectedVideo: videos[0]
});
}); // this.setState({videos : vidoos});
}
render (){
return (
<div>
<SearchBar />
<VideoDetail video={this.state.selectedVideo} />
<VideoList
onVideoSelect={selectedVideo => this.setState({selectedVideo}) }
videos={this.state.videos} />
</div>
);
}
}
ReactDOM.render(<App />, document.querySelector('.container'));
video_list.js
//video list file. JS.react
import React from 'react';
import VideoListItem from './video_list_item';
const VideoList = (props) => {
// ^props is made args here because videos var is passed
// in index.js into VideoList function(with state).
const videoItems = props.videos.map((video) => {
return (
<VideoListItem
onVideoSelect={props.onVideoSelect}
key={video.etag}
video ={video} />
);
});
return (
<ul className="col-md-4 list-group">
{videoItems}
</ul>
);
};
export default VideoList;
video_list.item.js
//video list item file. JS.react
import React from 'react';
const VideoListItem = ({video, onVideoSelect}) => {
const imageUrl = video.snippet.thumbnails.default.url;
// can see this in console log
return (
<li onClick={() => onVideoSelect{video} }className="list-group-item">
<div className ="video-list media">
<div className ="media-left">
<img className="media-object" src = {imageUrl}/>
</div>
<div className="media-body">
<div className="media-heading"> {video.snippet.title} </div>
</div>
</div>
</li>
);
};
export default VideoListItem;
I can post the error message I get in the dev tools, but it literally just says one thing. This is the error message => Cannot find module "./video_list_item"
Also, no files were moved around at all, the code was edited and that created the error message. Thanks for anyone who sincerely answers this question!
<li onClick={() => onVideoSelect{video} }className="list-group-item">
The error is the {video} should actually be in parenthesis like so (video).
correct code is:
<li onClick={() => onVideoSelect(video) }className="list-group-item">.
Note: The {} makes it so the child component is not recognized by the parent for some strange reason. Thanks to all those who helped in answering!