How to get response after a function call in React JS? - reactjs

Hi I am calling a function then trying to get response but it is saying undefined. I am passing that response from parent component to child component.
Component code is -
import React from 'react';
import {One, test, test1} from './Sample/SampleData';
let data:DataInterface = One;
const onChangeId = (Id:string) => {
switch (Id) {
case '1':
data = test
break;
case '2':
data = test1
break;
default:
data = One;
break;
}
console.log(data, " Data")
}
export const Test = () => {
return (
<div>
<ParentComponent
firstData={One}
onChangeId={onChangeId}
secondData={data}
/>
</div>
);
};
Parent Component code is -
import React from 'react';
export const ParentComponent = ({
firstData,
onChangeId,
secondData
}: NewInterface) => {
const [format, setFormat] = useState(secondData);
const onChange = (
type: string,
val:string
) => {
if (type === "welcome) {
onChangeId(val);
setTimeout(() => {
setFormat(secondData)
}, 2000)
console.log(secondData , "secondData")
}
};
return (
<React.Fragment>
<ChildComponent
onChange={onChange}
firstData={firstData}
newData={format}
/>
</React.Fragment>
);
}
When first tie component renders then I am getting secondData, but when I call onChangeId event I am getting secondData as undefined. So how can I resolve this issue ?
NOTE: We can't create seperate onChangeId event it must be inside onChange function as I am doing some other works too in ChildComponent.

