NextJS: data fetching in child component and pass to parent component - reactjs

I am new to Next.js and trying to make an e-commerce project. I am stuck on if a child component Sort Component has a post request to the server to filter the data and pass it back to the Products component as product props.
The folder structure is like this:
<>
<Sort />
<Products products={products} />
</>
Inside the Sort component, I will send the filter parameters back to the server. So the method I am thinking of is using Redux, but can I use the useSWR hook? As the action is taken at Sort component, seems useSWR hook need to have the action and the data returned together in the same component, is that correct?

Your code is looks like that:
<>
<Sort />
<Products products={products} />
</>
In this case you have to create a shared state in the container of that two, like this:
1, You can use a simple shared state, like:
function ContainerOfTwo(props) {
const [sharedState, setSharedState] = React.useState({});
return (
<>
<Sort setSharedState={setSharedState} sharedState={sharedState} />
<Products products={products} setSharedState={setSharedState} sharedState={sharedState} />
</>
)
}
2, Use the native React contextAPI maybe with useReducer. (This is a smaller and more specific state management. Small resource)
3, Use Redux. (For larger, and more robostus state handler)
Summary: I would go with shared state for the first, if thats not enought with your requirements, go with the contextAPI or with redux depending on your needs.
If you doing good, should not be a large issue to hold the state to contextAPI/redux.

The simplest solution, although perhaps not the best in the long term depending upon how complex the interactions between these child components can get, is managing the state and passing state and hooks to set the state to these children.
function ParentComponent(props) {
const initialState = {};
const [ sortedData, setSortedData ] = React.useState(initialState);
return(
<>
<Sort setSortedData={setSortedData} />
<Products sortedData={sortedData} />
</>
)
}
Note: Since the Products component is dependent upon the sortedData to be updated you may want to set conditions on its render as you await the async fetch in Sort.
Again, if there will be any degree of complexity beyond this then you may want to use Redux or React's ContextAPI to manage the state. For example, if sortedData is used in any child components of Sort or Products then you'd want to manage using Redux or ContextAPI so you're not passing it along child to child.
You can read more about the useContext hook here: useContext

You can use callback method from parent to child and setting the state value in the parent and passing this value to other child components.
class Parent extends Component {
constructor(props) {
super(props);
this.state = {
products: []
};
}
callBackMethod = (products) => {
this.setState({products})
}
render() {
const { products } = this.state;
return (
<>
<Sort callBackMethod={this.callBackMethod}/>
<Products products={products} />
</>
);
}
}
export default Parent;

Related

Is it possible to pass data to components without a parent?

I understand that the normal way is to pass props through a parent, but I want to know how else I can pass props to a component.
let C1 = createReactClass({
...
render: function() {
console.log('render C1');
return (
<div>
<button onClick={this.cambiaAAzul}>Azul</button>
<button onClick={this.cambiaAVerde}>Verde</button>
<button onClick={this.cambiaARojo}>Rojo</button>
<p>Estado C2 <strong style={ {color: this.state.color} }>{this.state.color}</strong></p>
<C2 color={this.state.color}/> // It is common
</div>
);
}
});
Typically, to solve the props-drilling problem, which is what seems to be the issue you are trying to solve, the useContext hook should help.
So set up a context,
const C1ContextProvider = ({children}) => {
//...
// the Provider gives access to the context to its children
return (
< C1Context.Provider value={someValue}>
{children}
</C1Context.Provider >
);
}
... and then in your component where you need someValue, you can just do this:
import React, { useContext } from "react";
import { C1Context } from "../C1Context";
//...
const values = useContext(AirDCPPSocketContext);
cons foo = values.someValue; // <-- someValue obtained from the context
//..
I don't know how it is possible to not have parents but you can pass informations by local storage and context hooks.
Props are by definition arguments passed into a React component. Since React components are instantiated in the context of their parent, I'm not sure if it would be possible to pass props in any other way.
There are many other ways to get data in React though. You could query data from an API or other source, or you could pull from a state manager (such as redux). It just depends on what you are trying to accomplish.
Props are simply things passed into a component when it's called.
For instance:
C1.js
function C1((prop1, prop2) {
<h1>{prop1} {prop2}</h1>
})
App.js
<C1 prop1="Hello" prop2="World" />
<C1 prop1="React's" prop2="Great" />
By referencing the C1 component in App.js, you can call it with different props to produce different results.
Now I'm not too familiar with the createReactClass and render: you're using, as this is a style of React I've never learned. However, I'd guess that props provide the same function.
Your question asks about props without a parent. Well. Props without a parent wouldn't be props, they'd just be normal JS data types inside your file.
Hope this helps :)
The component's local state only can drill into child components. for passing props without using React component's local state. you have to use state management libraries like Context API or Redux
These libraries are created to make you able to pass props into nonrelated or sibling components
Example with redux:
Here I Assume that you set up redux in your project. imagine you have two components that you want to pass props without parent-child relation.
const changeMyWeightAction = (weight) => {
return {
type: 'CHANGE_MY_WEIGHT',
payload: weight
}
}
const JenniferFunctionComponent = () => {
const dispatch = useDispatch()
return (
<div>
<span>hello I'm Jennifer and I can decide my weight</span>
<input onChange={e => dispatch(changeMyWeightAction(e.target.value)})/>
</div>
)
}
const WeightFunctionComponent = () => {
const weight = useSelector(state => state.Jenny.weight)
return (
<span>Jenny's weight is {weight}</span>
)
}

Composition In React with params

