How can I set data createContext? - javascript

How can I set data into the state?
And how can I solve createContext error?
export const LastChanceContext = createContext() //in there return error: Expected 1 arguments, but got 0.
export const GET_LASTCHANCE = "GET_LASTCHANCE"
const LastChanceWrapper = ({children} : {children:any}) => {
const initialState = {
lastChances: [],
lastChance: {}
};
console.log('asd',initialState);
const [state, dispatch] = useReducer(lastChanceReducer, initialState);
useEffect(() => {
const getLastChance = async () => {
const result = await axiosFetch('http://65.21.148.176:2803/api/Home/Get');
const action = {
type:GET_LASTCHANCE,
payload:result.data.data.lastChanceList
};
if(Object.keys(result).length !== 0) {
dispatch(
{state,
action}
)
console.log(result.data.data.lastChanceList);
}
};
getLastChance();
}, [])
return (
<LastChanceContext.Provider value={{
lastChances: state.lastChances,
lastChance: state.lastChance
}}>
{children}
</LastChanceContext.Provider>
)
}
export default LastChanceWrapper

Related

React hooks render more hooks issue

I have used more than two react hooks together and I get this issue where there is no error with my frontend other than render hooks. I don't know how to resolve this error. I tried even using useState method.
If there is a possible fix can you let me know?
const Login = () => {
const { register, handleSubmit, setValue } = useForm();
const onSubmit = useCallback((formData) => {
const { email, password } = formData;
console.log(formData);
}, []);
const windowWidth = Dimensions.get("window").width;
const windowHeight = Dimensions.get("window").height;
const [loaded] = useFonts({
Lato: require("../assets/fonts/Lato-Regular.ttf"),
});
if (!loaded) {
return null;
}
const onChangeField = useCallback(
(name) => (text) => {
setValue(name, text);
},
[]
);
useEffect(() => {
register("email");
register("password");
}, [register]);
return (
);
};
export default Login;
Your app must call the same number of hooks every render. So you need to move
if (!loaded) {
return null;
}
to be below all of your hooks:
const Login = () => {
const { register, handleSubmit, setValue } = useForm();
const onSubmit = useCallback((formData) => {
const { email, password } = formData;
console.log(formData);
}, []);
const windowWidth = Dimensions.get("window").width;
const windowHeight = Dimensions.get("window").height;
const [loaded] = useFonts({
Lato: require("../assets/fonts/Lato-Regular.ttf"),
});
const onChangeField = useCallback(
(name) => (text) => {
setValue(name, text);
},
[]
);
useEffect(() => {
register("email");
register("password");
}, [register]);
if (!loaded) {
return null;
}
return (
);
};
export default Login;

Push Array React Native Keep Replace And Not Append

What is the correct way to use push array in React native ?
const BuilderIndicatorCard = (props) => {
const [isChecked, setIsChecked] = useState(false);
const [checkedValue, setCheckedValue] = useState([]);
let storeCheckedValue = [];
useEffect(() => {
if (isChecked) {
storeCheckedValue.push(props.indicator);
}
console.log(storeCheckedValue);
}, [isChecked, checkedValue])
// const removeCheckedStrategy = (checkedValue, array) => {
// var copyArray = [...array];
// var index = copyArray.indexOf(checkedValue);
// if (index !== -1) {
// copyArray.splice(index, 1);
// setArray(copyArray);
// }
// }
return (
<CheckBox
containerStyle={styles.checkbox}
size={15}
textStyle={styles.name}
title={props.indicator}
checked={isChecked}
onPress={() => {setIsChecked(!isChecked)}}
/>
);
};
When I do storeCheckedValue.push(props.indicator); why the array keep replace and not append ?
This is show in the console :
Array [
"Price Below MA (5)",
]
Array [
"Price Below MA (7)",
]
Array [
"Price Below MA (9)",
]
did I miss something in here ?
I found a proper way to solve my question above.
This is how I did it.
I use redux-toolkit
Create a slice like :
import { createSlice } from '#reduxjs/toolkit'
const addChecked = (state, action) => {
state.indicator = [...state.indicator, action.payload];
}
const removeChecked = (state, action) => {
state.indicator = state.indicator.filter(data => data != action.payload);
}
// status: 'idle' | 'loading' | 'succeeded' | 'failed',
export const BuilderSlice = createSlice({
name: 'Builder',
initialState: {
indicator: [],
status: 'idle',
error: null
},
reducers: {
addCheckedIndicator: addChecked,
removeCheckedIndicator: removeChecked
},
extraReducers: {
}
});
export const { addCheckedIndicator, removeCheckedIndicator } = BuilderSlice.actions
Then In the card component I change to like this :
import { addCheckedIndicator, removeCheckedIndicator } from '../redux/slice/builder/BuilderSlice';
const BuilderIndicatorCard = (props) => {
const dispatch = useDispatch();
const data = useSelector(state => state.Builder.indicator);
const [isChecked, setIsChecked] = useState(true);
const addValue = useCallback(() => {
setIsChecked(!isChecked);
if (isChecked) {
dispatch(addCheckedIndicator(props.indicator));
} else {
dispatch(removeCheckedIndicator(props.indicator));
}
}, [isChecked]);
return (
<CheckBox
containerStyle={styles.checkbox}
size={15}
textStyle={styles.name}
title={props.indicator}
checked={props.checked}
onPress={() => {addValue()}}
/>
);
};
I dispatch the function in slice in here:
dispatch(addCheckedIndicator(props.indicator));
dispatch(removeCheckedIndicator(props.indicator));
And then make sure use :
const addValue = useCallback(() => {
},[second]);
Not useEffect.