Move useState hook outside of onChange method
export const ParentComponent = ({
firstData,
onChangeId,
secondData
}: NewInterface) => {
const [format, setFormat] = useState(secondData);
const onChange = (
type: string,
val:string
) => {
if (type === "welcome") {
onChangeId(val);
setTimeout(() => setFormat(secondData), 2000)
console.log(secondData , "secondData")
}
};

Related

React-redux component rerenders every time when and unconnected state changes in the store . How do I prevent it?

I have a component callled FileHeader. Everytime I resize a column in it, it dispatches an action to changes a state. This triggers a rerender.
ListeHeader.js
const ListHeader = props => {
const dispatch = useDispatch()
let headerRef = useRef(new Array())
const { header_ } = useSelector((state) => state.ui, shallowEqual)
const onResize = ( e, {event, node, size}) => {
dispatch(changeHeaderWidth(node.id, size.width))
}
return (
<HeaderBody>
{header_
.map((header) => {
const getRef = (element) => headerRef.current.push(element)
return (
<ResizableBox
axis="x"
width={header.width}
height={20}
key={header.id}
handle={<DragHandle id={header.id} />}
onResize={onResize}
minConstraints={[50, 20]}
maxConstraints={[300, 20]}
>
<Header
key={header.id}
width={header.width}
handleDrag={handleDrag}
onClick={handleSort(header.id)}
>
<HeaderText ref={getRef}>{header.name}</HeaderText>
</Header>
</ResizableBox>
)
})}
</HeaderBody>
)
}
This is my reducer
export default (state = initial_state, actions) => {
switch (actions.type) {
case consts.CHANGE_HEADER_WIDTH : return {
...state,
headerWidth: state.headerWidth.map((item) =>
item.id === actions.payload.id ? { ...item, width: actions.payload.neWidth}
: item),
}
break;
default: return state;
}
}
I'm not calling headerWidth state in my component it causes a rerender when it changes
From the docs
When passing a callback using dispatch to a child component, you may
sometimes want to memoize it with useCallback. If the child component
is trying to optimize render behavior using React.memo() or similar,
this avoids unnecessary rendering of child components due to the
changed callback reference.
import React, { useCallback } from 'react'
import { useDispatch } from 'react-redux'
export const CounterComponent = ({ value }) => {
const dispatch = useDispatch()
const incrementCounter = useCallback(
() => dispatch({ type: 'increment-counter' }),
[dispatch]
)
return (
<div>
<span>{value}</span>
<MyIncrementButton onIncrement={incrementCounter} />
</div>
)
}
export const MyIncrementButton = React.memo(({ onIncrement }) => (
<button onClick={onIncrement}>Increment counter</button>
))

passing object using context and doing iteration with map

This is a simple question but I couldn't reach the final result after a lot of attempts. The problem is that I want to pass an object in context and use it in another file. And then do an iteration and create a specific element for each value.
App.jsx
const [activities, setActivity] = useState([
{
key: Math.random() * Math.random(),
name: 'Hello',
}
]);
const inputValue = useRef(null);
const addActivity = () => {
const activity = {
key: Math.random() * Math.random(),
name: inputValue.current.value,
};
setActivity(activities.concat(activity));
};
const value = {
// I want to pass this parameter - only activities has problem (Activity.jsx <h1>)
// I can't achieve activities.name in Activity.jsx
activities: [...activities],
functions: {
addActivity: addActivity
},
ref: {
inputValue: inputValue
}
};
<Context.Provider
value={value}
>
Context.js
export const Context = createContext();
Activity.jsx
const { activities, functions, ref } = useContext(Context);
return (
<section className="activity-container">
<input type="text" ref={ref.inputValue} />
<button onClick={functions.addActivity}>add!</button>
{
activities.map(activity => (
<h1>activity.name</h1>
))
}
</section>
);
I believe this is what you want:
// Sharing data through context
Context file:
// Context.js
import React, { useState, useRef, createContext } from "react";
export const DataContext = createContext();
const getRandom = () => Math.random() * Math.random();
const defaultValue = {
key: getRandom(),
name: "Hello"
};
const ContextProvider = ({ children }) => {
const [activities, setActivity] = useState([defaultValue]);
const inputValue = useRef(null);
const addActivity = () => {
const activity = {
key: getRandom(),
name: inputValue.current.value
};
setActivity([...activities, activity]);
};
const value = {
activities: [...activities],
functions: { addActivity },
ref: { inputValue }
};
return <DataContext.Provider value={value}>{children}</DataContext.Provider>;
};
export default ContextProvider;
Hook to read from context:
// useDataContext
import { useContext } from "react";
import { DataContext } from "./Context";
const useDataContext = () => {
const contextValue = useContext(DataContext);
return contextValue;
};
export default useDataContext;
Child Element where you want to receive the value from context:
// Child.js
import React from "react";
import useDataContext from "./useDataContext";
const Child = () => {
const data = useDataContext();
return (
<>
{data.activities.map((val, idx) => (
<div key={idx}>Name is {val.name}</div>
))}
</>
);
};
export default Child;
And the App container:
// App.js
import Child from "./Child";
import ContextProvider from "./Context";
export default function App() {
return (
<div className="App">
<ContextProvider>
<Child />
</ContextProvider>
</div>
);
}
I've created a sandbox for you to test.
You should make sure that the Activity.jsx component is wrapped with context provider, to get the proper value from the context.
I tried in this codesandbox, and it's working properly. You can refer to this and check what you are missing.

ReactJs Functional Component - How to call function from outside?

How to call a function from outside of the functional component.
I have a functional component like this
import React, { useState } from 'react';
const Hello = () => {
// call updateField() here
};
const Headline = () => {
const [greeting, setGreeting] = useState(
'Hello Function Component!'
);
// Function inside Headline, I want to call this function in Hello()
const updateField = () => {
}
return <h1>{greeting}</h1>;
};
export default Headline;
I want to call updateField() in Hello() outside of Headline(). Please suggest.
Here are two ways to do this,
Method 1: Move the common state to a parent component
const ParentComponentWithHelloAndHeadline = () => {
const [field, setField] = useState()
const updateField = () => { ... }
return (
<>
<Headline field={field} updateField={updateField} />
<Hello updateField={updateField} />
</>
)
}
Method 2: Use React.Context (avoids prop-drilling, incase that is a concern using method 1)
const CommonContext = React.createContext({
field: 'commonField',
updateField: () => { ... }
})
const Hello = () => {
const { field, updateField } = useContext(CommonContext)
// call updateField() here
};
const Headline = () => {
const { field, updateField } = useContext(CommonContext)
const [greeting, setGreeting] = useState(
'Hello Function Component!'
);
return <h1>{greeting}</h1>;
};
export default Headline;
function RootApp() {
return (
<CommonContext.Provider>
<Headline />
...
...
<Hello />
</CommonContext.Provider>
);
}

React hooks useEffect calls mutiple times when redux store other data changed

my code like this:
Info component:
import {
getAttachData,
} from '#src/actions/creators/account'
const Info: React.FC = () => {
const info = useSelector<any, Account>(state => state.getIn(['account', 'info']).toJS())
const list = useSelector<any, Data[]>(state => state.getIn(['account', 'list']).toJS())
const attach = useSelector<any, AttachData[]>(state => state.getIn(['account', 'attach']).toJS())
...
const handleChange = ({ select }) => {
dispatch(getAttachData({v: select}))
}
const Template = (params) => {
return (
<div>
<BaseSelect onChange={(val) => handleChange(val)} list={list} />}
</div>
)
}
return (
...
<Template data={info} />
{attach.map((child, cidx) => (<Template data={child} />))}
)
}
export default Info
BaseSelect component:
const BaseSelect: React.FC<Props> = props => {
const [selectId, setSelectId] = useState('')
const { list } = props
useEffect(() => {
if (!isEmpty(list)) {
...
}
console.log('init')
}, [])
const handleChange = (value) => {
setSelectId(value)
props.onChange({
select: value,
})
}
return (
<Select
data={list}
value={selectId}
onChange={handleChange}
/>
)
}
export default BaseSelect
when excute handleChange event in BaseSelect component, the props.onChange function will call handleChange event in info component, and dispatch http request getAttachData which will change attach data in redux store, but useEffect in BaseSelect component will also excute and in console will print 'init' two times.
console:
It's because your Template component re-creates every time when redux store is changing.
Just move Template component outside the Info component.

