I'm new to React and I'm trying to use Context API. Here is my code:
FormColorContext.js
import React, { useState } from 'react';
export const FormColorContext = React.createContext();
const FormColorProvider = (props) => {
const [color, setColor] = useState('white')
return (
<FormColorContext.Provider value={{color}}>
{props.children}
</FormColorContext.Provider>
)
}
export default FormColorProvider
dashboard.js
import React from 'react';
import FormColorProvider from '../context/FormColorContext';
import DefaultLayout from '../layout/default-layout';
import EmptyDashboardComponent from '../components/Dashboard/EmptyDashboardComponent';
import NewFormComponent from '../components/Dashboard/NewFormComponent';
import ColorSelectorComponent from '../components/Dashboard/ColorSelectorComponent';
import styles from '../styles/dashboard.module.css';
export default function Dashboard() {
return (
<div>
<DefaultLayout>
<div className={styles.containerMain}>
<h1 className={styles.headingCenter}>Create a new form</h1>
<FormColorProvider>
<ColorSelectorComponent/>
<NewFormComponent/>
</FormColorProvider>
</div>
</DefaultLayout>
</div>
)
}
NewFormComponent.js
import React, { useContext } from 'react';
import styles from '../../styles/NewFormComponent.module.css';
import FormColorContext from '../../context/FormColorContext';
export default function NewFormComponent() {
const color = useContext(FormColorContext);
console.log(color);
return (
<div className={styles.formContainer}>
</div>
)
}
I made sure that all imports are correct, but for some reason when I try to log color variable I'm getting undefined. What am I doing wrong? Thanks in advance.
Renato
Sample Example: Expo Snack
In your Context Provider you are passing an object, so access color like below:
NewFormComponent.js:
import React, { useContext } from 'react';
import styles from '../../styles/NewFormComponent.module.css';
import {FormColorContext} from '../../context/FormColorContext';
export default function NewFormComponent() {
const {color} = useContext(FormColorContext);
console.log(color);
return (
<div className={styles.formContainer}>
</div>
)
}
FormColorContext.js:
import React, { useState } from 'react';
export const FormColorContext = React.createContext();
export const FormColorProvider = (props) => {
const [color, setColor] = useState('white')
return (
<FormColorContext.Provider value={{color}}>
{props.children}
</FormColorContext.Provider>
)
}
** dashboard.js: **
import React from 'react';
import {FormColorProvider} from '../context/FormColorContext';
import DefaultLayout from '../layout/default-layout';
import EmptyDashboardComponent from '../components/Dashboard/EmptyDashboardComponent';
import NewFormComponent from '../components/Dashboard/NewFormComponent';
import ColorSelectorComponent from '../components/Dashboard/ColorSelectorComponent';
import styles from '../styles/dashboard.module.css';
export default function Dashboard() {
return (
<div>
<DefaultLayout>
<div className={styles.containerMain}>
<h1 className={styles.headingCenter}>Create a new form</h1>
<FormColorProvider>
<ColorSelectorComponent/>
<NewFormComponent/>
</FormColorProvider>
</div>
</DefaultLayout>
</div>
)
}
The problem is in imports. You import the default value in NewFormComponent.js file. Change the import to import {FormColorContext} from '../../context/FormColorContext';
Moreover, it is a dupliate of useContext() returns undefined
you could have googled it)
You have a problem in importing the FormColorContext in your NewFormComponent and it's passing the undefined to useContext method and it returns undefined too.
here is what you need to do:
import React, { useContext } from 'react';
import styles from '../../styles/NewFormComponent.module.css';
import FormColorContext from '../context/FormColorContext';
export default function NewFormComponent() {
// remember to destructure the color variable
const { color } = useContext(FormColorContext);
console.log(color);
return (
<div className={styles.formContainer}>
</div>
)
}
Related
Could you please help use to resolve this case
Parent component
const HelloMessage = (props) => {
return <>
<div className="main-counter" >
<top-destination name="srini" />
</div>
</>
}
export default HelloMessage
customElements.define("react-counter", reactToWebComponent(HelloMessage, React, ReactDOM));
Child (Web component)
import React from 'react';
import reactToWebComponent from "react-to-webcomponent";
const TopDestination = (props) => {
console.log(props);
return <>
<div>{props.name}</div>
</>
}
export default TopDestination
customElements.define("top-destination", reactToWebComponent(TopDestination, React, ReactDOM));
console log value
In html
<top-destination name="John" />
Cross-check your Node version, It should be Node 14 or above.
Cross-check your import ReactDom statement, based on the React version you are using.
Update to the latest version of react-to-webcomponent and prop-types
Your code should be like this:
Parent component
import React from 'react';
const HelloMessage = (props) => {
return <>
<div className="main-counter" >
<top-destination name="srini" />
</div>
</>
}
export default HelloMessage
customElements.define("react-counter", reactToWebComponent(HelloMessage, React, ReactDOM));
Child (Web component)
import React from 'react';
import PropTypes from "prop-types"
import * as ReactDOM from 'react-dom/client';
import reactToWebComponent from "react-to-webcomponent"
const TopDestination = (props) => {
console.log(props);
return <>
<div>{props.name}</div>
</>
}
TopDestination.propTypes = {
name: PropTypes.string,
}
customElements.define("top-destination", reactToWebComponent(TopDestination, React, ReactDOM));
export default TopDestination
// Other ways of defining the props if you are on better versions.
// customElements.define(
// "top-destination",
// reactToWebComponent(TopDestination, React, ReactDOM, {
// props: {
// name: String
// },
// }),
// )
// or
// customElements.define(
// "top-destination",
// reactToWebComponent(TopDestination, React, ReactDOM, {
// props: ["name"]
// }),
// )
Refer this repo: https://github.com/sarat9/cross-ui-web-comp
File: https://github.com/sarat9/cross-ui-web-comp/blob/master/react-web-components/src/web-components/FancyButtonWC.js
I have a component in which i want to call different rtkquery hooks based on a condition. I am making a twitter clone and on the home page i want to call a getPostsList and on the profile page i want to call a getRetweetedPostsList but since the entire page is same apart from this i am using a single component. Now i want to call different hooks in the PostList component based on props? Is this possible? Maybe by using skip? Also is this against best practices?
index.tsx
import type { NextPage } from 'next'
import { useSession} from 'next-auth/react';
import SignUpLoginFullScreen from '../components/SignUpLoginFullScreen';
import LoadingScreen from '../components/LoadingScreen';
import PostsSection from '../components/Posts/PostsSection';
const Home: NextPage = () => {
const {data:session,status}=useSession();
return (
<>
{!session && status==='unauthenticated' &&
<SignUpLoginFullScreen/>
}
{!session && status==='loading' &&
<LoadingScreen/>
}
{session && status==='authenticated' &&
<PostsSection/>
}
</>
)
}
export default Home
PostSection.tsx
import React from 'react'
import { useSession} from 'next-auth/react';
import Sidebar from '../Sidebar';
import Search from '../Search';
import PostsList from '../Posts/PostsList';
import AddPostForm from '../Posts/AddPostForm';
import Modal from '../Modal';
import UsersList from '../UsersList';
const PostsSection=()=>{
const {data:session,status}=useSession();
return (
<>
<Modal>
<AddPostForm />
</Modal>
<div className='flex mx-32 gap-x-5'>
<Sidebar/>
<main className='mr-5 pt-8 flex-1 basis-[45%] border-x-2 border-stone-100 min-h-screen'>
<PostsList currUserId={session?.userId}/>
</main>
<div className='basis-[25%]'>
<Search/>
<UsersList currentUserId={session?.userId}/>
</div>
</div>
</>
)
}
export default PostsSection
PostList.tsx
import React from 'react'
import {useGetPostsQuery} from '../../services/apiSlice';
import LoadingSpinner from '../LoadingSpinner';
import Post from './Post';
interface PropsType{
currUserId:string|any
}
const mapPosts=(posts:any,currUserId:string)=>{
return posts?.map((post:any) => (
<Post key={post.id} currUserId={currUserId} {...post}/>
))
};
const PostsList:React.FC<PropsType>= ({currUserId}) => {
const {data:posts,isLoading,error,isError} = useGetPostsQuery(currUserId);
let content;
content=React.useMemo(()=>mapPosts(posts,currUserId), [posts]);
if(isLoading){
content=<LoadingSpinner/>
}
else if(isError){
let a:any=error
content=<p color='red'>{a?.message}</p>
}
else if(posts){
if(posts.length<=0){
console.log('aye')
content=<p color='black'>No tweets yet</p>;
return null;
}
}
return (
<section className="posts-list">
{content}
</section>
)
}
export default PostsList;
I want to call the PostList component from the profile page but with some props and based on that props i want to call a different hook to which i am calling for the index page.
Profile.tsx
import React from 'react';
import { useSession } from 'next-auth/react';
import LoadingScreen from '../components/LoadingScreen';
import Sidebar from '../components/Sidebar';
import Search from '../components/Search';
import PostsList from '../components/Posts/PostsList';
import AddPostForm from '../components/Posts/AddPostForm';
import Modal from '../components/Modal';
import UsersList from '../components/UsersList';
import SignUpLoginFullScreen from '../components/SignUpLoginFullScreen';
import PostsSection from '../components/Posts/PostsSection';
export default function Profile() {
const {data:session,status}=useSession();
return (
<>
{!session && status==='unauthenticated' &&
<SignUpLoginFullScreen/>
}
{!session && status==='loading' &&
<LoadingScreen/>
}
{session && status==='authenticated' &&
<PostsSection/>
}
</>
)
}
I would use different components to call different hooks, then pass the data to a reusable common component.
Hey all im looking for help. im having some trouble with passing data from one child component to another child component using the context api. But i get this typeError instead, i tried a few searches so far without much luck. if anyone can't point me in the right direction it would be much appreciated!
thanks
CurrencyProvider.js
import { React, Component} from 'react';
export const MContext = React.createContext('');
class CurrencyProvider extends Component {
constructor() {
super()
this.state = {
setinputValue: (value) => this.setState({ inputValue: value })
}
}
render() {
return (
<MContext.Provider value={this.state}>
{this.props.children}
</MContext.Provider>)
}
}
export default CurrencyProvider;
Dropdown.js
import { useQuery, gql } from "#apollo/client";
import { useState } from "react";
import './Dropdown.scss';
import { MContext } from "../CurrencyProvider";
const EXCHANGE_RATES = gql`
query GetExchangeRates {
rates(currency: "AUD") {
currency
rate
name
}
}
`;
function Dropdown() {
const [isToggled, setToggle] = useState(false);
const { data, loading, error } = useQuery(EXCHANGE_RATES);
if (loading) {
return <div>loading</div>;
}
if (error) {
return <div>{error}</div>;
}
return (
<div className="custom-dropdown">
<ul className={`dropdown-menu ${isToggled ? 'open':''}`}>
<li value="0" className="first-item" onClick={() => setToggle(!isToggled)} onKeyPress={() => setToggle(!isToggled)} tabIndex="0">Select Currency:</li>
{data.rates.map(({ currency, rate, name },index) => (
<MContext.Consumer>
{(context) => (
<li className="list-item" key={index} data={rate} tabIndex="0" onClick={()=>{context.setinputValue(rate)}}> <span>{name}: {currency}</span></li>
)}
</MContext.Consumer>
))}
</ul>
</div>
);
}
export default Dropdown;
Input.js
import './Input.scss';
import { MContext } from "../CurrencyProvider";
function Input() {
return(
<MContext.Consumer>
{(context) => (
<input value={context.state.inputValue} />
)}
</MContext.Consumer>
);
}
export default Input;
CurrencyContainer.js
import Dropdown from '../Dropdown/Dropdown';
import Input from '../Input/Input';
import './CurrencyContainer.scss';
import CurrencyProvider from '../CurrencyProvider';
function CurrencyContainer() {
return (
<div className='currency-container'>
<h1 >Select Items</h1>
<div className="currency-wrapper">
<CurrencyProvider>
<div><Input /></div>
<div><Dropdown /></div>
<div><Dropdown /></div>
</CurrencyProvider>
</div>
</div>
);
}
export default CurrencyContainer;
App.js
import logo from './logo.svg';
import './App.scss';
import { client } from "./ApolloClient/client";
import { ApolloProvider } from '#apollo/client';
import CurrencyContainer from './CurrencyContainer/CurrencyContainer';
function App() {
return (
<ApolloProvider client={client}>
<div className="App">
<img src={logo} className="App-logo" alt="logo" />
<CurrencyContainer />
</div>
</ApolloProvider>
);
}
export default App;
Why don't you try placing something more in the likes of this in a separate file mcontext.context.jsx:
import { createContext } from "react";
const MContext = createContext('');
export default MContext;
Then you can import it and
get values by importing your newly created context, the useContext hook and adding something like this to the top of a functional component which is encapsulated inside a MContext.Provider node:
const val = useContext(MContext);
set values:
<MContext.Provider value={mcontextValue}>
</MContext.Provider>
All children inside your MContext.Provider node and their children will have access to your MContext value given you get it as I showed you in the 1st part of the answer.
Your React import is incorrect. Change it to:
import React, {Component} from 'react';
React is the default export, not a named export.
React package doesn't have a named import called React, it has a default import that people generally use React for, so you should change this line
import { React, Component } from 'react';
to this
import React, { Component } from 'react';
If you use React 17+, you don't need to import React from 'react'; anymore, you can remove any mentioning of React from your import, so your import will look like this
import { createContext } from 'react';
But you have to turn off the lint rules for this import in your .eslintrc.json file like so
{
"rules": {
...
"react/jsx-uses-react": "off",
"react/react-in-jsx-scope": "off"
}
}
Hi i am quite new to react and redux , i was creating a poc and got this error , despite my efforts i am not able to solve this
here is my code
shoping-app/app/index.jsx
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import {createStore} from 'redux'
import reducer from './reducers/index.js'
import {Provider} from 'react-redux'
let store = createStore(reducer)
import App from './components/App'
ReactDOM.render(
<Provider store={store}><App/></Provider>,document.getElementById('app'));
shoping-app/app/components/product.jsx
import React from 'react'
let Product =({id,name,cost,handleClick})=>{
<div>
{name} ${cost}<button onClick={()=>handleClick(id)}>Add to Cart</button>
</div>
}
export default Product
shoping-app/app/components/App.jsx
import React, { Component } from 'react'
import Products from '../containers/products.jsx'
export default class App extends Component {
render(){
return (
<div>
<p>Welcome to our shop</p>
<Products/>
</div>
)
}
}
shoping-app/app/components/products.jsx
import React from 'react'
import Product from './product.jsx'
let Products=({products,handleClick})=>(
<section>
<h2>Our Products</h2>
< section>
{products.map(product=><Product
key={product.id}
{...product}
handleClick={handleClick}/>)}
</section>
</section>
)
export default Products
shoping-app/app/containers/products.jsx
import React from 'react'
import {connect} from 'react-redux'
import Products from '../components/products.jsx'
function mapStateToProps(state){
return{
products:state.products
}
}
function mapDispatchToProps(dispatch){
return{
handleClick(id){
dispatch({
type:'ADD_TO_CART',
payload:{
id
}
})
}
}
}
let ProductsContainer =connect(mapStateToProps,mapDispatchToProps) (Products)
export default ProductsContainer
shoping-app/app/reducers/index.js
import {ADD_TO_CART,REMOVE_FROM_CART,CHANGE_CATEGORY} from '../constants/actionTypes'
let initialState={
activeCategory:'food',
products:[
{id:193,name:'pizza',cost:10},
{id:194,name:'pizza2',cost:100},
{id:195,name:'pizza3',cost:1000},
{id:196,name:'pizza4',cost:10000},
],
shoppingCart:[]
}
export default function reducer(state=initialState,action){
switch(action.Type){
case CHANGE_CATEGORY:
return{
...state,
activeCategory:action.payload
}
case ADD_TO_CART:
return{
...state,
shoppingCart:[...state.shoppingCart,action.payload]
}
case REMOVE_FROM_CART:
return{
...state,
shoppingCart:state.shoppingCart.filter(productId=>productId!=action.payload)
}
default:
return state
}
}
The problem is this : shoping-app/app/components/product.jsx
The default exported function of this just references a react component but it does not return anything. In order to return you have to type return keyword explicitly or just wrap your object(the component in this case) in parentheses ().
import React from 'react'
let Product =({id,name,cost,handleClick})=> ({
<div>
{name} ${cost}<button onClick={()=>handleClick(id)}>Add to Cart</button>
</div>
})
export default Product
For a start change this error in your code.
ReactDOM.render(
<Provider store={store}><App/></Provider>,document.getElementById('app'));
to
const elem = () => <Provider store={store}> <App/> </Provider>;
ReactDOM.render(elem, document.getElementById('app'));
After that change the curly braces inside your product.jsx to parenthesis like so.
let Product =({id,name,cost,handleClick}) => (
//
//
)
This way, you'll be returning a valid jsx from Product. By enclosing it in curly braces, you simply start the function definition but return nothing.
I am utilizing thunk with react and redux. My action creator executes an API call and returns data in a property "data" and my reducer returns that object. I have this returned object mapped to props in my component. Its an array of 16 items (each item is an image url). when I console.log(this) I can click through and see the data, but if I go further like console.log(this.props.showGallery.imageLinks) it shows undefined.
Another situation is that when I render { this.props.showGallery.imageLinks } I can clearly see all the text of the items in the array on my web page but when I use .map on it, the console says cannot read property "map" of undefined and the web page is just empty. Am I doing this wrong? How can I make this data like normally?
Am I understanding redux concepts wrongly?
actions.js
export const SHOW_GALLERY = 'SHOW_GALLERY';
import axios from 'axios';
// FETCH THE IMAGES
export const actionGallery = () => {
return ( dispatch ) => {
axios.get('../images')
.then(res => {
if (res.status === 200) {
return dispatch({ type: SHOW_GALLERY, data: [...res.data] });
}
})
.catch(err => console.error(err));
}
}
reducer
images.js
import { HEAD_SELECTED, SHOW_GALLERY } from '../actions/actions';
import { actionSelectHeadImg } from '../actions/actions';
import { actionGallery } from '../actions/actions';
// Show the image links from an array
export function showGallery(state={}, action) {
switch(action.type) {
case SHOW_GALLERY:
return Object.assign({}, state, { imageLinks: new Array(action.data) })
default:
return state;
}
}
combined Reducers for above:
import React from 'react';
import { combineReducers } from 'redux';
import { showGallery, headSelected } from './images';
// Combine all your reducers to this
const allReducers = combineReducers({
showGallery,
headSelected
});
export default allReducers;
component / container
Gallery.js
import React from 'react';
import ReactDOM from 'react-dom';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { actionGallery } from '../actions/actions';
import cheerio from 'cheerio';
class Gallery extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
}
this.props.actionGallery();
}
render() {
return (
<div>
<h1>This is the Gallery.</h1>
<br />
<div className="container">
<div className="row">
<div className="col-md-8">
<h2>H2 h2 h2 2h2 </h2>
{ this.props.showGallery.imageLinks.forEach((i, index) => {
<p>i</p>
}) }
</div>
</div>
</div>
</div>
);
}
}
function mapStateToProps(state) {
return {
showGallery: state.showGallery,
headSelected: state.headSelected,
newState: state
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({
actionGallery,
actionSelectHeadImg
}, dispatch)
}
export default connect(mapStateToProps, mapDispatchToProps)(Gallery);
A regular component that just holds the other container/components
import React from 'react';
import ReactDOM from 'react-dom';
import Gallery from './containers/Gallery';
import HeadingImg from './containers/HeadingImg';
class App extends React.Component {
render() {
//console.log(this.props.actionGallery())
return (
<div>
<center>
<h3>SELECTED IMAGE:</h3>
<br />
<HeadingImg />
<hr />
<Gallery />
</center>
</div>
);
}
}
export default App;
TOP LEVEL COMPONENT (MAIN COMPONENT)
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import App from '../Components/Earth/app';
import allReducers from '../Components/Earth/reducers';
import thunk from 'redux-thunk';
const store = createStore(allReducers, applyMiddleware(thunk));
ReactDOM.render(
<Provider store={store}>
<App store={store}/>
</Provider>
, document.getElementById("root"));
I'm assuming when you create your store, you only have the one reducer. If that is the case then your assumption about 'state.showGallery' existing doesn't. Instead imageLinks will be in state without the 'showGallery'.
If my assumption is correct, then you should change your mapStateToProps to have showGallery as:
showGallery: { imageLinks: state.imageLinks },