Trying to show a random picture from Unsplash - reactjs

Hi this is my first React app im trying to build.
I'm trying to show a random image in React but i can't get
the image to show.
import React from 'react';
function ImageList(props) {
console.log(props);
return (
<div><img src={props} alt="cat"/></div>
);
}
export default ImageList;
the props looks like this:
props: "https://images.unsplash.com/photo-1568152950566-c1bf43f4ab28?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzNTkxNzd8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NjE3NTY3NTc&ixlib=rb-1.2.1&q=80&w=400"
When i inspect the img it says object Object.
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import './App.css'
import ImageList from './ImageList';
const App = () => {
const [cats, setCats] = useState("");
async function onSearchSubmit(term) {
const response = await axios.get('https://api.unsplash.com/photos/random/',{
params: { query: term},
headers:{
Authorization: 'Client-ID //here i just where i put my key in '
}
});
setCats(response.data.urls.small);
}
return(
<div className='App'>
<button onClick={() => {onSearchSubmit("cat")} }>
Show a cat picture
</button>
<ImageList props = {cats}/>
</div>
);}
export default App;
This is the rest of the code.
I am thankful for your help. Cheers!

props it's just the name of your prop.
Look at this row:
<ImageList props = {cats}/>
You shouldn't use the props name for your props. Use some meaningful name instead, like cats
<ImageList cats = {cats}/>
// And in ImageList
const ImageList = ({cats}) => {
// do something with cats. Now it must be a string
}
OR
// props is an object
const ImageList = (props) => {
const cats = props.cats
// do something with cats. Now it must be a string
}

Related

Keep track of another components state