Creating a Stepper using React and Redux

I am trying to create a Stepper using react and redux. The concept I am using for it is -
Store the active step in redux store.
I have a list of components and each component is associated with an index.
In parent component, I render the component whose index is equal to active step.
Here's the code for parent component -
I have component step map -
const COMPONENT_STEP_MAP = {
1: (props) => (
<Component1
{...props}
render = {(props) => <Buttons {...props}/>}
></Component1>
),
2: (props) => (
<Component2
{...props}
render = {(props) => <Buttons {...props}/>}
></Component2>
),}
Here's How my Redux Store looks like -
const initialState = {
activeTab: 1,
basicDetails: {
activeStep: 1,
name: '',
}
Here's the render function of the parent component -
export class ParentComponent extends React.component {
handleNext = () => {
if(this.props.activeStep == 1 &&
this.props.isBusinessOwner==false){ // isBusinessOwner is not showing correct value.
this.props.setActiveStep(this.props.activeStep + 2)
}
else this.props.setActiveStep(this.props.activeStep + 1);
};
handlePrevious = () => {
if(this.props.activeStep == 1 &&
this.props.isBusinessOwner==false){
this.props.setActiveStep(this.props.activeStep - 2);
} else
this.props.setActiveStep(this.props.activeStep - 1)
};
render() {
return ({Object.entries(COMPONENT_STEP_MAP).map((comp) => {
return comp[0] == this.props.activeStep
? comp[1]({handlePrevious, handleNext}):null}}) } }
I am using react-redux to connect it to the store -
const mapStateToProps = (state) => ({activeStep: state.ownerDetails.activeStep, isBusinessOwner: state.ownerDetails.isBusinessOwner});
const mapDispatchToProps = (dispatch) => ({
setActiveStep: (step) => dispatch({type: 'ownerDetails', payload:{activeStep: step}})
})
export default connect(mapStateToProps, mapDispatchToProps)(OwnerDetails);
Now I have following child component
import React from 'react';
import {useSelector, useDispatch} from 'react-redux';
export function IsOwner(props) {
const isOwner = useSelector(state => state.ownerDetails.isBusinessOwner);
const setIsBusinessOwner = useDispatch();
const handleChange = (value) => {
// console.log('value', value);
setIsBusinessOwner({type: 'ownerDetails', payload: {isBusinessOwner: value}})
props.handleNext();
};
return (
<div>
<h4>Are You Business Owner</h4>
<button onClick={handleChange.bind(null,true)}>Yes</button>
<button onClick={handleChange.bind(null,false)}>No</button>
</div>
)
}
I have doubt in following 2 lines -
setIsBusinessOwner({type: 'ownerDetails', payload: {isBusinessOwner: value}})
props.handleNext();
setIsBusinessOwner updates the store and will force the component to re-render.
However, I am immediately calling props.handleNext() after it , and component will be gone from the DOM.
So, When I access isBusinessOwner from store in parent component. It is reflecting the previous value not the updated value.
Any suggestions on how to fix this issue ?
Any help will be greatly appreciated.
Thanks in advance!! :)

Resources