I am trying to create an architecture that in some way imitates the slots from VUE.
The idea is for the parent component to be able to inject some props into the component and the child can inject the rest of the props.
This is how I tried to approach this problem, unfortunately this approach will not work because the compontent will be "monut" every time the parent re-render takes place.
Filters = (prams) => {
useEffect(()=>{ //RENDER ALL THE TIME },[])
...
}
ParentComponent = () => <ChildComponent Filters={(props) => <Filters propA={"A"} />}
ChildComponent = (props) => {
const Filters = props.Filters;
render(<Filters probB="B" />)
}
I know, I can use useCallback for ((props) => <Filters propA={"A"} />), but only it will help only if what I want to pass to "propA" is steady.
I want to "manage" <Filters /> component in parent, so that the child does not have to handle Filters logic (props).
React gives you proper API to do most things. Using it forces you into certain paradigms that are proven to work well.
You should probably have a look at the Context and Memo APIs from React.
Or if you have to select and update state from multiple components, you might wanna have a look at libraries that provide global state, like Redux and Recoil.
Context example
// The shape
interface ContextProps {
myProp: string
}
// The context
export const MyContext = React.createContext<Partial<ContextProps>>({
myProp: 'nothing'
});
// The provider
<MyContext.Provider value={{ myProp: 'override' }}>
{children}
</MyContext.Provider>
// Consumer
const { myProp } = useContext(MyContext)
In some case you can also use useMemo or React.memo and use your own custom compare function if needed to prevent re-renders in very specific situations.

FragmentContainer vs just another React component as a wrapper?

I am writing code to plug in an existing React component into another component.
The way it's been originally done in code is using a fragmentContainer.
I understand a fragmentContainer is a Higher Order Component that acts as a wrapper, and returns another React component.
However, I am trying to understand whether I really need to use a fragmentContainer to plug in my existing component, or I can create another wrapper component instead.
Is there a sure way of telling where a fragmentContainer should be used vs React Component within a React Component?
I have looked at the official docs(https://relay.dev/docs/en/fragment-container), and other resources, but it seems like either way can be used?
Are there special cases where fragment containers should be used?
You use a fragmentContainer to ensure what data you need in a component.
For exemple:
parent.js
const ParentComponent = ({list}) => (
<QueryRenderer
query={graphql`
query List {
id
...childComponent_item
}
`}
render={
list.map(item => (
<ChildComponent item={item} key={item.id} />
))
}
/>
);
export default ParentComponent;
// Here, in the parent component
// I need the id of each item of the list but I don't need the others values.
childComponent.js
const ChildComponent = item => (
<>
<div>{item.name}</div>
<div>{item.avatar}</div>
<div>{item.othervalue}</div>
</>
)
const ChildComponentWithFragment = createFragmdentContainer(
ChildComponent,
{
list: graphql`
fragment childComponent_item on ItemType {
name
avatar
othervalue
}
`
};
export default ChildComponentWithFragment;
// Here in the child component
// I need the others data of the Item object so i have to get these values
// in my fragment

Can you pass down state to child components with React Hooks?

I'm trying to re-write some of my code in React Hooks, and I was wondering, when I pass down searchData in this example... Will the now have access to searchData and setSearchData? I'm confused about how passing around state in React Hooks works.
import React, { useState, useEffect } from "react";
import SearchBarContainer from "../SearchBar/SearchBarContainer";
import PostContainer from "./PostContainer";
function PostPage(props) {
const [searchData, setSearchData] = useState([...props.data]);
const [addLike, setAddLike] = useState([]);
useEffect(() => {
setAddLike({ addLike: Array(props.data.length).fill(false) });
});
return (
<div>
<SearchBarContainer data={props.data} searchData={searchData} />
<div css={parentPostContainer}>
{searchData.map((dataOnMap, index) => {
return (
<PostContainer
data={dataOnMap}
addLike={addLike[index]}
searchData={searchData}
/>
);
})}
</div>
</div>
);
}
export default PostPage;
Yes, as far as passing down props are concerned there is no difference in usage with React Hooks. In the snippet you've provided just pass setSearchData as a prop to PostContainer.
<PostContainer
data={dataOnMap}
addLike={addLike[index]}
searchData={searchData}
setSearchData={setSearchData}
/>
Yes Absolutely you can. In fact React docs talk about "Lifting state up" so to speak.
If there is shared state between components and you need to lift it up to their nearest ancestor.
The general concept is props are passed down and state is passed up.
However, this can get messy. If you are working on a larger project, I would recommend using Redux.
You can pass the state as props, but if you want child components to alter state, then you can pass the setter from the useState directly to child components.
Here is the same example:
<PostContainer
data={dataOnMap}
addLike={addLike[index]}
searchData={searchData}
setSearchData={setSearchData}
setAddLike={setAddLike}
/>
Or another solution
const LikeManager = {
addLike: setAddLike,
data: {
//some data
}
}
<PostContainer
data={dataOnMap}
likeManager: {LikeManager}
/>
I know this is not part of the question, but I would recommend using scalar values for useState wherever possible

How do I pass a class's state as props in another class?

I want to create a React App that fetches data based on filters given by the user. I have two classes, Filters and News. In Filters, I want to set sourceName and countryCode as state; then fetch based on these parameters in News. How do I pass the state values as props in News?
The best way is to pass the state from the parent of both elements.
import React, { Component } from "react";
export default class Parent extends Component {
constructor() {
super();
this.state = {
sourceName: null,
contryCode: null
}
}
render() {
return (
<div>
<Filters {...this.state} />
<News {...this.state} />
</div>
)
}
}
You should always keep state in an element higher up in the render chain then all the children that need it. Doing this allows you to trickle down the state to all children that need it. Then only time state should be maintained within a component is if that component is the only component that needs it.
you can simple pass the state down as props in the child.
like <News filter={this.state.filer} />.

Resources