How to display data from global state in React? - reactjs

Hello fellow programmers,
I need the data from the global state displayed on a page. To specify: the user has to see the data he entered in a form and make sure it is correct. Main goal is getting it on the page first.
What is global state? It is where the data from input fields is collected and is able to be edited. Here is an example how I get the data:
const [enteredFirstName, setEnteredFirstName] = useState('');
In the form it looks like this:
<Card>
<div className="formControl">
<label htmlFor="first_name">Voornaam</label>
<input
type="text"
id="first_name"
value={enteredFirstName}
onChange={event => {
setEnteredFirstName(event.target.value)
}}
/>
</div>
</Card>
Card makes sure that the form data will be collected.
const Card = props => {
return <div className="card">{props.children}</div>
};
Now I need to display the data. I assume that I have to get the props of the children and 'fetch' the data that way? I have tried tutorials but I can't find anything related to my issue.
This picture illustrates how it is supposed to look:

If you'd like to share data between multiple components without having to pass them as props down through all of your components, you can use Context. That will let you write and read from the context in any components that are wrapped within the context provider.

I've used some of your code and created a sandbox to hopefully replicate the functionality you require.
Please check and let me know if this helps: https://codesandbox.io/s/wizardly-visvesvaraya-025cf?file=/src/Form.js
EDIT: To answer your question, you can use the original state and pass it down to another component that only renders based on a condition you've set. - In my example, I am passing the state down to the UserData component which will only render when the data has been submitted.

Related

How do I show a loading state while React components are being mapped from a large array of data?

I understand how to set a loading state while data is fetching from my API, but how do I set a loading state when the data is already retrieved but is being mapped into components?
I have a component that waits to be rendered while the data is being retrieved like so:
const [retrieving, setRetrieving] = useState(false)
useEffect(async () => {
setRetrieving(true)
// make an API request and set data
setRetrieving(false)
}
}, [pageId])
return (
{retrieving ? (
<LoadingSpinner />
) : (
<MyComponent data={data} />
)}
)
Inside of that component, I am mapping that data to output some child components for example:
{data.map((item) => (
<ChildComponent key={item.id} data={item} />
))}
When that data changes for the same component, there's a split second where the previous data shows in my component before the current data is rendered. I want to polish it a bit so I show a loading spinner while the appropriate data is being mapped. Is there any way to do that?
UPDATE: So I figured out my issue if anyone finds this through google. I was using the same 'retrieving' state for two different API calls. The initial API call was setting the retrieving state to false before the second API call was finished, hence displaying my component before the state was retrieved. My code example was too sparse to show that unfortunately. I'll try posting more code in future questions.
Using .map shouldn't take long at all.
I think the issue sounds more from your useEffect. Maybe move the setRetrieving(true) line to where ever the trigger for changing pageId is.
Could you possibly post some more code (maybe upload it to codepen) so we could have a loot at it more?
You could also have a look at using something like React-Query as that has alot of what you are asking for pre built.
https://react-query.tanstack.com/

How to obtain a value from a file in another file thanks to the store

I have recently started a project in a team of three people. We've been learning some React for that, and when I explained to a friend what I was trying to do, he advised me to try it with Redux, but I'm not quite sure how I'm supposed to proceed.
My goal is to generate a code in an Arrival.js page, depending on a form that the customer filled, based on his first name and the date. I have the right function to generate that code. Now when the customer submits the form, a pop-up shows up, telling him "here's your code: CODE1245" for example. The thing is that this pop-up is a component located in another file named PopUpArrival.js and I can't manage to transfer the code generated in Arrival.js with the form's information.
So I tried to set up a store with reducers and actions, but I can't manage to find any actions that would fit my goals. Am I overthinking it by trying to use Redux? Or is there an easy way to do so? It's been three days and I'm quite lost and demotivated to be honest. Thanks if anyone took the time to read me and I'd be even more grateful if anyone shows up with a solution
If your components have a
parent-child relationship, then it would be easy to send the code as a prop to the child.
Sibling relationship, then What is the most simplest method of updating component's state from another component? Lets say components are siblings?
Not related at all, there are a lot of ways like cookies, local storage, context, redux, etc.
I guess using redux only for this purpose might be overkill. You can look at contexts in that case.
I think Redux maybe an overkill here. You can get this done without redux from how it looks. If you can consider the following flow.
Your Arrival.js will maintain state for the first name and the date. Your PopUpArrival.js should be a component in itself, which takes whatever text you want to show in popup as a prop. Based on when you want to trigger the popup logic, you should display the PopUpArrival component. I have tried to roughly write some code below which does the same.
const PopUpArrival = (props) => {
const { textToShow } = props;
return(
<div>{textToShow}</div>;
);
}
const Arrival = () => {
// maintains state for both name and date
const [showPopup, setPopupDisplay] = useState(false);
const togglePopup = () => {
setPopupDisplay((currentDisplay) => !currentDisplay);
}
const getTextToShow = () => {
return `${name}-{date}`; // whatever logic you have
}
return(
<>
<button onClick={togglePopup}>
Submit
</button>
{
showPopup && <PopUpArrival textToShow={getTextToShow()}/>
}
</>
)
}

