How can I extract the useState from the file. It is necessary to export exactly sliderCount for further work. Thanks in advance.
There are 2 files. The first file uses the useState function and changes the state when the button is clicked. In the second file, I want to get the changed state of useState from the first file and continue to work with it.
Make conditions, etc., for example:
if(sliderCount == 1){
console.log('Number 1')
}
if(sliderCount == 2){
console.log('Number 2')
}
First file:
import React, {useState} from "react";
function ContainerAtwSwap() {
const [sliderCount, setSliderCount] = useState(0)
return (
<div className="container_button__swap-main">
<div className="dropdown">
<div className="dropdown-content">
<button className="button__swap-button" onClick={() => setSliderCount(1)}>№1</button>
<button className="button__swap-button" onClick={() => setSliderCount(2)}> №2</button>
<button className="button__swap-button" onClick={() => setSliderCount(3)}>№3</button>
</div>
</div>
</div>
)
}
export default ContainerAtwSwap
Second file:
import React from 'react';
function WorkingEnvironment() {
..here I wanted to make conditions, etc.
return (
<div className='boxControl scroll' id='boxSliderOne'>
<div className='container-slider'>
{}
</div>
</div>
);
}
export default WorkingEnvironment;
That is what the Context API is for: https://reactjs.org/docs/context.html
Of course you could also use Redux, or transfer data from child to parent and to another child, but the Context API solves this in a much easier way and it is built in without any extra dependency.
One way is to have a parent (of both components) relay the change to the other. Component A will send a changed event to the parent (via a component property event). Then the parent will simply send that changed value to Component B (via a component property).
Grouping your components in one parent component and lifting the state up to their parent is the only way you can share their state.
Otherwise you have to implement a redux store or anything like that.
I link you the React doc's below
https://reactjs.org/docs/lifting-state-up.html
Related
I know that you can do navigation.navigate("address", {/* params go here */ to send parameters over to another screen. But then you have to navigate there. Is there a way of sending params over without navigating?
I have a application with multiple screens. And I want to update a useState from another component by updating its params so that a button appears. But I dont want to navigate there, I just want to update it so when the user does go there the button will be there.
Like this:
const currentComponent = (navigation) {
return (
<Button onPress={navigation.updateParams("otherComponent", {shouldShowValue: true})} />
)
}
const otherComponent = (route, navigation) {
const {shouldShowValue} = route.params
const [shouldShow, setShouldShow] = useState(shouldShowValue);
return (
{shouldShow ? <Button> Yayy this button appears now <Button /> : null}
)
}
}
'''
this is just pseudo code and not at all
like the code I have written,
but its just meant as an example to get a
understanding of what I mean.
(updateParams) isnt a function that exists,
but I want something similiar like it.
Is there a way of updating the params in a
component from another component without having
to navigate there? Like with
navigate.navigate("address" {params go here})
but without the navigation part?
You can consider using useContext() hook to execute your functionality.
Using navigation library to pass param without navigating to that page is somehow misusing the navigation function.
With useContext, you can share the state(s) among components. If you want to change the value upon clicking action, you can also pass the useState hook into useContext. Alternatively, you can consider to use redux library to share state.
import { useState, createContext, useContext } from 'react';
const shareContext = createContext(null);
export default function demoUseContext() {
const [isClicked, setClicked] = useState(false);
return (
<shareContext.Provider value={{isClicked, setClicked}}>
<ComponentA />
<ComponentB />
</shareContext.Provider>
)
}
function ComponentA() {
const sharedParam = useContext(shareContext);
return (
<button onClick={() => sharedParam.setClicked(!sharedParam.isClicked)}>
click to change value
</button>
);
}
function ComponentB() {
const sharedParam = useContext(shareContext);
return (
sharedParam.isClicked && <div>it is clicked</div>
)
}
As the example above, the code pass the useState hook from parent component into context, where A is consuming the useState from context to setup isClicked via setClicked, B is consuming the value isClicked from context.
You can also manage to setup context with value not only in a hook, but a param / object / function as a callback.
For more details, please refer to https://reactjs.org/docs/hooks-reference.html#usecontext
There're multiple hooks including useContext fyi
Passing parameters to routes
There are two pieces to this:
Pass params to a route by putting them in an object as a second parameter to the navigation.navigate function: navigation.navigate('RouteName', { /* params go here */ })
Read the params in your screen component: route.params.
We recommend that the params you pass are JSON-serializable. That way, you'll be able to use state persistence and your screen components will have the right contract for implementing deep linking.
I'm working on the freeCodeCamp drum machine app. In my app with function arrow components, I set state of display with the useState hook in the parent component and pass it as a prop to the child component. In the parent component, I try to render the display state in a div. However, when the method is triggered (on click of the "drum pad" div), the app crashes. In the console I get an error that says "Uncaught Invariant Violation: Objects are not valid as a React child (found: object with keys {display}). If you meant to render a collection of children, use an array instead."
I've been following along a YouTube tutorial for this project but using arrow function components and Hooks instead of regular classes as used in the tutorial--in the tutorial (around 1:55 of this video) the person successfully does what I'm trying to do, so I think the issue is something to do with using Hooks or arrow function components.
// APP COMPONENT (PARENT)
const sounds = [
{ id: 'snare', letter: 'Q', src: 'https://www.myinstants.com/media/sounds/snare.mp3' },
// etc.
];
const App = () => {
const [display, setDisplay] = useState(''); // <----
const handleDisplay = display => { // <----
setDisplay({ display });
}
return (
<div className="App">
<div className="drum-machine">
<div className="display">
<p>{display}</p> // <---- Related to error in console
</div>
<div className="drum-pads">
{sounds.map(sound => (
<DrumPad
id={sound.id}
letter={sound.letter}
src={sound.src}
handleDisplay={handleDisplay} // <----
/>
))}
</div>
</div>
</div>
);
}
// DRUMPAD COMPONENT (CHILD)
const DrumPad = ({ id, letter, src, handleDisplay }) => {
let audio = React.createRef();
const handleClick = () => {
audio.current.play();
audio.current.currentTime = 0;
handleDisplay(id); // <----
}
return (
<div
className="drum-pad"
id={id}
onClick={handleClick}
>
<p className="letter">{letter}</p>
<audio
ref={audio}
id={letter}
src={src}
>
</audio>
</div>
);
}
You're setting the state as an object instead of a string. Remove the curly brackets around it.
const handleDisplay = display => {
setDisplay(display);
}
This was already answered, but since you are following a tutorial, I am assuming you are learning React and wanted to point a couple of things to help you :)
The incorrect use of state was pointed out, but just for clarification (and the reason I think you were using an object): in the "old" way, with Class components, the state used to be an object, and you needed to update it like an object. This example here shows that. With Hooks, you don't need to set the whole State object, only that specific state property. More info here.
Another point is, in your CodePen example at least, you were missing the import for useState. You either need to import it like this import { useState } from React or use it like this React.useState, since this is a separate module, not imported by default when you import React.
The last point is, when creating components using a loop (like your <DrumPad> with the map) you need to provide a "key" attribute. that will help React keep track of things that needs to be updated or rerendered.
O updated your code with those changes in this link, if you wanna see it working:
https://codesandbox.io/s/reverent-browser-zkum2
Good luck and hope you are enjoying React Hooks :)
I wonder if it is fine to predefine some JSX and use it multiple times in different components.
const saveButton =
<div class="u-mth u-textRight">
<Button variant="flatBlue">Save</Button>
</div>;
const test = <div>{saveButton}</div>;
Is there any downside compared to a normal functional react component?
export const SaveButton = () => (
<div class="u-mth u-textRight">
<Button variant="flatBlue">Save</Button>
</div>
);
const test = <div> <SaveButton /> </div>
And what about this one instead of functional with react props:
const saveButton = (text: string) => (
<div class="u-mth u-textRight">
<Button variant="flatBlue">{text}</Button>
</div>
);
const test = <div> {saveButton(text)} </div>;
First one is simply just jsx, it's not a component.
Second one is a stateless component, which is fine as well but you have not used any props.
Third one is also just a function not a component as you have not used props. What I would do is as #estus recommended in answer.
But please also view this link which says they way you have approached is actually faster.
React component (snippet 2) will appear as in React devtools as <SaveButton>...</SaveButton>, while other options won't.
React component (snippet 2) is the way it's usually done. If a component needs to expose dynamic behaviour, parameters should be passed as props:
const SaveButton = ({ text }) => (
<div class="u-mth u-textRight">
<Button variant="flatBlue">{text}</Button>
</div>
);
and
<SaveButton text={text} />
Helper function (snippet 3) is the way how the performance of React component can be improved, by calling it directly. It can be considered preliminary optimization, unless proven otherwise.
As long as element hierarchy doesn't expose dynamic behaviour, the definition of React elements as a variable (snippet 1) has no downside under normal circumstances. If there's a possibility that dynamic behaviour can be necessary in future (custom or localized text), it will require refactoring.
It is just declaring variables. Nothing else. In this case, using ES6 and JSX.
It is the same thing as 1. just as function. This function returns what you declared under 1. Using ES6. No downsides.
The same as 2. with arguments object, actually passing parameter to function using ES6 and Type Script.
function saveButton(props) {
return <div class="u-mth u-textRight">
<Button variant="flatBlue">{props.text}</Button>
</div>;
}
const element = <saveButton text="Save" />;
ReactDOM.render(
element,
document.getElementById('root')
);
This is the way using props and pure function.
I'm trying to build an application to help me learn react. It's a simple app that takes users input location, gets the coordinates from googles geolocation api and then gets the weather conditions for that location with dark skys api.
I originally had all my application logic in one container which you can see here https://github.com/darragh3277/night-sky
I want to separate out my logic a bit more to as I felt my one container was doing too many things. I'm looking to structure my app as follows.
App.js - Holds state, locationChangeHandler function to pass down to LocationSearchContainer.
LocationSearchContainer - Geolocation API and calls LocationSearch to display search bar
WeatherContainer - WeatherAPI and calls Weather component to render the display.
I believe this gives me a better separation of concerns and makes my code a bit more readable.
Because of this structure I think I need a locationChangeHandler in my App.js that will be passed to my Dump LocationSearch component. This tightly couples my App.js to the search bar but as that's the core function of the app I don't believe it's a problem.
What I'm having trouble with is how to pass my handler from App.js -> LocationSearchContainer -> LocationSearch. Here is my poor attempt so far:
In App.js I have
handleLocationChange = e => {
e.preventDefault();
console.log('hello');
//Calls getLocation in LocationSearchContainer and updates state
}
render(){
return (
<LocationSearchContainer onLocationChange={this.handleLocationChange} />
)
}
In LocationSearchContainer I have the following:
import React from 'react';
import LocationSearch from '../components/LocationSearch';
class LocationSearchContainer extends React.Component{
getLocation = (address) => {
//DO STUFF
}
render(){
return (
<LocationSearch onLocationChange={this.props.handleLocationChange} />
)
}
}
export default LocationSearchContainer;
And finally LocationSearch:
import React from 'react';
const LocationSearch = (
<form onSubmit={props.onLocationChange}>
<div className="input-group">
<input type="text" name="location" className="form-control" placeholder="Search location..." />
<button className="btn btn-primary">Go!</button>
</div>
</form>
)
export default LocationSearch;
How can I pass this handler down correctly?
Once I have the above working I'll also need to call the getLocation in my SearchLocationContainer from App.js but I'm not sure how to do that either?
EDIT
I've figure out part one of my problem. I was calling the function by name rather than the prop name I was passing. So in the render() function of my LocationSearchContainer I should have had
return (
<LocationSearch onLocationChange={this.props.handleLocationChange} />
)
rather than my original.
That still leaves me with the problem of calling my LocationSearchContainer's getCoordinates function from my App.js file. Anyone able to help me with that?
You are passing your handler like that:
<LocationSearchContainer onLocationChange={this.handleLocationChange} />
So, in LocationSearchContainer component, your handler function's name is onLocationChange, within props it is this.props.onLocationChange.
So, you need to pass this function to your LocationSearch component like that:
<LocationSearch onLocationChange={this.props.onLocationChange} />
Lastly, you need to use it in LocationSearch as props.onLocationChange
For your second question, you shouldn't try to invoke a child component's method from the parent. Change your logic. Either keep this function in the parent, then pass it again as a prop to your child component or move the logic to your child component.
I have this:
const ProjectsSummaryLayout = ({projects}) => {
return (
<div className="projects-summary col-md-10">
<h3>Projects</h3>
<ul>
{ projects.map(p => <li key={p.id}>{p.contract.client}</li>) }
</ul>
</div>
)
}
const ProjectsSummary = connect(
state => ({projects: state.projects})
)(ProjectsSummaryLayout)
and I get:
Warning: Stateless function components cannot be given refs (See ref
"wrappedInstance" in ProjectsSummaryLayout created by
Connect(ProjectsSummaryLayout)). Attempts to access this ref will
fail.
What is it trying to tell me? Am I actually doing something wrong?
I see discussion about this here but unfortunately I simply don't understand the conclusion.
In React, refs may not be attached to a stateless component.
React Redux 3 attaches a ref to the component you give it regardless of whether or not it's stateless. The warning you see comes from React because internally, React Redux 3 attaches a ref to the stateless component you supplied (ProjectsSummaryLayout).
You're not doing anything wrong and according to this GitHub comment, you can safely ignore the warning.
In React Redux 4, no ref is attached to the wrapped component by default, which means if you upgrade to React Redux 4, the warning should go away.
React has 2 commonly used component styles.
Functional Component
Class Component
So, When I was making use of Functional one then I was encountering this error.
Code snippet corresponding to Functional Component
But as soon as I changed it to Class Component then it worked.
Code snippet corresponding to Class Component.
Try changing Functional Component to Class Component.
I hope it will resolve your problem.