Filter array and show results in React

I am trying to filter my results via button onClicks in React, but for some reason its not working?
https://stackblitz.com/edit/react-x7tlxr?file=src/App.js
import React, {useEffect, useState} from "react";
import axios from 'axios';
import "./style.css";
export default function App() {
const [fetchData, setFetchData] = useState([]);
const [loading, setLoading] = useState(true);
const [isError, setIsError] = useState(false);
const url = 'https://jsonplaceholder.typicode.com/todos';
useEffect(() => {
let mounted = true;
const loadData = async () => {
try {
const response = await axios(url);
if (mounted) {
setFetchData(response.data);
setLoading(false);
setIsError(false);
console.log('data mounted')
}
} catch (err) {
setIsError(true)
setLoading(false);
setFetchData([]);
console.log(err);
}
};
loadData();
return () => {
mounted = false;
console.log('cleaned');
};
},
[url]
);
const renderdata = () => {
if (fetchData) {
return (
<div>{fetchData.map(inner => {
return (
<React.Fragment key={inner.id}>
<p>{inner.title}</p>
</React.Fragment>
)
})}</div>
)
} else {
<p>No data to display!</p>
}
}
const handle1 = () => {
const result1 = fetchData.filter((inner) => inner.id === '1');
setFetchData(result1);
}
const handle2 = () => {
const result2 = fetchData.filter((inner) => inner.id === '2');
setFetchData(result2);
}
const handleAll = () => {
setFetchData(fetchData);
}
return (
<div>
<button onClick={handleAll}>Show all</button>
<button onClick={handle1}>Filter by id 1</button>
<button onClick={handle2}>Filter by id 2</button>
{renderdata()}
</div>
);
}
The id is a number, not a string, so you filter(s) need to be changed like that:
const result1 = fetchData.filter((inner) => inner.id === 1);
You have another problem, is that you change the whole data set when you filter, so once you've filtered, you can't "unfilter" or filter again on another id.
You need to maintain the original fetchedData unchanged.
This example shows how it can be fixed.
I found 2 issues in your code
Id in the API result is numeric not string
inner.id === '2'. so this will return false inner.id === 2 you need to use like this
when you assign the filtered value to the original array it will of course change the original array so when you try to filter it second time you don't have the original API result in the fetch data array because it is already filtered
So i have created one more array filteredData
This will work.
import React, {useEffect, useState} from "react";
import axios from 'axios';
import "./style.css";
export default function App() {
const [fetchData, setFetchData] = useState([]);
const [filteredData, setFileredData] = useState([]);
const [loading, setLoading] = useState(true);
const [isError, setIsError] = useState(false);
const url = 'https://jsonplaceholder.typicode.com/todos';
useEffect(() => {
let mounted = true;
const loadData = async () => {
try {
const response = await axios(url);
if (mounted) {
setFetchData(response.data);
setFileredData(response.data)
setLoading(false);
setIsError(false);
console.log('data mounted')
}
} catch (err) {
setIsError(true)
setLoading(false);
setFetchData([]);
console.log(err);
}
};
loadData();
return () => {
mounted = false;
console.log('cleaned');
};
},
[url]
);
const renderdata = () => {
if (filteredData) {
return (
<div>{filteredData.map(inner => {
return (
<React.Fragment key={inner.id}>
<p>{inner.title}</p>
</React.Fragment>
)
})}</div>
)
} else {
<p>No data to display!</p>
}
}
const handle1 = () => {
const result1 = fetchData.filter((inner) => inner.id === 1);
setFileredData(result1);
}
const handle2 = () => {
const result2 = fetchData.filter((inner) => inner.id === 2);
setFileredData(result2);
}
const handleAll = () => {
setFileredData(fetchData);
}
return (
<div>
<button onClick={handleAll}>Show all</button>
<button onClick={handle1}>Filter by id 1</button>
<button onClick={handle2}>Filter by id 2</button>
{renderdata()}
</div>
);
}