I am trying to understand why componentDidUpdate is not firing for specific component

I am having some issues with a particular component not properly updating. This component is effectively modeled after each of the other components, the only difference that I can determine is that it receives props that are array elements; although I have switched the variable being passed so that it renders store elements that are working elsewhere, though I am still getting the same update issue.
The weird thing about this is that the component update does fire, but only when one of the other elements that is properly updating is triggered, so it logs the console object on this instance for two different checks within the componentDidUpdate function.
The overall design is a basic React/Redux app, with a component that is designed to hold/render the audio events. I have a MainLayout component that renders the AudioEngine component, followed by multiple "Panel" components that are only specified for the UI. It is this component that is passed the redux store. It appears that the redusx store is handling state properly, and is passing the data back as expected; however, it is only this element of the UI that is failing to properly trigger an update.
Within the AudioEngine component:
if(this.props.lfoRate != prevProps.lfoRate){
console.log(this.state.lfoRate)
this.setState({
lfoRate: this.props.lfoRate
}, () => {
this.lfo['osc'].frequency.value = this.state.lfoRate
});
}
Here is the return from the MainLayout component, which receives the stor/props (sorry this is still a bit of a work in progress):
return(
<div >
<Header />
<div style={mainLayoutStyle} className={"main-layout"}>
{
this.props.keyOn ? (<AudioEngine lfoRate={this.props.LFObj[2]} gain={this.props.masterGain} freq={this.props.masterFreq} oscArray={this.props.oscArray}
lfoType={this.props.LFObj[1]} lfoFreq={this.props.LFObj[3]} count={count}/>) : (count % 2 == 0 ? (<AudioEngine count={0} gain={0} freq={this.props.masterFreq} oscArray={this.props.oscArray}
lfoType={this.props.LFObj[1]} lfoRate={this.props.LFObj[2]} lfoFreq={this.props.LFObj[3]}/>) : (''))
}
<MainPanel keyToggle={this.props.keyToggle} changeMasterGain={this.props.changeMasterGain}
masterGain={this.props.masterGain} keyOn={this.props.keyOn} baseFrequency={this.props.masterFreq}
changeBaseFrequency={this.props.changeBaseFrequency} />
<div style={{display: 'flex', flexFlow:'column'}} >
<Oscillator addOsc={this.props.addOsc} subOsc={this.props.subOsc} oscArray={this.props.oscArray} />
<LfoPanel lfoRate={this.props.LFObj[2]} lfoFreq={this.props.LFObj[3]} onChange={this.props.changeLFO}
lfoType={this.props.LFObj[1]}/>
</div>
</div>
</div>
)
The LfoPanel component is designed much of the same way as the others...
Any pointers would be quite helpful, perhaps it is passing array elements as properties? If that is the case, that seems like a strange gotcha. Thank-you in advance...
Ok, so after some further research, I realized that it was in fact a mutability issue from Redux. Even though it was technically updating the state, it was not properly immutable. I ended up using the primary solution from this question.
Thanks to those who looked / took time to respond. Hopefully this reference will save another React-Redux a headache later on :)

React dynamically rendered component not updating

