Change state value in context file from child component? - reactjs

Trying to understand context api, and I understand props are passed down. I am trying to change state of my Context file's value to another number like 50.
Created Context File
import React, { useState, createContext } from "react";
export const PointsContext = createContext();
export const PointsProvider = (props) => {
const [points, setPoints] = useState(0);**<--WANT TO CHANGE THIS**
return <PointsContext.Provider value={points}>{props.children}</PointsContext.Provider>;
};
Wrapped Everything In Provider in App.js
import {PointsProvider } from "./PointsContext";
<PointsProvider>
<ChildComponent>
</PointsProvider>
The "ChildComponent" is Provided Context
import React, { useState, useEffect, useContext } from "react";
import { PointsContext } from "../PointsContext";
const value = useContext(PointsContext);
return(
<Button title="ChangeNumber" onPress={() => Change value to 50 }/>
)

I figured it out, instead of importing
const value = useContext(PointsContext);
import this, which gives access to the setState in the context file. As long as you import this on to any screen you will have access to that useState to change stuff.
const [points, setPoints] = useContext(PointsContext);
the rest might go something like this!
<Button title="ChangeNumber" onPress={() => setPoints(50)}/>
<Text>{points}</Text>
This tutorial helped alot thanks devEd, he is one of my favs!
DevEd Youtube React State

Related

How to render new value of array in react

Here I am getting my data from child component and trying to add it into existing array and also I am trying to display it in console using map but the moment I try to to do so I get nothing in console:
import "./App.css";
import Home from "./Components/Home";
import {useState} from 'react';
let App = () => {
let DataList = ["Apple","Banana"];
const newList = (data)=>{
DataList = [...DataList,data];
}
return (
<div>
<Home newList = {newList}/>
{ DataList.map((val)=>(
console.log(val)
))
}
</div>
)
};
export default App;
You need to use React hooks to make it work, then only your component will rerender
import "./App.css";
import Home from "./Components/Home";
import {useState} from 'react';
let App = () => {
const [DataList, setDataList] = useState(["Apple","Banana"]);
const newList = (data)=>{
let temp = [...DataList,data];
setDataList(temp);
}
return (
<div>
<Home newList = {newList}/>
{ DataList.map((val)=>(
console.log(val)
))
}
</div>
)
};
export default App;
You imported this for a reason, use it:
import {useState} from 'react';
React won't detect changes to any random variable you declare. So there's no reason for it to re-render the component in the code you have.
State values are fundamental to React. It's how you persist data across renders, and it's how React knows to re-render any given component. Store your data in state:
const [dataList, setDataList] = useState(["Apple","Banana"]);
And use that setter function to update the state:
const newList = (data)=>{
setDataList([...dataList, data]);
};
When React sees that state was updated, it will queue a re-render of the component (in this case re-invoking the App function internally to the framework) so the new state can be used.

Why my useState from Context doesn't update

Hello I try to save the fatched data from my database to my variable selectedRestaurant. I use setSelectedrestaurant in the useEffekt hook but it doesn't update my variable. I get as a value null.
Here is my code
import React, { useContext, useEffect, useState } from 'react';
import { useParams } from 'react-router';
import RestaurantFinder from '../api/RestaurantFinder';
import { RestaurantsContext } from "../context/RestaurantsContext";
import Reviews from '../components/Reviews';
import StarComponent from '../components/StarComponent';
import AddReview from '../components/AddReview';
import Test from '../components/Test';
const RestaurantDetailedPage = (props) =>{
//const{ selectedRestaurant, setSelectedRestaurant}= createContext(RestaurantsContext);
const[ selectedRestaurant, setSelectedRestaurant]= useState(null);
const {id} = useParams();
useEffect(()=>{
const fetchData = async(id)=>{
const result = await RestaurantFinder.get("/"+id);
console.log(result);
setSelectedRestaurant(result.data.data);
console.log(selectedRestaurant);
}
fetchData(id);
},[]);//Wichtig, damit es nur 1x
/*
useEffect(()=>{
console.log("useEffect2");
console.log(selectedRestaurant);
},[selectedRestaurant]);
*/
return(
<div>{selectedRestaurant && (
<>
<div>{<AddReview/>}</div>
<div></div>
</>
)}
</div>
)
}
export default RestaurantDetailedPage;
I know that useEffect is async so I tried with await setSelectedRestaurant(result.data.data)
but it didn't work. I also defined two useEffects that should invoke only once. One for changing and the other for update but both useEffects are invoked twice. I dont know why and how to solve it.
Hope u can help me
Try tidying up your sample code. There are lot of poorly formatter comments and spelling errors that make it difficult to parse.
EDIT:
When you update the state (i.e. setSelectedRestraunt) those changes are batched together don't change the state variable until the next render loop.
If you want to console.log or otherwise use the data, create a useEffect which is dependent on that value.
import React, { useContext, useEffect, useState } from 'react';
import { useParams } from 'react-router';
import RestaurantFinder from '../api/RestaurantFinder';
import { RestaurantsContext } from "../context/RestaurantsContext";
import Reviews from '../components/Reviews';
import StarComponent from '../components/StarComponent';
import AddReview from '../components/AddReview';
import Test from '../components/Test';
const RestaurantDetailedPage = (props) =>{
const{ selectedRestaurant, setSelectedRestaurant}= createContext(RestaurantsContext);
const {id} = useParams();
useEffect(()=>{
const fetchData = async(id)=>{
const result = await RestaurantFinder.get("/"+id);
console.log(result);
setSelectedRestaurant(result.data.data);
}
fetchData(id);
},[]);
useEffect(()=>{
console.log("Selected Restaurant:", selectedRestaurant);
},[selectedRestaurant]);
return(
<div>{selectedRestaurant && (
<>
<div>{<AddReview/>}</div>
<div></div>
</>
)}
</div>
)
}
export default RestaurantDetailedPage;
Original comment
With that in mind, your <Reviews> element is commented out, is that intentional?
{/* <Reviews reviewsObject={selectedRestaurant.reviews}/>*/}

