react accordion component collapse in another component - javascript

I have two component in my project. I have below component in my 1st component
import React, { useContext, useState, useEffect, useMemo, useRef } from "react";
function Invoice() {
const accordionRef = useRef(null);
const toggleAccordion = () => {
accordionRef.current.click();
}
}
2nd component
import React, { useContext, useState, useEffect, useMemo, useRef } from "react";
function Modal() {
toggleAccordion ();
}
}
I need to call 'toggleAccordion()' function inside the second component. how i do it

There are different ways to do it.
If one component is inside another component then you can pass reference of function to child component and call from there.
If components are not nested then you can use react context

1- Pass function as props
import React, { useContext, useState, useEffect, useMemo, useRef } from "react";
function Invoice() {
const accordionRef = useRef(null);
const toggleAccordion = () => {
accordionRef.current.click();
}
return (<Modal toggle={toggleAccordion }/>);
}
import React, { useContext, useState, useEffect, useMemo, useRef } from "react";
function Modal({toggle}) {
toggle();
}
}
2- Configure store (Context API or Redux)
checkout this open-sourced repository which shows both ways, see here

You can manage your components with props which are the part of app state. In case you change something inside you child component depending on events or data in the parent one you should pass the proper props:
const Child = ({color}) => <p style={{"color":color}}>{color}</p>
const Parent = () => {
const [childColor, setChildColor] = useState("#faa")
return <Child color={childColor} />
}
Finally, you may also send you function from the parent component as the prop
In the example above you utilize the prop "color" just to show the data. But also you can check the new value and decide what should be done further with useEffect hook help:
const Child = ({color}) => {
useEffect(()=>{
switch (color) {
case "#fff":
console.log('the color is white')
break
case "#000":
console.log('the color is black')
break
default:
console.log(`the color's code is ${color}`)
}
}, [color])
<p style={{"color":color}}>{color}</p>
}
Here you catch the new data value and make a decision whether anything should be done or not. You can call any functions, set up className etc, but the main idea s all these should be based on state / props change.
You can also define function in you parent component and then send it to the child component as prop:
const Child = ({func}) => {
func("Hi")
return null
}
const Parent = () => {
const func = (str) => {
console.log(str)
}
return <Child func={func} />
}

Related

How to return data from a React Functional Component