Using the Context API gives me undefined

So I'm using Auth0 for my user sign up. I'm trying to get the user id under sub:value to add to my database to identify with the post of a user. I'm trying to use a Context API in order to get the user info to put in my database.
react-auth0-spa.js
// src/react-auth0-spa.js
import React, { useState, useEffect, useContext } from "react";
import createAuth0Client from "#auth0/auth0-spa-js";
const DEFAULT_REDIRECT_CALLBACK = () =>
window.history.replaceState({}, document.title, window.location.pathname);
export const Auth0Context = React.createContext();
export const useAuth0 = () => useContext(Auth0Context);
export const Auth0Provider = ({
children,
onRedirectCallback = DEFAULT_REDIRECT_CALLBACK,
...initOptions
}) => {
const [isAuthenticated, setIsAuthenticated] = useState();
const [user, setUser] = useState();
const [auth0Client, setAuth0] = useState();
const [loading, setLoading] = useState(true);
const [popupOpen, setPopupOpen] = useState(false);
useEffect(() => {
const initAuth0 = async () => {
const auth0FromHook = await createAuth0Client(initOptions);
setAuth0(auth0FromHook);
if (window.location.search.includes("code=") &&
window.location.search.includes("state=")) {
const { appState } = await auth0FromHook.handleRedirectCallback();
onRedirectCallback(appState);
}
const isAuthenticated = await auth0FromHook.isAuthenticated();
setIsAuthenticated(isAuthenticated);
if (isAuthenticated) {
const user = await auth0FromHook.getUser();
setUser(user);
}
setLoading(false);
};
initAuth0();
// eslint-disable-next-line
}, []);
const loginWithPopup = async (params = {}) => {
setPopupOpen(true);
try {
await auth0Client.loginWithPopup(params);
} catch (error) {
console.error(error);
} finally {
setPopupOpen(false);
}
const user = await auth0Client.getUser();
setUser(user);
setIsAuthenticated(true);
};
const handleRedirectCallback = async () => {
setLoading(true);
await auth0Client.handleRedirectCallback();
const user = await auth0Client.getUser();
setLoading(false);
setIsAuthenticated(true);
setUser(user);
};
return (
<Auth0Context.Provider
value={{
isAuthenticated,
user,
loading,
popupOpen,
loginWithPopup,
handleRedirectCallback,
getIdTokenClaims: (...p) => auth0Client.getIdTokenClaims(...p),
loginWithRedirect: (...p) => auth0Client.loginWithRedirect(...p),
getTokenSilently: (...p) => auth0Client.getTokenSilently(...p),
getTokenWithPopup: (...p) => auth0Client.getTokenWithPopup(...p),
logout: (...p) => auth0Client.logout(...p)
}}
>
{children}
</Auth0Context.Provider>
);
};
other.js (trying to get user info from react-auth0-spa.js)
class AddAlbum extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
let value = this.context;
console.log(value);
}
render() {
return (
)
}
AddAlbum.contextType = Auth0Context;
This gives me user: undefined
In my index.js I have this
ReactDOM.render(
<Auth0Provider
domain={config.domain}
client_id={config.clientId}
redirect_uri={window.location.origin}
onRedirectCallback={onRedirectCallback}
>
<App />
</Auth0Provider>,
document.getElementById("root")
);
Which I believe is giving me these results:
So I'm wondering why my Context API isn't working and giving me user: undefined.
You're logging the user when the component first mounts, which is long before the await auth0FromHook.getUser() call will complete. Log it in a componentDidUpdate, or check in a parent if that value is available, and don't mount the child component until it is.