I have a bit of a basic React question that I am having trouble googling.
I have this component which is managing the state of maximize:
import React from 'react'
import { useState } from 'react';
import './Panel.scss'
import { AiFillExperiment, AiOutlineExpandAlt } from "react-icons/ai";
const Panel = ({title}) => {
const [maximize, setMaximize] = useState(false);
return (
<div className='panel'>
<AiFillExperiment />
<p>{title}</p>
<AiOutlineExpandAlt onClick={() => setMaximize(!maximize)} />
</div>
)
}
export default Panel
and this component that needs to be able to see the value of that state:
import './App.scss';
import { useEffect, useState } from 'react';
import ReactMarkdown from 'https://esm.sh/react-markdown#7'
import remarkBreaks from 'https://esm.sh/remark-breaks#3'
import Panel from './components/Panel'
function App() {
const [markdown, setMarkdown] = useState(``)
const placeholder =
`# Welcome to my React Markdown Previewer!
## This is a sub-heading...
### And here's some other cool stuff:
Here's some code, \`<div></div>\`, between 2 backticks.
\`\`\`
// this is multi-line code:
function anotherExample(firstLine, lastLine) {
if (firstLine == '\`\`\`' && lastLine == '\`\`\`') {
return multiLineCode;
}
}
\`\`\`
You can also make text **bold**... whoa!
Or _italic_.
Or... wait for it... **_both!_**
And feel free to go crazy ~~crossing stuff out~~.
There's also [links](https://www.freecodecamp.org), and
> Block Quotes!
And if you want to get really crazy, even tables:
Wild Header | Crazy Header | Another Header?
------------ | ------------- | -------------
Your content can | be here, and it | can be here....
And here. | Okay. | I think we get it.
- And of course there are lists.
- Some are bulleted.
- With different indentation levels.
- That look like this.
1. And there are numbered lists too.
1. Use just 1s if you want!
1. And last but not least, let's not forget embedded images:
![freeCodeCamp Logo](https://cdn.freecodecamp.org/testable-projects-fcc/images/fcc_secondary.svg)
`;
useEffect(() => {
setMarkdown(placeholder)
}, [placeholder])
return (
<div className="App">
{/* Editor Container */}
<div
className={'editor-container'}
>
<Panel title='Editor' />
<textarea id='editor' onChange={(e) => setMarkdown(e.target.value)} rows="" cols="">{placeholder}</textarea>
</div>
{/* Preview Container */}
<div className='preview-container'>
<Panel title='Preview' />
<div id='preview'>
<ReactMarkdown children={markdown} remarkPlugins={[remarkBreaks]} />
</div>
</div>
</div>
);
}
export default App;
How do I go about doing this? I realize I could have it all in one component, but I would like to know how to do it with two separate components.
Thanks in advance!
Through useState + props (less recommended)
You can do that by having that state in your App component and passing the setState as a property
const App = () => {
const [maximize, setMaximize] = useState(false);
const handleToggle = (newState) => {
setState(newState)
}
return (
<div>
<Panel toggleState={toggleState} maximize={maximize} />
</div>
)
}
And in your Panel component:
const Panel = ({toggleState, maximize}) => {
const handleToggle = () => {
toggleState(!maximize)
}
return (
<AiOutlineExpandAlt onClick={handleToggle} />
)
}
Through useContext hook
useContext allows you to store variables and access them on all child components within that context provider.
MaximizeProvider.js
import React, {useState, useContext} from "react";
//creating your contexts
const MaximizeContext = React.createContext();
const MaximizeUpdateContext = React.createContext();
// create a custom hook
export const useUpdate = () => {
return useContext(MaximizeUpdateContext)
}
export const useMaximize = () => {
return usecContext(MaximizeContext)
}
//creating your component that will wrap the child components
const MaximizeProvider = ({children}) => {
const [maximize, setMaximize] = useState(false)
// Your toggle to switch the state
const toggle = () => {
setMaximize(prevState => !prevState)
}
return (
<MaximizeContext.Provider value={maximize}>
<MaximizeUpdateContext.Provider value={toggle}>
{children}
</MaximizeUpdateContext.Provider>
</MaximizeContext.Provider>
)
}
export {MAximizeProvider}
Both providers allow you to access both the state and the setState
App.js
import React, {useState} from "react";
// your context component
import {MaximizeProvider} from "./MaximizeProvider";
// a button component
import {ButtonComponent} from "./ButtonComponent";
const App = () => {
return (
<>
<MaximizeProvider>
<ButtonComponent/>
</MaximizeProvider>
< />
);
}
export {App};
in the App, you are wrapping the elements that need your context.
as long as the elements and even children of children are in the wrap, it would have access to it the same way as in the button component.
ButtonComponent.js
import {useMaximize, useUpdate} from "./MaximizeProvider";
const ButtonComponent = () => {
const toggle = useUpdate();
const state = useMaximize()
return (
<button onClick={toggle}>Click</button>
);
}
export {ButtonComponent};
I hope this helps, I am not an expert, so there might be better ways to do it, but this seems to work for me.
Use redux or react context please,
props drilling is bad practice
https://reactjs.org/docs/context.html
https://redux.js.org/

Unable to run the function from the context

