This question already has answers here:
When to use ES6 class based React components vs. functional ES6 React components?
(7 answers)
Closed last month.
I have this error
error message : Cannot find name 'render'.ts(2304)
Then I did googling but couldn't find anything about render.
I don't know what's wrong with 'render'.
import React from "react";
import HoverButtons from "./HoverButtons";
const evStop = (ev:any) => {
ev.preventDefault();
ev.stopPropagation();
ev.nativeEvent.stopImmediatePropagation();
};
function HoverMenus () {
const state = { hiddenPopupMenu: true };
const toggle = () => {
this.setState({ hiddenPopupMenu: !this.state.hiddenPopupMenu });
};
const clkBtn = (ev:any, msg:any) => {
evStop(ev);
this.props.flashFn(msg);
};
// ***error message : Cannot find name 'render'.ts(2304)***
render() {
const p = {
funcs: {
interested: (e:any) => this.clkBtn(e, "interested"),
}
};
return (
<div className="whenhovered" onClick={this.toggle}>
{this.state.hiddenPopupMenu && (
<div>
<div className="mt-5 pt-5" />
<div className="mt-5" />
<HoverButtons
txt="LIKE"
icon="thumbs-up"
clicked={p.funcs.interested}
/>
</div>
)}
</div>
);
}
}
export default HoverMenus;
You mixed between a class component and a function component,
To use class component convert your function to a class and add extends React.Component to your class:
class HoverMenus extends React.Component {
}
To use function component, you will need to change the syntax acording to https://reactjs.org/docs/components-and-props.html
The 'render' is a class component method. It does not work in functional components.
Try this:
import {useState} from 'react'
function HoverMenus (props) {
const [hiddenPopupMenu, setHiddenPopupMenu] = useState(true)
const toggle = () => {
setHiddenPopupMenu(!hiddenPopupMenu);
};
const clkBtn = (ev:any, msg:any) => {
ev.stopPropagation();
props.flashFn(msg);
};
const p = (e:any) => clkBtn(e, "interested");
return (
<div className="whenhovered" onClick={toggle}>
{hiddenPopupMenu && (
<div>
<div className="mt-5 pt-5" />
<div className="mt-5" />
<HoverButtons
txt="LIKE"
icon="thumbs-up"
clicked={p}
/>
</div>
)}
</div>
);
}
export default HoverMenus;
Related
I am starting with React. I am trying to send a var and function to my component. I know that it is a bad practice to use :any that is why I want to change for a proper way.
I am doing a modal and I am sending the data to my component this way. I am using useState
Datatable.tsx
import { useEffect, useMemo, useState } from "react";
import Modal from "../modal/Modal";
const Datatable = () => {
const [show, setShow] = useState<boolean>(false);
return (
<div>
<Modal show={show} closeModal={() => setShow(false)} />
<button onClick={() =>setShow((s) => !s)}>
Open Modal
</button>
<tableStuff/>
<div/>
);
Modal.tsx
import "./modal.scss";
import React from "react";
import ReactDOM from "react-dom";
const Modal = (props:any) => {
const portal = document.getElementById("portal");
if (!portal) {
return null;
}
if (!props.show) {
return null;
}
return ReactDOM.createPortal(
<>
<div className="modal" onClick={props.closeModal}>
<div className="content">
<h2>Simple modal</h2>
</div>
</div>
</>,
portal
);
};
export default Modal;
I have seen this on tons of videos, but the following piece of code does not work for me.
I am getting this error Binding element 'show' implicitly has an 'any' type and Binding element 'closeModal' implicitly has an 'any' type
//...
const Modal = ({show, closeModal}) => {
if (show) {
return null;
}
//...
return ReactDOM.createPortal(
<>
<div className="modals" onClick={closeModal}>
<button onClick={closeModal}>Close</button>
</div>
</>,
portal
);
}
Is something else I am missing in order to not use (props:any)? Any help or suggestion would be nice.
interface ModalProps {
show: boolean;
closeModal: () => void;
}
const Modal = ({show, closeModal}: ModalProps) => {
I am trying to render a popup when a card is clicked. My problem is that I can't get the showPopup function running on click of the card component.
//... all required imports
class App extends Component {
constructor() {
super();
this.state = {
monsters: [],
searchField: ''
};
}
componentDidMount() {
// Fetches monsters and updates the state (working fine)
}
showPopup = () => {
console.log(2);
};
render() {
const { monsters, searchField } = this.state;
const filteredMonsters = monsters.filter(monster => monster.name.toLowerCase().includes(searchField.toLowerCase()));
return (
<div className="App">
<CardList className="name" monsters={filteredMonsters} showPopup={e => this.showPopup(e)} />
</div>
);
}
}
Following is the code for my CardList component
import React from 'react';
import { Card } from '../card/card.comp';
import './card-list.styles.css';
export const CardList = props => {
return (
<div className="card-list">
{props.monsters.map(monster => (
<Card key={monster.id} monster={monster} onClick={props.showPopup} />
))}
</div>
);
};
The onclick function above is not working as expected. Please help me find out the problem.
EDIT The code for card component
import React from 'react';
import './card.styles.css';
export const Card = props => {
return (
<div className="card-container">
<img src={`https://robohash.org/${props.monster.id}?set=5&size=150x150`} alt="Monster" />
<h2 key={props.monster.id}>{props.monster.name}</h2>
<p>{props.monster.email}</p>
</div>
);
};
Let's say I have a component tree as follows
<App>
</Header>
<Content>
<SelectableGroup>
...items
</SelectableGroup>
</Content>
<Footer />
</App>
Where SelectableGroup is able to select/unselect items it contains by mouse. I'm storing the current selection (an array of selected items) in a redux store so all components within my App can read it.
The Content component has set a ref to the SelectableGroup which enables me to clear the selection programatically (calling clearSelection()). Something like this:
class Content extends React.Component {
constructor(props) {
super(props);
this.selectableGroupRef = React.createRef();
}
clearSelection() {
this.selectableGroupRef.current.clearSelection();
}
render() {
return (
<SelectableGroup ref={this.selectableGroupRef}>
{items}
</SelectableGroup>
);
}
...
}
function mapStateToProps(state) {
...
}
function mapDispatchToProps(dispatch) {
...
}
export default connect(mapStateToProps, mapDispatchToProps)(Content);
I can easily imagine to pass this clearSelection() down to Contents children. But how, and that is my question, can I call clearSelection() from the sibling component Footer?
Should I dispatch an action from Footer and set some kind of "request to call clear selection" state to the Redux store? React to this in the componentDidUpdate() callback in Content and then immediately dispatch another action to reset this "request to call clear selection" state?
Or is there any preferred way to call functions of siblings?
You can use ref to access the whole functions of Content component like so
const { Component } = React;
const { render } = ReactDOM;
class App extends Component {
render() {
return (
<div>
<Content ref={instance => { this.content = instance; }} />
<Footer clear={() => this.content.clearSelection() } />
</div>
);
}
}
class Content extends Component {
clearSelection = () => {
alert('cleared!');
}
render() {
return (
<h1>Content</h1>
);
}
}
class Footer extends Component {
render() {
return (
<div>Footer <button onClick={() => this.props.clear()}>Clear</button>
</div>
);
}
}
render(
<App />,
document.getElementById('app')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
I think the context API would come handy in this situation. I started using it a lot for cases where using the global state/redux didn't seem right or when you are passing props down through multiple levels in your component tree.
Working sample:
import React, { Component } from 'react'
export const Context = React.createContext()
//***************************//
class Main extends Component {
callback(fn) {
fn()
}
render() {
return (
<div>
<Context.Provider value={{ callback: this.callback }}>
<Content/>
<Footer/>
</Context.Provider>
</div>
);
}
}
export default Main
//***************************//
class Content extends Component {
render() {
return (
<Context.Consumer>
{(value) => (
<div onClick={() => value.callback(() => console.log('Triggered from content'))}>Content: Click Me</div>
)}
</Context.Consumer>
)
}
}
//***************************//
class Footer extends Component {
render() {
return (
<Context.Consumer>
{(value) => (
<div onClick={() => value.callback(() => console.log('Triggered from footer'))}>Footer: Click Me</div>
)}
</Context.Consumer>
)
}
}
//***************************//
Assuming content and footer and in there own files (content.js/footer.js) remember to import Context from main.js
According to the answer of Liam , in function component version:
export default function App() {
const a_comp = useRef(null);
return (
<div>
<B_called_by_a ref={a_comp} />
<A_callB
callB={() => {
a_comp.current.f();
}}
/>
</div>
);
}
const B_called_by_a = forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({
f() {
alert("cleared!");
}
}));
return <h1>B. my borther, a, call me</h1>;
});
function A_callB(props) {
return (
<div> A I call to my brother B in the button
<button onClick={() => { console.log(props); props.callB();}}>Clear </button>
</div>
);
}
you can check it in codesandbox
One way I use to call the sibling function is to set a new date.
Let me explain more:
In their parent we have a function that set new date in a state (the state's name is something like "refresh date" or "timestamp" or something similar).
And you can pass state to sibling by props and in sibling component you can use useEffect for functional components or componentDidUpdate for class components and check when the date has changed, call your function .
However you can pass the new date in redux and use redux to check the date
const Parent = () => {
const [refreshDate, setRefreshDate] = useState(null);
const componentAClicked = () => setRefreshDate(new Date())
return (
<>
<ComponentA componentAClicked={componentAClicked}/>
<ComponentB refreshDate={refreshDate}/>
</>
}
const ComponentA = ({ componentAClicked}) => {
return (
<button onClick={componentAClicked}>click to call sibling function!!<button/>
)
}
const ComponentB = ({ refreshDate }) => {
useEffect(()=>{
functionCalledFromComponentA()
},[refreshDate]
const functionCalledFromComponentA = () => console.log("function Called")
return null
}
Functional components & TypeScript
Note 1: I've swapped useRef for createRef.
Note 2: You can insert the component's prop type in the second type parameter here: forwardRef<B_fns, MyPropsType>. It's confusing because the props & ref order are reversed.
type B_fns = {
my_fn(): void;
}
export default function App() {
const a_comp = createRef<B_fns>();
return (
<div>
<B_called_by_a ref={a_comp} />
<A_callB
callB={() => {
a_comp.current?.my_fn();
}}
/>
</div>
);
}
const B_called_by_a = forwardRef<B_fns>((props, ref) => {
useImperativeHandle(ref, () => ({
my_fn() {
alert("cleared!");
}
}));
return <h1>B. my borther, a, call me</h1>;
});
function A_callB(props) {
return (
<div> A I call to my brother B in the button
<button onClick={() => { console.log(props); props.callB();}}>Clear </button>
</div>
);
}
I' m new to React and I'm building a simple React app that displays all the nations of the world on the screen and a small search bar that shows the data of the searched nation.
Here an image of the site
But I don't know how to show the country you want to click in the scrollbar.
Here the app.js code:
import React, { Component } from 'react';
import './App.css';
import NavBar from '../Components/NavBar';
import SideBar from './SideBar';
import CountryList from '../Components/SideBarComponents/CountryList';
import Scroll from '../Components/SideBarComponents/Scroll';
import Main from './Main';
import SearchCountry from '../Components/MainComponents/SearchCountry';
import SearchedCountry from '../Components/MainComponents/SearchedCountry';
import Datas from '../Components/MainComponents/Datas';
class App extends Component {
constructor() {
super();
this.state = {
nations: [],
searchField: '',
button: false
}
}
onSearchChange = (event) => {
this.setState({searchField: event.target.value});
console.log(this.state.searchField)
}
onClickChange = () => {
this.setState(prevsState => ({
button: true
}))
}
render() {
const {nations, searchField, button, searchMemory} = this.state;
const searchedNation = nations.filter(nation => {
if(button) {
return nation.name.toLowerCase().includes(searchField.toLowerCase())
}
});
return (
<div>
<div>
<NavBar/>
</div>
<Main>
<div className='backgr-img'>
<SearchCountry searchChange={this.onSearchChange} clickChange={this.onClickChange}/>
<SearchedCountry nations={searchedNation}/>
</div>
<Datas nations={searchedNation}/>
</Main>
<SideBar>
<Scroll className='scroll'>
<CountryList nations={nations} clickFunc/>
</Scroll>
</SideBar>
</div>
);
}
componentDidMount() {
fetch('https://restcountries.eu/rest/v2/all')
.then(response => response.json())
.then(x => this.setState({nations: x}));
}
componentDidUpdate() {
this.state.button = false;
}
}
export default App;
The countryList:
import React from 'react';
import Images from './Images';
const CountryList = ({nations, clickFunc}) => {
return (
<div className='container' style={{display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(115px, 3fr))'}}>
{
nations.map((country, i) => {
return (
<Images
key={country.numericCode}
name={country.name}
flag={country.flag}
clickChange={clickFunc}
/>
);
})
}
</div>
)
}
export default CountryList;
And the images.js:
import React from 'react';
import './images.css'
const Images = ({name, capital, region, population, flag, numericCode, clickChange}) => {
return (
<div className='hover bg-navy pa2 ma1 tc w10' onClick={clickChange = () => name}>
<img alt='flag' src={flag} />
<div>
<h6 className='ma0 white'>{name}</h6>
{capital}
{region}
{population}
{numericCode}
</div>
</div>
);
}
export default Images;
I had thought of using the onClick event on the single nation that was going to return the name of the clicked nation. After that I would have entered the name in the searchField and set the button to true in order to run the searchedNation function.
I thank anyone who gives me an answer in advance.
To keep the actual structure, you can try using onClickChange in Images:
onClickChange = (newName = null) => {
if(newName) {
this.setState(prevsState => ({
searchField: newName
}))
}
// old code continues
this.setState(prevsState => ({
button: true
}))
}
then in onClick of Images you call:
onClick={() => {clickChange(name)}}
Or you can try as well use react hooks (but this will require some refactoring) cause you'll need to change a property from a parent component.
With that you can use useState hook to change the value from parent component (from Images to App):
const [searchField, setSearchField] = useState('');
Then you pass setSearchField to images as props and changes the searchField value when Images is clicked:
onClick={() => {
clickChange()
setSearchField(name)
}}
This question already has an answer here:
List elements not rendering in React [duplicate]
(1 answer)
Closed 24 days ago.
I am going through a react course and currently learning react's lifecycle method. So far, I have been able to call the API using componentDidMount and have set the state. However, I can't seem to get the card components to show the images in the cardlist div. I'm sure I've done it correctly (looping through the state and creating a Card component with the props).
import react, {Component} from 'react';
import axios from 'axios';
import Card from './Card';
const api = ' https://deckofcardsapi.com/api/deck/';
class CardList extends Component {
state = {
deck: '',
drawn: []
}
componentDidMount = async() => {
let response = await axios.get(`${api}new/shuffle`);
this.setState({ deck: response.data })
}
getCards = async() => {
const deck_id = this.state.deck.deck_id;
let response = await axios.get(`${api}${deck_id}/draw/`);
let card = response.data.cards[0];
this.setState(st => ({
drawn: [
...st.drawn, {
id: card.code,
image: card.image,
name: `${card.value} of ${card.suit}`
}
]
}))
}
render(){
const cards = this.state.drawn.map(c => {
<Card image={c.image} key={c.id} name={c.name} />
})
return (
<div className="CardList">
<button onClick={this.getCards}>Get Cards</button>
{cards}
</div>
)
}
}
export default CardList;
import react, {Component} from 'react';
class Card extends Component {
render(){
return (
<img src={this.props.image} alt={this.props.name} />
)
}
}
export default Card;
import CardList from './CardList';
function App() {
return (
<div className="App">
<CardList />
</div>
);
}
export default App;
Your map function:
const cards = this.state.drawn.map(c => {
<Card image={c.image} key={c.id} name={c.name} />
})
does not return anything. So the result of this code is an array of undefined.
You have two options:
Add return:
const cards = this.state.drawn.map(c => {
return <Card image={c.image} key={c.id} name={c.name} />
})
Wrap in (), not {}:
const cards = this.state.drawn.map(c => (
<Card image={c.image} key={c.id} name={c.name} />
))
You should return the card component inside the map
const cards = this.state.drawn.map(c => {
return <Card image={c.image} key={c.id} name={c.name} />
})