How to access child's state in React? (React Hooks)

What's the best solution to get access to the child's state using react-hooks?
I've tried various approaches. Below the one that I've ended up with.
Form (Parent)
export const Form: FunctionComponent<IProps> = ({ onFinish, initState }) => {
const formInputsStateRef = useRef({})
const handleFinish = () => {
const params = formInputsStateRef.current
console.log(params)
onFinish(params)
}
return (
<div>
<Inputs initState={initState} stateRef={formInputsStateRef} />
<S.Button onClick={handleFinish}>
Finish
</S.Button>
</div>
)
}
Inputs (Child)
export const Inputs: FunctionComponent<IProps> = ({ initState, stateRef }) => {
const [pool, setPool] = useState(initState.pool)
const [solarPanel, setSolarPanel] = useState(initState.solarPanel)
useEffect(() => {
stateRef.current = { pool, solarPanel }
})
const handlePoolInput = () => {
setPool('new pool')
}
const handleSolarPanelInput = () => {
setSolarPanel('new solar panel')
}
return (
<div>
<h2>{pool}</h2>
<S.Button onClick={handlePoolInput}>Change pool</S.Button>
<h2>{solarPanel}</h2>
<S.Button onClick={handleSolarPanelInput}>Change solar panel</S.Button>
<h2>-----</h2>
</div>
)
}
It works that way but I don't like the fact that it creates an object on every render.
Inputs(Child)
useEffect(() => {
stateRef.current = { pool, solarPanel }
})
You could pass pool and solarPanel as the second argument to useEffect so that the state is updated to ref only on these values change
export const Inputs: FunctionComponent<IProps> = ({ initState, stateRef }) => {
const [pool, setPool] = useState(initState.pool)
const [solarPanel, setSolarPanel] = useState(initState.solarPanel)
useEffect(() => {
stateRef.current = { pool, solarPanel }
}, [pool, solarPanel])
const handlePoolInput = () => {
setPool('new pool')
}
const handleSolarPanelInput = () => {
setSolarPanel('new solar panel')
}
return (
<div>
<h2>{pool}</h2>
<S.Button onClick={handlePoolInput}>Change pool</S.Button>
<h2>{solarPanel}</h2>
<S.Button onClick={handleSolarPanelInput}>Change solar panel</S.Button>
<h2>-----</h2>
</div>
)
}
However to have a more controlled handle of child values using ref, you can make use of useImperativeHandle hook.
Child
const InputsChild: FunctionComponent<IProps> = ({ initState, ref }) => {
const [pool, setPool] = useState(initState.pool)
const [solarPanel, setSolarPanel] = useState(initState.solarPanel)
useImperativeHandle(ref, () => ({
pool,
solarPanel
}), [pool, solarPanel])
const handlePoolInput = () => {
setPool('new pool')
}
const handleSolarPanelInput = () => {
setSolarPanel('new solar panel')
}
return (
<div>
<h2>{pool}</h2>
<S.Button onClick={handlePoolInput}>Change pool</S.Button>
<h2>{solarPanel}</h2>
<S.Button onClick={handleSolarPanelInput}>Change solar panel</S.Button>
<h2>-----</h2>
</div>
)
}
export const Inputs = forwardRef(InputsChild);
Parent
export const Form: FunctionComponent<IProps> = ({ onFinish, initState }) => {
const formInputsStateRef = useRef({})
const handleFinish = () => {
const params = formInputsStateRef.current
console.log(params)
onFinish(params)
}
return (
<div>
<Inputs initState={initState} ref={formInputsStateRef} />
<S.Button onClick={handleFinish}>
Finish
</S.Button>
</div>
)
}

Categories

Resources