Child Component using WebSocket to get data from server
this working fine,
output of the code is correct when passing string
import { useContext, useEffect, useState } from "react";
import { WebsocketContext } from "./Wsconnection";
import React from "react";
const Allotments = ({ num }) => {
const [isReady, socket] = useContext(WebsocketContext);
const [allotdata, setAllotdata] = useState({});
useEffect(() => {
if (isReady) {
socket.send(JSON.stringify({ type: "get_allotment_details", number: num }));
socket.onmessage = (e) => {
const data = JSON.parse(e.data);
if (data.type === "get_allotment_details") {
const altdata = data.alloted_details[0];
setAllotdata({ customer: altdata.prq__customer__name });
}
};
}
return () => {};
}, [isReady, num, socket]);
return (
<div>
<h5>{allotdata?.customer}</h5>
</div>
);
};
export default Allotments;
Parent Component
import React from "react";
import Allotments from "./Allotments";
const init_alloted = JSON.parse(document.getElementById("reporting").dataset.alloted) || [];
export const Alloted = () => {
const allots = init_alloted.map((allot, idx) => {
return (
<div key={idx}>
<Allotments num={allot.number} key={idx} />
</div>
);
});
return <div className="col">{allots}</div>;
};
i tried passing text string then, everything works fine
Related
I have two function components with useState in two different files in my project. I want to display the url on my FaceRecognition component if I set fetchSuccess to true.
const ImageLinkForm = () => {
const [url, setUrl] = useState("");
const [fetchSuccess, setFetchSuccess] = useState(false);
const onInputChange = (event) => {
// I get the url and fetchSuccess is true
};
return (
<div>
// I return a form that allowed me to make the fetch call
</div>
);
};
export default ImageLinkForm;
const FaceRecognition = () => {
return (
<div>
{/* if fetchSuccess */}
<img src=url />
</div>
);
};
export default FaceRecognition;
This really depends on how these components are hierarchically related but one easy-ish option is to use the context API
// context/image.js
import { createContext, useState } from "react";
export const ImageContext = createContext({ fetchSuccess: false });
export const ImageContextProvider = ({ children }) => {
const [fetchSuccess, setFetchSuccess] = useState(false);
const setSuccessful = () => {
setFetchSuccess(true);
};
return (
<ImageContext.Provider value={{ fetchSuccess, setSuccessful }}>
{children}
</ImageContext.Provider>
);
};
Your components can then use the context to read the value...
import { useContext } from "react";
import { ImageContext } from "path/to/context/image";
const FaceRecognition = () => {
const { fetchSuccess } = useContext(ImageContext);
return <div>{fetchSuccess && <img src="url" />}</div>;
};
and write the value...
import { useContext, useState } from "react";
import { ImageContext } from "path/to/context/image";
const ImageLinkForm = () => {
const [url, setUrl] = useState("");
const { setSuccessful } = useContext(ImageContext);
const onInputChange = (event) => {
// I get the url and fetchSuccess is true
setSuccessful();
};
return (
<div>{/* I return a form that allowed me to make the fetch call */}</div>
);
};
The only thing you need to do is wrap both these components somewhere in the hierarchy with the provider
import { ImageContextProvider } from "path/to/context/image";
const SomeParent = () => (
<ImageContextProvider>
<ImageLinkForm />
<FaceRecognition />
</ImageContextProvider>
);
I am displaying a foto in the front using Leigh Halliday's Image Previews in React with FileReader from https://www.youtube.com/watch?v=BPUgM1Ig4Po and everything is super BUT:
1.I want to get information from the image is displaying, exactly the base64 info, and have it then globally in my reactjs app.
2.for that reason I made a Context, i configured it ok BUT:
when I am doing dispatch inside a useEffect I want the image rendering and the info store in my variable globally
but I have one thing or another
if my image renders ok in my front, I can not obtain the value of my dispatch and viceversa
this is the code of my component:
import React, { useContext, useEffect, useRef, useState } from 'react'
import { AuthContext } from '../../auth/AuthContext'
import { types } from '../../types/types'
export const ButtonLoadFoto = () => {
const { dispatchFoto } = useContext(AuthContext)
const [image, setImage] = useState('')
const [preview, setPreview] = useState('')
const [status, setStatus] = useState(false)
useEffect(() => {
if (image) {
const reader = new FileReader()
reader.onloadend = () => {
setPreview(reader.result)
}
reader.readAsDataURL(image)
setStatus(true)
} else {
setPreview('')
}
}, [image])
// useEffect(() => {
// if (status) {
// dispatchFoto({
// type: types.foto,
// payload: {
// foto: preview.split(',')[1]
// }
// })
// }
// return () => setStatus(false)
// }, [preview])
const fileInputRef = useRef()
const handleRef = (e) => {
e.preventDefault()
fileInputRef.current.click()
}
const handleFile = (e) => {
const file = e.target.files[0]
if (file && file.type.substr(0, 5) === 'image') {
setImage(file)
}
}
return (
<div className='load-input '>
{
preview
?
(<img src={preview} alt='' onClick={() => setImage('')} />)
:
(<button
className='alert alert-danger'
onClick={handleRef}>
foto
</button>
)
}
< input
type='file'
style={{ display: 'none' }}
ref={fileInputRef}
accept='image/*'
onChange={handleFile}
/>
</div>
)
}
in the code above if you put away the comments we will have the information we want but the foto won t display at all
thanks all for your time , I really appreciate!
EDIT
this is the main component
import React, { useEffect, useReducer } from 'react'
import { AuthContext } from './auth/AuthContext'
import { fotoReducer } from './components/formScreen/fotoReducer'
import { AppRouter } from './routers/AppRouter'
const initImage = () => {
return { foto: '' }
}
export const CMI = () => {
const [foto, dispatchFoto] = useReducer(fotoReducer, {}, initImage)
return (
<div>
<AuthContext.Provider value={{
foto,
dispatchFoto
}}>
<AppRouter />
</AuthContext.Provider>
</div>
)
}
this is the componenent I use
import React, { useContext} from 'react'
import { ButtonLoadFoto } from '../components/formScreen/ButtonLoadFoto'
import { AuthContext } from '../auth/AuthContext'
export const FormScreen = () => {
const { foto } = useContext(AuthContext)
}
return (
<div>
<ButtonLoadFoto/>
</div>
)
as I said : if a render the image I can not have the information and viceversa...
when I use dispatch I don t know I it brokes the image render
thanks in advance
I thought had a better grasp of hooks but I've clearly got something wrong here. Not all of the character objects will have what I'm trying to get but it wont work with those that do.
I cna't even build in a check for character.comics.available. Same errors appear. I'm presuming I'm getting them before the state is set? But {character.name} always works.
CharacterDetail.js
import React from "react";
import { useParams } from "react-router-dom";
import useCharacter from "../hooks/useCharacter";
const CharacterDetail = () => {
// from the Route path="/character/:id"
const { id } = useParams();
// custom hook. useCharacter.js
const [character] = useCharacter(id);
// this only works sometimes but errors if i refresh the page
// console.log(character.comics.available);
return (
<div>
<h2 className="ui header">Character Details</h2>
<p>Works every time: {character.name}</p>
<div className="ui segment"></div>
<pre></pre>
</div>
);
};
export default CharacterDetail;
Custom hook useCharacter.js
import { useState, useEffect } from "react";
import marvel from "../apis/marvel";
const useCharacter = (id) => {
const [character, setCharacter] = useState({});
useEffect(() => {
loadItem();
return () => {};
}, [id]);
const loadItem = async (term) => {
const response = await marvel.get(`/characters/${id}`);
console.log(response.data.data.results[0]);
setCharacter(response.data.data.results[0]);
};
return [character];
};
export default useCharacter;
error when console is uncommented
Uncaught TypeError: Cannot read property 'available' of undefined
at CharacterDetail (CharacterDetail.js:11)
...
Here is the character object.
thanks to #Nikita for the pointers. Settled on this...
CharacterDetail.js
import React from "react";
import { useParams } from "react-router-dom";
import useCharacter from "../hooks/useCharacter";
const CharacterDetail = () => {
const { id } = useParams();
// custom hook. useCharacter.js
const { isLoading, character } = useCharacter(id);
const isArray = character instanceof Array;
if (!isLoading && isArray === false) {
console.log("isLoading", isArray);
const thumb =
character.thumbnail.path +
"/portrait_uncanny." +
character.thumbnail.extension;
return (
<div>
<h2 className="ui header">{character.name}</h2>
<img src={thumb} />
<div className="ui segment">{character.comics.available}</div>
<div className="ui segment">{character.series.available}</div>
<div className="ui segment">{character.stories.available}</div>
</div>
);
}
return <div>Loading...</div>;
};
export default CharacterDetail;
useCharacter.js
import { useState, useEffect } from "react";
import marvel from "../apis/marvel";
function useCharacter(id) {
const [character, setCharacter] = useState([]);
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
setIsLoading(true);
const fetchData = async () => {
setIsLoading(true);
await marvel
.get(`/characters/${id}`)
.then((response) => {
/* DO STUFF WHEN THE CALLS SUCCEEDS */
setIsLoading(false);
setCharacter(response.data.data.results[0]);
})
.catch((e) => {
/* HANDLE THE ERROR (e) */
});
};
fetchData();
}, [id]);
return {
isLoading,
character,
};
}
export default useCharacter;
I have trouble with react context.
Especially with function getProductCategory which I use in the second component.
My React context provider looks like :
import React, { createContext, useState, useEffect } from "react";
import data from "./data";
export const ProductContext = createContext();
const ProductContextProvider = ({ children }) => {
const [productsCategory, setProductCategory] = useState();
const [products, setProducts] = useState();
useEffect(() => {
setProducts(data);
});
function getProductCategory(category) {
const productFromCategory = data.filter(
(product) => product.type === category
);
setProductCategory(productFromCategory); //this line is causing the problem
console.log(productFromCategory);
return productsCategory;
}
const getProduct = (product) => {
const currentProduct = products
? products.filter((item) => item.slug === product)[0]
: undefined;
return currentProduct;
};
return (
<ProductContext.Provider
value={{ getProduct, getProductCategory }}
>
{children}
</ProductContext.Provider>
);
};
export default ProductContextProvider;
I want to get access to my context from another component Mats which is a page.
import React, { useContext, useEffect } from "react";
import { ProductContext } from "../../context";
/accesoriesComponent/CategoryTitle/CategoryTitle";
import Filters from "../../components/accesoriesComponent/Filters/Filters";
import ProductWrapper from "../../components/accesoriesComponent/ProductWrapper/ProductWrapper";
export default function Mats(props) {
const { getProductCategory } = useContext(ProductContext);
const mats = getProductCategory("mats");
return (
<div>
<div style={{ display: "flex" }}>
<Filters />
{mats && <ProductWrapper products={mats} />}
</div>
</div>
);
}
When I want to visit page Mats, I get error "Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside component WillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.".
I marked the line of code in the first code, that courses the problem .
I don't know how to handle it.
Any suggestions ?
Based on your code:-
instead of return-ing productsCategory from your getProductCategory function. Send your productsCategory as ProductContext.Provider values props
Btw, your useEffect should have [] or empty array as dependency
ProductContextProvider.js:-
import React, { createContext, useState, useEffect } from "react";
import data from "./data";
export const ProductContext = createContext();
const ProductContextProvider = ({ children }) => {
const [productsCategory, setProductCategory] = useState();
const [products, setProducts] = useState();
useEffect(() => {
setProducts(data);
}, []); // making sure it will only run once when rendered
function getProductCategory(category) {
const productFromCategory = data.filter(
(product) => product.type === category
);
setProductCategory(productFromCategory); // you already set the data in here
console.log(productFromCategory);
// return productsCategory; // no need to return this
}
const getProduct = (product) => {
const currentProduct = products
? products.filter((item) => item.slug === product)[0]
: undefined;
return currentProduct;
};
return (
<ProductContext.Provider
value={{ productsCategory, getProduct, getProductCategory }}
>
{children}
</ProductContext.Provider>
);
};
export default ProductContextProvider;
So in Mats.js, just get display your updated ``
export default function Mats(props) {
const { productsCategory, getProductCategory } = useContext(ProductContext);
// Shouldn't do this. Cause it will keep rerender
// const mats = getProductCategory("mats");
// default state of category
const [category, setCategory] = useState('mats')
// use useffect to send the updated products by category
useEffect(() => {
(() => {
if(category) {
getProductCategory(category);
}
})()
}, [category]) // will initiated every time category change
return (
<div>
<div style={{ display: "flex" }}>
<Filters />
{productsCategory && <ProductWrapper products={productsCategory} />}
</div>
</div>
);
}
import React, {useState, useEffect} from 'react';
import {connect} from 'react-redux';
import {
fetchRecipes
} from '../../store/actions';
import './BeerRecipes.css';
const BeerRecipes = ({recipesData, fetchRecipes}) => {
const [page, setPage] = useState(1);
const [recipes, setRecipes] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchRecipes();
}, [])
return (
<div className='beer_recipes_block'>
<div className='title_wrapper'>
<h2 className='title'>Beer recipes</h2>
</div>
<div className='beer_recipes'>
<ul className='beer_recipes_items'>
{
recipesData && recipesData.recipes && recipesData.recipes.map(recipe =>
<li className='beer_recipes_item' id={recipe.id}>{recipe.name}</li>
)
}
</ul>
</div>
</div>
);
};
const mapStateToProps = state => {
return {
recipesData: state.recipes
}
}
const mapDispatchToProps = dispatch => {
return {
fetchRecipes: () => dispatch(fetchRecipes())
}
}
export default connect(mapStateToProps, mapDispatchToProps)(BeerRecipes);
this is my component where I would like to create infinite scroll and below is my redux-action with axios:
import axios from "axios";
import * as actionTypes from "./actionTypes";
export const fetchRecipesRequest = () => {
return {
type: actionTypes.FETCH_RECIPES_REQUEST
}
}
export const fetchRecipesSuccess = recipes => {
return {
type: actionTypes.FETCH_RECIPES_SUCCESS,
payload: recipes
}
}
export const fetchRecipesFailure = error => {
return {
type: actionTypes.FETCH_RECIPES_FAILURE,
payload: error
}
}
export const fetchRecipes = (page) => {
return (dispatch) => {
dispatch(fetchRecipesRequest)
axios
.get('https://api.punkapi.com/v2/beers?page=1')
.then(response => {
const recipes = response.data;
dispatch(fetchRecipesSuccess(recipes));
})
.catch(error => {
const errorMsg = error.message;
dispatch(fetchRecipesFailure(errorMsg));
})
}
}
I want to create a scroll. I need, firstly, to display first 10 elements and then to add 5 elements with every loading. I have 25 elements altogether and when the list is done it should start from the first five again.