I would like to return data in the form of a String, JSON object or integer, or any other data other a JSX component, but without breaking the Rules of Hooks. Is there a way to do this in React?
I need to go about it this way since I need access to React Hooks.
import {} from 'react-native';
import React, {useEffect} from 'react';
export function revGetUserEntities({revCallbackFunction}) {
let myData;
useEffect(() => {
// Set myData here, or do something with it before returning;
}, []);
return myData;
}
Thank you all in advance.
Create a custom hook
a common practice is use the word use before the name of your function
i would recommend to rename function to useRevGetUserEntities
import {} from 'react-native';
import React, {useEffect} from 'react';
export function useRevGetUserEntities({revCallbackFunction}) {
// let myDate; this will be undefined on rerender. use state
const [myDate,SetMyDate] =React.useState(null);
useEffect(() => {
// Set myData here, or do something with it before returning;
SetMyDate(your value)
}, []);
return [myData];
}
now you can reuse it in any other function without losing state or value on rerender
note you can also pass a callback function in hooks
const [myData] = useRevGetUserEntities((callbackValue)=>{
// revCallbackFunction from useRevGetUserEntities function will be
})
Edit you can also watch for myData change in parent Observe changes
this will enter code here fire once myData value changes in Parent function
React.useEffect(()=>{
if(myData !== null){
}
},[myData]

Add useContext() on JSON export

I want to create a list of functionalities that I can access easily from anywhere on my app by simply importing the component. Here is what my component looks like:
functionalities.component.jsx
import { AES } from "crypto-js"
import { useContext, useState } from "react"
import { ConfigurationContext } from "../env"
const {configurationState} = useContext(ConfigurationContext);
const Functionalities = {
encrypt: (info) => AES.encrypt(info, configurationState.application.key).toString();
}
export default Functionalities
The problem I'm facing now is that I'm not able to use any context values since it would cause an error. Is there a way to implement "useContext" on this?
You can call a React Hook only inside a React component or inside a custom hook, it's one of the rules of the hooks.
The best you could do, if you need to share common functionalities, is creating a set of custom hooks.
import { AES } from "crypto-js"
import { useContext } from "react"
import { ConfigurationContext } from "../env"
const Functionalities = {
useEncrypt: () => {
const { configurationState } = useContext(ConfigurationContext);
return (info) => AES.encrypt(info, configurationState.application.key).toString();
}
};
export default Functionalities;
Example usage (always remember to call useContext inside a Context.Provider).
function EncryptComponent({info}) {
const encrypt = Functionalities.useEncrypt();
return <button onClick={() => encrypt(info)}>Encrypt</button>
}
I provide a CodeSandbox example that show how to do that.

Props alternative to pass the component state to all the components of application in next.js

I want to pass the setState method of the component (SnackBar) to all the child components of the _app.js. If I pass the setState method of SnackBar to all the child components of _app.js then it will be a very tedious task. Because, there are approx 4 levels of hierarchy from _app.js to the single component node. It includes,
_app.js -> pages -> layouts -> sections -> components
The snippet of _app.js is here.
function MyApp({ Component, pageProps }) {
const [ toastOpen, setToastOpen ] = React.useState({
msg: '',
open: false
});
React.useEffect(() => {
pageProps = { ...pageProps, setToastOpen };
}, []);
return (
<React.Fragment>
<ToastMessage
message={ toastOpen.msg }
setOpenState={ setToastOpen }
openState={ toastOpen.open }
/>
<Component {...pageProps} />
</React.Fragment>
)
}
Is there any way that I can directly import the setToastOpen method in the child component and use it whenever I need it?
React have a special Feature called Context Api , using that you can skip the props chain passed into your components..
I recomend you to checkout below resources to learn about context Api -
https://reactjs.org/docs/context.html
https://www.freecodecamp.org/news/react-context-in-5-minutes
Example of ContextAPI
Create a seperate file for Context Toast-context.js , You can use any name you want.
import React, { useState } from "react"
const ToastContext = React.createContext({
message: "",
toastOpen: false,
toggleToast: () => { },
changeMessage: () => { }
})
export const ToastContextProvider = ({children}) => {
/*you need to use
this component to wrap App.js so that the App.js and all of its children
and their children components and so on will get the access to the
context*/
const [toastOpen, setToastOpen] = useState(false);
const [message, setMessage] = useState("");
const toggleToast = () => {
setToastOpen(true)
}
const changeMessage = (message) => {
setMessage(message);
}
return (
<ToastContext.Provider value={
toastOpen,
message,
toggleToast,
changeMessage
}>
{children}
</ToastContext.Provider>
)
}
now in the App.js file you need to wrap your components with ToastContextProvider component
import React, { useContext } from "react";
import { ToastContextProvider } from "./Toast-context";
import { ToastContext } from "./Toast-context";
function MyApp({ Component, pageProps }) {
const { message, toastOpen, toggleToast, changeMessage } =
useContext(ToastContext);
return (
<ToastContextProvider>
{toastOpen && <div className="toast">{message}</div>}
</ToastContextProvider>
);
}
just import the context using useContext Hook in any component you want. you don't need to wrap with <ToastContextProvider> in every component.
just use useContext hook and then you can see the state and as well as call the functions methods to change the state.
Also make sure to refer the above links to learn more about Context Api. Thank You

Custom hook's state does not update across all components?

import { useState } from 'react';
export default function usePrivacyMode() {
const [isPrivacyOn, setIsPrivacyOn] = useState(false);
return {
isPrivacyOn,
setIsPrivacyOn
};
}
This is my custom hook. I set the state in PrivacyIcons component, and then I use isPrivacyOn for show/hide values from a table based on the value. But in a different component the isPrivacyOn is not changed, it's changed only in PrivacyIcons? Why I can't change it in one component and then use the value across all components? Thanks.
states are not meant to be shared across components. You are looking for useContext. This allows you to share a function and a state between components. React has an excellent tutorial on how to do it in the official documentation: https://reactjs.org/docs/hooks-reference.html#usecontext
For your specific example it would look something like this:
Your App.js
import { useState } from 'react';
export const PrivacyContext = createContext([]);
const App = (props) => {
const [isPrivacyOn, setIsPrivacyOn] = useState(false);
return (
<PrivacyContext.Provider value={[isPrivacyOn, setIsPrivacyOn]}>
<ComponentUsingPrivacyContext />
{props.children}
</PrivacyContext.Provider>
);
};
export default App;
Keep in mind that any component that wants access to that context must be a child of PrivacyContext
Any component that wants to use PrivacyContext:
import React, { useContext } from "react";
import {PrivacyContext} from "...your route";
const ComponentUsingPrivacyContext = (props) => {
const [isPrivacyOn, setIsPrivacyOn] = useContext(PageContext);
return (
<button onclick={setIsPrivacyOn}>
Turn Privacy On
</button>
<span>Privacy is: {isPrivacyOn}</span>
);
};
export default ComponentUsingPrivacyContext;

Adding refs to components passed in an array

I'm trying to make a component that takes a list of other components as a prop and then renders one of those components as a child according to an index held in the parent's state.
Ultimately I want to be able to call the 'getValidation' function of a child element in the array using imperative handler and forwardRef methodology. I've done this for a single child component but can't figure out how to do it with an array of children. I thought about creating an array of refs in the parent component but couldn't get that right. Would appreciate any help and alternative ways of going about this are more than welcome.
E.g.
Parent:
import React, {createRef, useRef, useEffect, useState} from 'react';
const Parent = props => {
const [currentChildIndex, setCurrentChildIndex] = useState(0);
return (
<div className='parent'>
{
props.children[currentChildIndex]
}
</div>
)
};
export default Parent;
Child:
import React, {forwardRef, useEffect, useImperativeHandle, useRef} from 'react';
const Child = forwardRef((props, ref) => {
isValidated() {
//stuff that validates the form
return true;
}
useImperativeHandle(ref, () => ({
getValidation() {
return isValidated();
}
}));
return (
<div className='child'>
{form with inputs and things}
</div>
)
});
export default Child;
So I'm not sure if this is the best way to do it but I was having trouble asigning the refs to my array from inside the render method of the Parent component so I made a function to render the child component and called that from the render method and it seems to be working:
import React, {createRef, useRef, useEffect, useState} from 'react';
const Parent = props => {
const [currentChildIndex, setCurrentChildIndex] = useState(0);
function renderChildComponent(CurrentComponent) {
return (
<CurrentComponent ref={childRefs[currentChildIndex] = createRef()} />
)
}
return (
<div className='parent'>
{
renderChildComponent(props.children[currentChildIndex])
}
</div>
)
};
export default Parent;

Categories