I have a context, I import it into my functional component:
import { TaskContexts } from "../../../contexts";
The context stores data and functions.
The data comes from the context and is displayed on the site.
const {
editTodo,
setEditID,
toggleTodoCompletion,
editID,
editTodoHandler,
removeTodo,
state,
text,
isEditError,
} = useContext(TaskContexts);
But!
<button onClick={() => editTodo(todo.id)}>
<img src={editIcon} alt="edit button"></img>
</button>
When I try to call the editTodo function, It fails with the following error:
Uncaught TypeError: editTodo is not a function
How to fix this error?
UPD.
Full component code
import React, { useState } from 'react';
import ACTION_TYPES from '../ToDo/reducer/actionTypes';
import RenderedTable from './RenderedTable';
import styles from './TaskList.module.scss';
import allIcon from '../../icons/all.svg';
import completedIcon from '../../icons/completed.svg';
import notCompletedIcon from '../../icons/notCompleted.svg';
import mona from '../../icons/mona.gif';
import { TODO_TASK_CHEMA } from '../../utils/validationSchemas';
import { TaskContexts } from '../../contexts';
const TaskList = props => {
const {
reducerData: [state, dispatch],
} = props;
const [editID, setEditID] = useState(null);
const [editText, setEditText] = useState(null);
const [isEditError, setIsEditError] = useState(false);
const [mode, setMode] = useState('All');
const removeTodo = id => {
dispatch({ type: ACTION_TYPES.REMOVE, id });
};
const toggleTodoCompletion = id => {
dispatch({ type: ACTION_TYPES.TOGGLE, id });
};
const editTodo = id => {
const text = editText.trim();
try {
TODO_TASK_CHEMA.validateSync({ text });
} catch (e) {
setIsEditError(true);
throw new Error(e);
}
setIsEditError(false);
setEditID(null);
dispatch({ type: ACTION_TYPES.EDIT, id, text });
setEditText(null);
};
const editTodoHandler = ({ target: { value } }) => {
setEditText(value);
};
const contextsValues = {
editID,
setEditID,
editText,
setEditText,
isEditError,
setIsEditError,
mode,
setMode,
state
};
return (
<TaskContexts.Provider value={contextsValues}>
<div className={styles.container}>
{state.todos.length === 0 ? (
<div>
<h2 className={styles.noTask}>No tasks =)</h2>
<img src={mona} alt='mona gif' />
</div>
) : (
<>
<button
className={styles.section}
onClick={() => {
setMode('All');
}}
>
<img src={allIcon} alt='all button' />- All
</button>
<button
className={styles.section}
onClick={() => {
setMode('Completed');
}}
>
<img src={completedIcon} alt='completed button' />- Completed
</button>
<button
className={styles.section}
onClick={() => {
setMode('NotCompleted');
}}
>
<img src={notCompletedIcon} alt='not completed button' />- Not
completed
</button>
<RenderedTable
editTodo={editTodo}
setEditID={setEditID}
toggleTodoCompletion={toggleTodoCompletion}
editID={editID}
editTodoHandler={editTodoHandler}
removeTodo={removeTodo}
state={state}
mode={mode}
isEditError={isEditError}
/>
</>
)}
</div>
</TaskContexts.Provider>
);
};
export default TaskList;
All functions on this component do not work. But these are functions. I don't understand why React doesn't think so.
You need to do 3 things to pass the context values successfully:
Place the Context Provider at least one level above the Consuming Component.
Create Your Context, Declare all variables and methods within the Context, and Export the Context's Provider after passing the value Prop.
Consume the Context Values by importing the useContext() hook in TaskList.jsx/TaskList.js and calling it on the Provider object.
Place the Context Provider at least one level above the Consuming Component
The reason JavaScript thinks editTodo is not a function or is undefined is that you are trying to consume it in React within the <TaskList/> component before it (<TaskList/>) is even made aware of the context. By the time <TaskList/> has been rendered by React, it is too late to pass any context values. So we need to place the context, somewhere higher up the component tree where React will be made aware of the context and its values ahead of time before rendering (and passing the context values to) child components down the tree.
To fix this, place the context provider wrapper at least one level above the component that is consuming the values of the context provider. If more than one component needs values from the provider, the best place to place the provider wrapper would be in your App.jsx/App.js or your index.jsx/index.js file.
Inside App.jsx/App.js:
import { TaskProvider } from 'path/to/context';
function App() {
<TaskProvider>
{/* All your code/rendered elements/rendered route elements go here */}
</TaskProvider>
}
export default App;
or Inside index.jsx/index.js:
import React from "react";
import ReactDOM from "react-dom";
import { ToastProvider } from "path/to/context";
import "./index.css";
import App from "./App";
ReactDOM.render(
<React.StrictMode>
<ToastProvider>
<App />
</ToastProvider>
</React.StrictMode>,
document.getElementById("root")
);
I'll show you a better way to pass those context values.
Create Your Context, Declare all variables and methods within the Context, and Export the Context's Provider after passing the value Prop:
Inside TaskContexts.jsx/TaskContexts.js:
import {useContext, createContext } from "react";
// ...All your necessary imports
// Create context first
const TaskContexts = createContext();
export const TaskProvider = ({ children }) => {
const [editID, setEditID] = useState(null);
const [editText, setEditText] = useState(null);
const [isEditError, setIsEditError] = useState(false);
const [mode, setMode] = useState('All');
const removeTodo = id => {
dispatch({ type: ACTION_TYPES.REMOVE, id });
};
const toggleTodoCompletion = id => {
dispatch({ type: ACTION_TYPES.TOGGLE, id });
};
const editTodo = id => {
const text = editText.trim();
try {
TODO_TASK_CHEMA.validateSync({ text });
} catch (e) {
setIsEditError(true);
throw new Error(e);
}
setIsEditError(false);
setEditID(null);
dispatch({ type: ACTION_TYPES.EDIT, id, text });
setEditText(null);
};
// ...and the rest of the methods
// Prepare your contextValues object here
const contextValues = {
editID,
setEditID,
// ...and the rest
};
// Notice that we have called the provider here
// so that we don't have to do it within the `App.jsx` or `index.jsx`.
// We have also passed the default values here so we can that
// we don't have to export them and pass them in `App.jsx`.
// We used component composition to create a `hole` where the rest of
// our app, i.e, `{children}` will go in and returned the
// composed component from here, i.e, `<TaskProvider/>`.
// This is so that all the preparation of the context Provider object
// gets done in one file.
return (<TaskContexts.Provider value={contextValues}>
{children}
</TaskContexts.Provider>);
};
// Now, use the context, we will export it in a function called `useTask()`
// so that we don't have to call `useContext(TaskContexts)` every time we need values from the context.
// This function will call `useContext()` for us and return the values
// in the provider available as long as we wrap our app components
// with the provider (which we have already done).
export function useTask() {
return useContext(TaskContexts);
}
Consume the Context Values by importing the useContext() hook in TaskList.jsx/TaskList.js and calling it on the Provider object.
Since we've already called useContext on the provider object, we just need to import useTask() from earlier in TaskList.jsx, run it and it will return the contextValues object which we can destructure.
import React, { useState } from 'react';
import ACTION_TYPES from '../ToDo/reducer/actionTypes';
import RenderedTable from './RenderedTable';
import styles from './TaskList.module.scss';
import allIcon from '../../icons/all.svg';
import completedIcon from '../../icons/completed.svg';
import notCompletedIcon from '../../icons/notCompleted.svg';
import mona from '../../icons/mona.gif';
import { TODO_TASK_CHEMA } from '../../utils/validationSchemas';
// Import `useTask` only.
import { useTask } from '../../contexts';
const TaskList = props => {
// Values from context
const {editID, setEditID,...} = useTask();
const {
reducerData: [state, dispatch],
} = props;
const [editID, setEditID] = useState(null);
const [editText, setEditText] = useState(null);
const [isEditError, setIsEditError] = useState(false);
const [mode, setMode] = useState('All');
const removeTodo = id => {
dispatch({ type: ACTION_TYPES.REMOVE, id });
};
const toggleTodoCompletion = id => {
dispatch({ type: ACTION_TYPES.TOGGLE, id });
};
const editTodo = id => {
const text = editText.trim();
try {
TODO_TASK_CHEMA.validateSync({ text });
} catch (e) {
setIsEditError(true);
throw new Error(e);
}
setIsEditError(false);
setEditID(null);
dispatch({ type: ACTION_TYPES.EDIT, id, text });
setEditText(null);
};
const editTodoHandler = ({ target: { value } }) => {
setEditText(value);
};
return (
<div className={styles.container}>
{/*...everything else */}
<RenderedTable
editTodo={editTodo}
setEditID={setEditID}
toggleTodoCompletion={toggleTodoCompletion}
editID={editID}
editTodoHandler={editTodoHandler}
removeTodo={removeTodo}
state={state}
mode={mode}
isEditError={isEditError}
/>
</>
)}
</div>
);
};
export default TaskList;
In summary, scope everything about the context object to its own component, within its own file, export it and wrap all the children components in the root component (or wrap the root component itself), and call useContext() on the provider object in the component that needs the context values.

