How to properly pass parameter from one component to another component. In my scenario, When I console log my pass parameter to another component they have empty string first before the actual string in the last. Which is supposed to be the actual string only.
Component 1:
import React, {useState, useEffect} from 'react'
import {dataComponent} from './include/childComponent'
export default function Parentcomponent(props) {
const [data, setdata] = useState('');
function functioncalhttp(){
//data from database
setdata(response.data);
}
useEffect(() => {
functioncalhttp();
},[]);
return (
<div>{<dataComponent callbackfunction={data}/>}</div>
)
}
Compnent 2:
import React, {useState, useEffect} from 'react'
export default function dataComponent(props) {
console.log(props.callbackfunction);
return (
<div></div>
)
}
Screenshot:
At the core of react is the idea of rendering components when either its state or received props change. Props are always passed to components when they render, so here in your case, whenever data changes, the child component will receive your new data state on the callbackfunction prop, and rerender. If you want to "wait" to render children until data is ready, here is a demo using a guard pattern to include children when conditions are met:
React also provides a way to further hint to react when a component should rerender with a memo HOC that provides more control over the received props and selectively letting react know that a rerender isn't necessary.
Related
Question:
WHY does the code without array always iterate in relation compare to the code with array that only execute once?
Stackblitz:
Without array:
https://stackblitz.com/edit/react-ts-9w3cgd?file=App.tsx
With array:
https://stackblitz.com/edit/react-ts-xrrvan?file=App.tsx
Thank you!
Without array
import axios from 'axios';
import * as React from 'react';
import { useEffect, useState } from 'react';
import './style.css';
export default function App() {
const [data, setData] = useState();
useEffect(() => {
axios
.get('https://jsonplaceholder.typicode.com/users')
.then((result) => setData(result.data));
//console.log(data);
console.log('t');
});
return (
<div>
<h1>Hello StackBlitz!</h1>
<p>Start editing to see some magic happen :)</p>
</div>
);
}
With array
import axios from 'axios';
import * as React from 'react';
import { useEffect, useState } from 'react';
import './style.css';
export default function App() {
const [data, setData] = useState();
useEffect(() => {
axios
.get('https://jsonplaceholder.typicode.com/users')
.then((result) => setData(result.data));
console.log(data);
//console.log("t");
}, []);
return (
<div>
<h1>Hello StackBlitz!</h1>
<p>Start editing to see some magic happen :)</p>
</div>
);
}
From the official React hooks documentation:
If you want to run an effect and clean it up only once (on mount and unmount), you can pass an empty array ([]) as a second argument. This tells React that your effect doesn’t depend on any values from props or state, so it never needs to re-run. This isn’t handled as a special case — it follows directly from how the dependencies array always works.
Basically, a useEffect hook with an empty dependency array should run only once when the component mounts.
Alternatively, if we were to not include a dependency array, the callback will run every time the component re-renders.
Which occurs whenever there is a change in state or the state of any of it's parent components.
With that said, it's probably better to avoid using the useEffect hook without a dependency array, since we would usually want to use it to act in a specific way upon the change of a specific state.
Using it in such a way is valid, but not really advised.
Let's say I want to have a reusable react component in my project. I also want that component to have its state under different locations without losing it during component unmount. What is the correct way to deal with this kind of architecture in React? In other words, when the user navigates between these two routes react unmounts the previous component, therefore it loads remote data on every navigation between /user and /groups routes.
I also know that there is something called Redux. I don't see a clear way how to do it using reduct. Do I need two reducers? one for Users and the other for Groups? If so it's quite inconvenient creating a new reducer and write new logic each time when I need to use ReusableComponent.
Here is a similar skeleton to describe what I am trying to do. Any hint would be helpful.
//Router example
<Router>
<Switch>
<Route exact path=”/users” >
<UserComponent>
<ReusableComponent url=”http://apidomain.com/users” />
</UserComponent>
</Route>
<Route exact path=”/groups” >
<GroupComponent>
<ReusableComponent url=”http://apidomain.com/groups” />
</GroupComponent>
</Route>
</Switch>
</Router>
//ReusableComponent Example
<ReusableComponent>
--->use url, that passed from parent component tree(users or groups) to load data and keep in state
<ReusableComponentContext>
<Head />
<Body />
<Footer />
</ReusableComponentContext>
</ReusableComponent>
EDIT
So to describe my problem better is I need to have the same component with two or more parallel state on the different locations without overriding each other. If it's possible
I would use the "React Context" api. The context wrappes your app so if one component updates/ rerenderes the state which is stored inside of the context stayes untouched. To use Context you need three files:
"UserContext" = Example => rename!
Context Component (UserContext)
import { createContext } from "react"
export const UserContext = createContext(initValue)
Parent Component (Provider)
//filename: UserContext.js
//* import React, { useState } from "react"
//* import UserContext from "./UserContext"
const [state, setState] = useState("initState")
//* return(
<UserContext.Provider value={{state, setState}}> //value="props"
<ChildComponent/>
</UserContext.Provider>
Child Component (Consumer)
//*import React, { use Context } from "react";
//*import {UserContext} from "./UserContext"
const data = useContext(UserContext) //here "UserContext"
src: short explenation of usage
Edit: consuming with a custom hook
To avoid one import-statement you can create a custom Hook like this
import React, { use Context } from "react";
import {UserContext} from "./UserContext";
const useUserContext = (()=>{
const {state, setState} = useContext(UserContext)
//use effect if you want to set the context? with the hook...
return[state, setState]
})
in your remounting component
import useUserContext from "./useUserContext"
//rfce{
const {state, setState} = useUserContext()
//}
you can connect ReusableComponent to a piece of your redux store (see connect for more details).
import { connect } from "react-redux";
const ReusableComponent = (props) => {
// some logic before return
return <div>{props.magicProperty}</div>
}
const mapStateToProps = (state) => ({ magicProperty: state.magicProperty });
return connect(mapStateToProps)(ReusableComponent);
So every time you use ReusableComponent in you app, the magicProperty is shared, You can also connect some actions to the component in order to manage that part of state in the classical redux flow.
I think I found the solution. In my case, I had some misunderstanding on what level put context provider tag in the router component tree. So in React, it's very important to put the context provider wrapper in the right location. It holds a dedicated state only for those child components that are wrapped by that context provider.
In my case, I had ReusableComponentContext inside ReusableComponent and that was the wrong approach Because everywhere I used ReusableComponent it had individual context(Therefore individual state). I moved ReusableComponentContext on the top of a couple of components to solve my problem.
I'm writing chat app using react js and socket.io library.
All the logic where I subscribe to events form server and emit some events is written in useEffect of custom hook.
Then I return all data I need from this custom hook and reuse it in components that I need. However, I realized that logic written in useEffect is called every time I import this custom hook to external component.
If I put all the logic outside of useEffect, it's called even more times than custom hook is imported.
How do I prevent it if it's possible at all?
If it's not possible, what solution could you please suggest? I don't want to use redux for this app, I thought to keep everything in this custom hook component and just reuse data from it where I need.
I can't share working example because it won't work without server part so here is a simple codesandbox example. You can see in console that it's rendered twice.
https://codesandbox.io/s/custom-hook-bfc5j?file=/src/useChat.js
It renders twice because you call useChat() two times in your app (one in App.js, other in Text.js) What you can do is to create a reference of useChat component in your App.js and pass is as a prop to Text.js like:
App.js
import React from "react";
import useChat from "./useChat";
import Text from "./Text";
import "./styles.css";
export default function App() {
const myUseChat = useChat();
const { printMessage } = myUseChat;
return (
<div className="App">
<button onClick={printMessage}>Print</button>
<Text myUseChat={myUseChat} />
</div>
);
}
Text.js
import React from "react";
import useChat from "./useChat";
import "./styles.css";
export default function Text(props) {
const { text } = props.myUseChat;
return <div className="App">{text}</div>;
}
If you want to set up some side effects once but also consume the resulting data in multiple places, one way is to use the context feature.
// ws/context.jsx, or similar
const WsContext = React.createContext(defaultValue);
export const WsProvider = props => {
const [value, setValue] = useState(someInitialValue);
useEffect(() => {
// do expensive things, call setValue with new results
});
return (
<WsContext.Provider value={value}>
{props.children}
</WsContext.Provider>
);
};
export const useCustomHook = () => {
const value = useContext(WsContext);
// perhaps do some other things specific to this hook usage
return value;
};
You can expect the hook to work in any component that is a descendant of <WsProvider> in React's rendered tree of elements.
If you use the hook in a non-descendant of the provider component, the value returned will be the defaultValue we initialized the context instance with.
I am rendering my react component inside an existing JSP page using
ReactDOM.render(
React.createElement(MyReactComponents.myReactComponent, {
props
}),
document.querySelector("#id")
);
and the react component is as follows:
import MyStore from "./MyStore";
const MyReactComponent: React.FC<any> = (props: any) => {
const store = useContext(MyStore);
store.myFunction();
---code---
}
and MyStore is as follows:
export class MyStore{
---Code---
}
export default createContext(new MyStore());
But i'm getting this error:
And one more importing thing to notice is that when I'm trying to render this react component on top of another existing react component, i'm not getting any error and everything is working fine.
Can someone please explain me what might be causing the issue?
I'm not sure, but maybe you are misusing the useContext hook?
Whenever you use it inside a component Child, then at least one of its parent component must call the <Context>.Provider, so that it is initialized down the tree.
In your example, you render MyReactComponent using ReactDOM.render: due this, I suppose MyReactComponent is the first component in your tree. If that is the case, when you use useContext inside it, it cannot find any MyStore context.
So, probably, you just need to wrap your MyReactComponent with a context provider.
export class MyStore { ... }
export const MyStoreContext = createContext(new MyStore());
---
ReactDOM.render(
<MyStoreContext.Provider>
<MyReactComponent {...props />
</MyStoreContext.Provider>
, document.querySelector("#id"));
And then, inside MyReactComponent, you can use const store = useContext(MyStoreContext);.
I have a component that i'm loading via react-loadable. The component that is being loading has some logic in componentWillReceiveProps for detecting if it needs to get some more data, etc.
When loaded via react loadable, it calls render 1 time, and componentWillReceiveProps is never called.
import React from 'react'
import Loadable from 'react-loadable'
import Loading from 'components/Loading'
const LoadableThing = Loadable({
loader: () => import('components/Thing'),
loading: Loading,
render(loaded, props) {
let Component = loaded.default;
return <Component {...props}/>
}
});
export default LoadableThing
And this component is included in another component that's making some initial data calls and sending the results to the Thing
any thoughts? It's calling return <Component again, but that seems like it's creating a new component in that case.