React.js - passing functions between components using Context API - not working

I am trying to pass a function between two components but even though I do not have any errors, the function that I am passing wont show or to be precise it is not working. I have two files and one of them is creating a context while the other is using it (obviously). Now, they are not shown in App.js (which is rendered in index.js, usual stuff) they are in the seperate folder. I am using React Router to show one the pages (News.js).
Here are the files:
NewsContext.js
import React, { useContext, createContext, useState, useEffect } from "react";
export const newsK = React.createContext();
export const NewsContext = (props) => {
const working = () => {
console.log("it is working");
};
return <newsK.Provider value={working}>{props.children}</newsK.Provider>;
};
export default NewsContext;
News.js
import React, { useContext, useState, useEffect } from "react";
import { newsK } from "./NewsContext";
import { NewsContext } from "./NewsContext";
const News = () => {
const data = useContext(newsK);
return (
<NewsContext>
<div>
<button onClick={data}></button>
</div>
</NewsContext>
);
};
export default News;
When i pressed the button, it wont do anything. Any tips?
You're trying to use context outside the NewsContext component
The solution for this will be to create a component that will call useContext inside NewsContext.
I.e.
const WrappedButton = () => {
const data = useContext(newsK)
return <button onClick={data} />
}
And then put it inside the NewsContext:
<NewsContext>
<div>
<WrappedButton />
</div>
</NewsContext>

useEffect socket.on problem rerendering useState

I'm looking for some help using socket.io-client. I'm having some issues trying to get all messages from the chat server. I'm supposed to get an individual message and I'll need to push to a state. I'm not getting rerender on each message. Is there any way to handle the state and update it? Thanks
import React, {useState, useEffect} from 'react'
import {withRouter} from 'react-router-dom'
import Button from '../core/Button'
import Field from '../core/Field'
import Label from '../core/Label'
import {Container, ScrollContainer} from './StyledComponents'
import useLocalStorageState from '../../hooks/useLocalStorage'
import io from 'socket.io-client'
import {SOCKET_SERVER_CLIENT} from '../../utils/const'
import Profile from '../Profile/Profile'
let socket
const Chat = ({location}) => {
const [listMessages, setListMessages] = useState([])
const [message, setMessage] = useState('')
useEffect(() => {
const username = location.search.split('=')[1]
socket = io(`${SOCKET_SERVER_CLIENT}/?username=${username}`)
return () => {
socket.disconnect()
}
}, [])
useEffect(() => {
socket.on('message', message => {
const auxArr = listMessages
auxArr.push(message)
setListMessages(auxArr)
})
})
return (
<Container>
{console.log('rerender')}
<ScrollContainer>
{listMessages &&
listMessages.map(infoMessage => (
<Profile key={infoMessage.time} {...infoMessage} />
))}
</ScrollContainer>
</Container>
)
}
export default withRouter(Chat)
const auxArr = listMessages
auxArr.push(message)
setListMessages(auxArr)
This code is mutating the old array, and then setting state with that same array. Function components do a check when setting state to make sure it changed. Since it's the same array before and after, the render gets skipped.
Instead of mutating the state, you will need to copy it:
const auxArr = [...listMessages];
auxArr.push(message);
setListMessages(auxArr);
Since you're basing the new state on the old one, you should also use the callback form of setting state, to eliminate any bugs that might happen if multiple set states happen at right about the same time:
setListMessage(prevMessages => {
const auxArr = [...prevMessages];
auxArr.push(message);
return auxArr;
})

Have to click twice to update state (useState hook) with onClick event

I've seen more questions being post here about this, but the solutions did not work for me.
The problem is that I: have to click twice to update the state of a constant defined using the useState hook
How can I make this work only having to click once?
Please see the code on CodeSandbox, or the code below:
App.js
import React, { useState } from "react";
import "./styles.css";
import Row from "./Row";
export default function App() {
const [adults, setAdults] = useState(1);
return <Row adults={adults} setAdults={setAdults} />;
}
Row.jsx
import React, { useEffect } from "react";
export default function({ adults, setAdults }) {
useEffect(() => {
console.log(adults);
}, [adults]);
return (
<>
<button onClick={() => setAdults(adults++)}>{adults}</button>
</>
);
}
Either do:
setAdults(adults+1)
or:
setAdults(++adults)
Be careful using ++ because someObject.counter++ will mutate someObject.

Resources