I'm trying to render a list of components using map function in render. When I change state, render function is called as expected but my component is not updated.
I've made a sample codesandbox here
https://codesandbox.io/s/nk24mr55om
What am I doing wrong?
I've added some console logs and it look like secret content should be displayed but it is not
Once your item is pushed into the items array, it will not be updated, ever. A solution to this would be to convert the items you push into arrow functions that will get a show parameter :
items.push(show =>
<div>
{show && <div>I'm secret</div>}
My content
<br />
<input
type="button"
onClick={showSecret}
value="Show secret content"
/>
</div>
);
And then call it in the mapping of your render :
return <div key={index}>{item(show)}</div>;
However, with this solution, clicking on one button will cause every item to show their secret element, if this isn't the behavior you expect and want every item to act on its own, I suggest creating a hook for each item. And ahev them store their own show variable in their state.
I have no experience yet with react hooks, but i tried to understand whats going on.
The variable items you refer to is neither a prop nor in the state of your component, i would make the component stateful and initialize items in the state.
Maybe there is a better way with react hooks that someone else can give

Best practice for conditional rendering of children elements in ReactJs with Redux connect?

The situation I have is a login screen that displays one of 3 blocks of code, depending on the store state of the app. Eg... Below would be the resulting render if the second display option was selected.
<LoginFormPage>
<DisplayOption2 />
</LoginFormPage>
There are specific calls and logic for each display option distinct enough to warrant their own containers. My file structure is:
/components
/displayOpt1.jsx
/displayOpt2.jsx
/displayOpt3.jsx
/loginFormPage.jsx
/containers
/displayOpt1.js
/displayOpt2.js
/displayOpt3.js
/loginFormPage.js
I need a way to render the correct option without embedding too much logic into the parent container; since it really doesn't need to know anything about any of the login mechanisms. I can think of a few ways to do it.
All logic in loginFormPage.js with a connect direct to the loginFormPage.jsx. Then conditional parameters in the loginFormPage.jsx that makes calls to the components directly; removing the other containers.
Create a React.Component in the loginFormPage.js to do the conditional rendering calls to the other containers; this would call all the .jsx files from the container component. loginFormPage.jsx would then render the selected child with {props.children}.
Same as 2. but do the conditional rendering call in the mergeProps parameter passed to connect in loginFormPage.js; rather than creating a jsx component in the container js code.
Some standard practice that I don't know of?
Right now I'm leaning towards option 3, but I can't find any evidence with my Google searches of this being a recommended practice. All thoughts are welcome. Thanks.
Some code to maybe make it easier:
loginFormPage.jsx
<div>
<div onClick={props.someActionHeader}>
<h1>Login Form</h1>
</div>
<div className="formarea">
// render the selected option here based on props.renderOptionChoice
// this will be one of displayOpt1, displayOpt2, displayOpt3
</div>
<div className="otherstuff">...</div>
</div>
displayOpt1.jsx - Opt2.jsx and Opt3.jsx code is a variation of something like this
<div onClick={props.someAction1}>
stuff...
</div>
loginFormPage.js
import LoginFormPage from '../components/loginFormPage'
const mapStateToProps = (state, ownProps) => {
return {
renderOptionChoice: state.login.selectedLoginType,
}
}
const mapDispatchToProps = ...
export default connect(mapStateToProps, mapDispatchToProps)(LoginFormPage)
I can answer with what I've found to be the best practice. It's worth reading the 3 posts in my comment to the question.
The Container level should contain the What is being displayed. In terms of a Login screen with several different options, then all the What's should be presented in one file. Following this style makes it clear exactly What is being displayed on the particular screen / component simply by looking at a single file.
So at the top level, the render will look like:
render() {
return (
<LoginPage>
{this.state.step === STEPS.Step1 && <LoginStep1 />}
{this.state.step === STEPS.Step2 && <LoginStep2 />}
{this.state.step === STEPS.Step3 && <LoginStep3 />}
</LoginPage>
)
}
Here LoginStep1/2/3 can be contained components with their own connection to the Redux state, or it can be managed at the LoginPage level if the steps code is very simple or strongly related.

Resources