How to use variable from script A in srcript B typescript?

I want to get variable from other script to build the next part of the page on the basis of this data.
This is code to get data from API:
import Axios from "axios";
import React from "react";
export default class PersonList extends React.Component {
state = {
dataURL: [], //from this variable I want get data
};
componentDidMount() {
Axios.get(
"https://g.tenor.com/v1/search?q=" +
"mems" +
"&key=" +
"MY_TENOR_API_KEY" +
"&limit=" +
"1"
).then((res) => {
this.state.dataURL = res.data;
this.setState({ dataURL });
console.log(this.state.dataURL);
});
}
render() {
return;
}
}
Here I want to dynamically import the script and try to get access to variable from other script
import { useState } from "react";
import styles from "../styles/Form.module.scss";
function Form() {
const [results, setResults] = useState();
return (
<div className={styles.container}>
<div className={styles.form}>
<input
type="button"
onClick={async (e) => {
const { value } = e.currentTarget;
const Fuse = (await import("../pages/api/tenor")).default;
const fuse = new Fuse(state); //I got there an error: "Cannot find name 'state'.ts(2304)"
setResults(fuse.search(value));
}}
/>
</div>
</div>
);
}
export default Form;
Basically, if you want to access a component's data from a different component you have a few options you can choose from.
Send that data as a prop.
(only relevant if the 2nd component is a child/grand-child/etc.. of the 1st component)
Manage a "global state" (a single source containing the app's relevant data).
This can be achieved via 3rd-party libraries (Redux / MobX / etc..)
Or even via React's built-in ContextAPI.
Use a shared hook containing the state which can then be accessed from other components.
(only relevant for functional components)
IMO, the simplest option is the 3rd, but it will require turning PersonList into a functional hook.
An example should look like this:
// Shared "PersonList" hook.
import Axios from "axios";
import React, { useState } from "react";
export function usePersonList() {
const [dataURL, setDataURL] = useState([]);
useEffect(() => {
Axios.get(
"https://g.tenor.com/v1/search?q=" +
"mems" +
"&key=" +
"MY_TENOR_API_KEY" +
"&limit=" +
"1"
).then(res => setDataURL(res.data));
}, []);
return dataURL;
}
// Form.tsx
import { useState } from "react";
import styles from "../styles/Form.module.scss";
function Form() {
const [results, setResults] = useState();
const dataURL = usePersonList();
return (
<div className={styles.container}>
<div className={styles.form}>
<input
type="button"
onClick={async (e) => {
const { value } = e.currentTarget;
const Fuse = (await import("../pages/api/tenor")).default;
const fuse = new Fuse(dataURL);
setResults(fuse.search(value));
}}
/>
</div>
</div>
);
}
export default Form;
You can try React Redux or useReducer to share variable between components.

Difference between this two js in react

I start to learn React JS and anyone can explain me the difference between those two files? Both of them do the same thing.
First JS
import React, { useEffect, useState } from 'react'
import Product from './Product';
import './Today.css';
import { Link } from 'react-router-dom';
import { render } from '#testing-library/react';
export default class Today extends React.Component {
state = {
loading : true,
fixture : null
};
async componentDidMount() {
const OPTIONS = {
method : 'GET',
headers : {
'X-RapidAPI-Host' : 'api-football-v1.p.rapidapi.com',
'X-RapidAPI-Key' : '###'
}
};
const url = 'https://api-football-v1.p.rapidapi.com/v2/fixtures/date/2020-07-18';
const response = await fetch(url,OPTIONS);
const fixtures = await response.json();
this.setState({ fixture: fixtures.api.fixtures, loading: false});
const teamData = fixtures.api && fixtures.api.fixtures > 0 ? fixtures.api.fixtures : [];
console.log(this.state);
}
render() {
return (
<div className="today">
{this.state.loading || !this.state.fixture ? (
<div><img src=""/></div>
) : (
<div>
<div>
{this.state.fixture.slice(0,10).map(fixtureToday => (
<div>{fixtureToday.homeTeam.team_name}</div>
))}
</div>
</div>
)}
</div>
)
}
}
Second one
import React, { useState, useEffect } from 'react';
import './AnotherDay.css';
import { Link } from 'react-router-dom';
function AnotherDay() {
useEffect(() => {
fetchItems();
},[]);
const OPTIONS = {
method : 'GET',
headers : {
'X-RapidAPI-Host' : 'api-football-v1.p.rapidapi.com',
'X-RapidAPI-Key' : '###'
}
};
const [fixtures, setItems] = useState([]);
const fetchItems = async () => {
const data = await fetch(
'https://api-football-v1.p.rapidapi.com/v2/fixtures/date/2020-07-18' , OPTIONS
);
const fixtures = await data.json();
const teamData = fixtures.api && fixtures.api.fixtures.length > 0 ? fixtures.api.fixtures : [];
console.log(teamData);
setItems(teamData);
}
return (
<div>
{fixtures.slice(0,10).map(fixture => (
<div>{fixture.homeTeam.team_name}</div>
))}
</div>
);
}
export default AnotherDay;
And in the App.js I have
import React from 'react'
import './Today.css';
import { Link } from 'react-router-dom';
import Today from './Today ';
import AnotherDay from './EvenimenteMaine';
function TodayEvents() {
return (
<div className="today">
<div className="todayEvents">
<Today />
</div>
<div className="anotherDayEvents">
<AnotherDay />
</div>
</div>
)
}
export default TodayEvents
I have the same result in the both divs. My question is, what is the difference? The first one is a class and the second one is a function?
Which one is the correct way?
Thanks, maybe is a noob question but I'm new to learning React.
The first example is a class component the second one is a functional component. React development is moving away from classes toward the functional components. useEffect is supposed to replace several life cycle functions from class components.
Two things to look into functional components and class components. The second set of things to look up is life cycle functions and functional component hooks.
Here is a link that will explain at a high level the differences.
https://dev.to/danielleye/react-class-component-vs-function-component-with-hooks-13dg

On click returns null instead of an object

It's really basic I guess. I'm trying to add onClick callback to my script & I believe I'm missing a value that would be responsible for finding the actual item.
Main script
import React from 'react';
import { CSVLink } from 'react-csv';
import { data } from 'constants/data';
import GetAppIcon from '#material-ui/icons/GetApp';
import PropTypes from 'prop-types';
const handleClick = (callback) => {
callback(callback);
};
const DownloadData = (props) => {
const { callback } = props;
return (
<>
<CSVLink
data={data}
onClick={() => handleClick(callback)}
>
<GetAppIcon />
</CSVLink>
</>
);
};
DownloadData.propTypes = {
callback: PropTypes.func.isRequired,
};
export default DownloadData;
Storybook code
import React from 'react';
import DownloadData from 'common/components/DownloadData';
import { data } from 'constants/data';
import { action } from '#storybook/addon-actions';
export default {
title: 'DownloadData',
component: DownloadData,
};
export const download = () => (
<DownloadData
data={data}
callback={action('icon-clicked')}
/>
);
So right now with this code on click in the storybook I'd get null and I'm looking for an object.
One of the potential issues I can see is that your handleClick function is stored as it is in-memory, when you import the component. That means you're keeping reference of something that doesn't exists and expects to use it when rendering the component with the callback prop.
Each instance of a component should have its own function. To fix it, move the function declaration inside the component. Like this:
const Foo = ({ callback }) => {
// handleClick needs to be inside here
const handleClick = callback => {
console.log("clicked");
callback(callback);
};
return <div onClick={() => handleClick(callback)}>Click me!</div>;
};
Check this example.
If this doesn't fix your problem, then there is something wrong with how you're implementing Storybook. Like a missing context.

Resources